type-inference #39
1
Makefile
@@ -108,6 +108,7 @@ SEX_TEST_PROGRAMS = c99 \
|
|||||||
inference \
|
inference \
|
||||||
lambdas \
|
lambdas \
|
||||||
lists \
|
lists \
|
||||||
|
operators \
|
||||||
serialize \
|
serialize \
|
||||||
type-shapes \
|
type-shapes \
|
||||||
unicode \
|
unicode \
|
||||||
|
|||||||
57
semen.scm
@@ -274,12 +274,15 @@
|
|||||||
|
|
|||||||
;;; (fn sum ((a int) (b int)) int ...) -> (fn ((int) (int)) int).
|
;;; (fn sum ((a int) (b int)) int ...) -> (fn ((int) (int)) int).
|
||||||
;;; Anything that is not a plain (name type) -- a variadic tail -- goes
|
;;; Anything that is not a plain (name type) -- a variadic tail -- goes
|
||||||
;;; through untouched.
|
;;; through untouched.
|
||||||
(define (fn-type-of fn-form)
|
(define (arglist-types arglist)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
`(fn ,(map (lambda (param)
|
(map (lambda (param)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(if (and (pair? param) (= 2 (length param)) (named-arg? param))
|
(if (and (pair? param) (= 2 (length param)) (named-arg? param))
|
||||||
(list (second param))
|
(list (second param))
|
||||||
param))
|
param))
|
||||||
(sex-fn-arglist fn-form))
|
arglist))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(define (fn-type-of fn-form)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
`(fn ,(arglist-types (sex-fn-arglist fn-form))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
,(sex-fn-return-type fn-form)))
|
,(sex-fn-return-type fn-form)))
|
||||||
|
|
||||||
(define (aux-name! env make)
|
(define (aux-name! env make)
|
||||||
@@ -379,8 +382,24 @@
|
|||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(fourth form))))))))
|
(fourth form))))))))
|
||||||
|
|
||||||
((var)
|
((var)
|
||||||
;; the initializer is walked before the name it binds is in scope
|
;; the initializer is walked before the name it binds is in
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(let* ((walked (resolve-wildcard (walk-parts form env) env))
|
;; scope; the type is resolved rather than walked, a `fn' type's
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;; parameter list being indistinguishable from a call -- walking
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
alex-eg
commented
Re 347. The type gets what a Re 347. The type gets what a `fn` header gets -- macro expansion and closure resolution, no walk.
```
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) area) -> int (*fp)(int)
```
fe72a10.
|
|||||||
|
;; `(fn ((c int)) int)' with a closure named `c' in scope would
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;; rewrite the parameter as a call of it
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(let* ((prefix (if (>= (length form) 3)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(append (take form 2)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(list (resolve-closure-types
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(expand-type (third form) env))))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
form))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(walked (resolve-wildcard
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(copy-form-source!
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
form
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(append prefix
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(if (> (length form) 3)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(walk-body (drop form 3) env)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(list))))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
env))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(bound (if (>= (length walked) 4)
|
(bound (if (>= (length walked) 4)
|
||||||
(copy-form-source!
|
(copy-form-source!
|
||||||
walked
|
walked
|
||||||
@@ -408,12 +427,16 @@
|
|||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(else
|
(else
|
||||||
(let ((closure (receiver-closure-type (car form) env)))
|
(let ((closure (receiver-closure-type (car form) env)))
|
||||||
(if closure
|
(if closure
|
||||||
|
;; the receiver is walked first: a closure written where it
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;; is called registers its struct on the way, and the call
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;; helper's signature mentions that struct
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(let ((receiver (walk-statement (car form) env)))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(copy-form-source!
|
(copy-form-source!
|
||||||
|
alex-eg
commented
Re 348. A closure literal answers with its own type. The receiver is walked before the call helper is registered, so the struct is declared ahead of the signature naming it. Re 348. A closure literal answers with its own type. The receiver is walked before the call helper is registered, so the struct is declared ahead of the signature naming it.
```
((closure ((x int)) int () (return x)) 5) -> 5
```
fe72a10.
|
|||||||
form
|
form
|
||||||
`(,(register-closure-call! closure form)
|
`(,(register-closure-call! closure form)
|
||||||
,(walk-statement (car form) env)
|
,receiver
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
,@(map (lambda (argument) (walk-statement argument env))
|
,@(map (lambda (argument) (walk-statement argument env))
|
||||||
(cdr form))))
|
(cdr form)))))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(convert-arguments (walk-parts form env) env))))))))
|
(convert-arguments (walk-parts form env) env))))))))
|
||||||
|
|
||||||
;;; `(var n _ (strlen s))' becomes `(var n size-t (strlen s))'.
|
;;; `(var n _ (strlen s))' becomes `(var n size-t (strlen s))'.
|
||||||
@@ -507,6 +530,21 @@
|
|||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(else (pair (cdr params) (- remaining 1)
|
(else (pair (cdr params) (- remaining 1)
|
||||||
(cons (unwrap-type (car params)) acc))))))
|
(cons (unwrap-type (car params)) acc))))))
|
||||||
|
|
||||||
|
;;; A `fn' header has its macros expanded and its closure types
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;;; resolved without being walked; a `var' type is the same thing in the
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;;; same position, and gets the same two. A macro standing in for a type
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;;; may still ask `(type-of x)' while it does so.
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(define (expand-type type env)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(let ((expanded
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(parameterize ((current-type-of
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(lambda (queried)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(unresolve-closure-types
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(expression-type queried env)))))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(macro-expand (list type)))))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(if (and (pair? expanded) (null? (cdr expanded)))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
(car expanded)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
expanded)))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(define (walk-parts form env)
|
(define (walk-parts form env)
|
||||||
(copy-form-source! form (walk-body form env)))
|
(copy-form-source! form (walk-body form env)))
|
||||||
|
|
||||||
@@ -575,6 +613,11 @@
|
|||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
(cddr expr)))
|
(cddr expr)))
|
||||||
((cast) (and (= 3 (length expr)) (third expr)))
|
((cast) (and (= 3 (length expr)) (third expr)))
|
||||||
((sizeof) 'size-t)
|
((sizeof) 'size-t)
|
||||||
|
;; a closure literal is its own type: the first three elements
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;; already spell one, so calling one where it is written resolves
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
;; like calling one through a name
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
((closure) (and (closure-expression? expr)
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
|
`(closure ,(arglist-types (second expr)) ,(third expr))))
|
||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
;; `c-and' and `c-or' are the names from before `&&' and `||'
|
;; `c-and' and `c-or' are the names from before `&&' and `||'
|
||||||
((== != < > <= >= && |\|\|| ! c-and c-or) 'bool)
|
((== != < > <= >= && |\|\|| ! c-and c-or) 'bool)
|
||||||
((+ - / %) (arithmetic-type expr env))
|
((+ - / %) (arithmetic-type expr env))
|
||||||
|
|||||||
|
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pkulev
commented
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With `n` a `size-t` (an unparsed name, rank 1, same as `int`):
```c
int m1 = 1 + n;
size_t m2 = n + 1;
```
`cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`.
`size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
pkulev
commented
The forms that reach this walk are
The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`.
`(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
pkulev
commented
An array operand is returned as the array. emits An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it.
```sex
(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))
```
emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
pkulev
commented
A subscript types only when the base's surface form is already stops with A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so
```sex
(fn f ((p (* int))) int
(var e _ (¤ p 0))
(return e))
```
stops with `cannot infer the type of`. This is the other use named on `decay`.
pkulev
commented
`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
pkulev
commented
`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type.
```sex
(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))
```
`-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
pkulev
commented
The callee is typed before it is walked, so a closure literal has no type yet and falls through to
The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor:
```c
return ƛ0_f_make()(5);
```
`cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
|
|||||||
90
tests/sex-programs/operators.sex
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
(input)
|
||||||
|
(output "logical: 1 1 0"
|
||||||
|
"bitwise: 7 2 5"
|
||||||
|
"shifts: 48 0 12"
|
||||||
|
"increment: 7"
|
||||||
|
"decayed: 2 2 there"
|
||||||
|
"unsigned wins either way: 4294967295 4294967295"
|
||||||
|
"toplevel: 1 2.5 hi 12"
|
||||||
|
"closure in place: 5"
|
||||||
|
"a type is not a call: 7")
|
||||||
|
(return 0)
|
||||||
|
|
||||||
|
;;; The walk types an expression by its head, and the heads it had a
|
||||||
|
;;; rule for were the ones inference was written against. `&&', the
|
||||||
|
;;; bitwise operators, the shifts and `++' were not among them and each
|
||||||
|
;;; stopped with `cannot infer'.
|
||||||
|
;;;
|
||||||
|
;;; The rest of this is the same mistake in three other places: an array
|
||||||
|
;;; is a pointer the moment it is an operand, a rank tie is not decided
|
||||||
|
;;; by which operand was written first, and `_' is not a local's
|
||||||
|
;;; privilege.
|
||||||
|
|
||||||
|
(include stdio.h)
|
||||||
|
|
||||||
|
(fn area ((w int) (h int)) int
|
||||||
|
(return (* w h)))
|
||||||
|
|
||||||
|
;;; a toplevel `_' reads the same table a local's does, so it can name
|
||||||
|
;;; anything declared above it
|
||||||
|
(var n _ 1)
|
||||||
|
(var d _ 2.5)
|
||||||
|
(var s _ "hi")
|
||||||
|
(var a _ (+ 3 (* 3 3)))
|
||||||
|
|
||||||
|
(fn make-adder ((k int)) (closure ((int)) int)
|
||||||
|
(return (closure ((b int)) int (k) (return (+ k b)))))
|
||||||
|
|
||||||
|
(pub fn main () int
|
||||||
|
(var x int 6)
|
||||||
|
(var y int 3)
|
||||||
|
(var ok _ (&& x y))
|
||||||
|
(var orr _ (|| x y))
|
||||||
|
(var neg _ (! x))
|
||||||
|
(printf "logical: %d %d %d\n" ok orr neg)
|
||||||
|
|
||||||
|
(var bor _ (| x y))
|
||||||
|
(var band _ (& x y))
|
||||||
|
(var bxor _ (^ x y))
|
||||||
|
(printf "bitwise: %d %d %d\n" bor band bxor)
|
||||||
|
|
||||||
|
;; a shift is the promoted left operand, not a join: the right one
|
||||||
|
;; says only how far
|
||||||
|
(var c char 12)
|
||||||
|
(var shl _ (<< x y))
|
||||||
|
(var shr _ (>> x y))
|
||||||
|
(var wide _ (>> c 0))
|
||||||
|
(printf "shifts: %d %d %d\n" shl shr wide)
|
||||||
|
|
||||||
|
;; ...and an increment is the operand, unpromoted
|
||||||
|
(var inc _ (++ x))
|
||||||
|
(printf "increment: %d\n" inc)
|
||||||
|
|
||||||
|
;; an array operand decays, so this is a pointer and not an array
|
||||||
|
(var xs (¤ int 4) #(1 2 3 4))
|
||||||
|
(var p _ (+ xs 1))
|
||||||
|
(var q _ (+ 1 xs))
|
||||||
|
(var names (¤ (* const char) 2) #("hi" "there"))
|
||||||
|
(var np _ (+ names 1))
|
||||||
|
(printf "decayed: %d %d %s\n" (* p) (* q) (* np))
|
||||||
|
|
||||||
|
;; at equal rank C takes the unsigned operand, whichever side it is on
|
||||||
|
(var i int -1)
|
||||||
|
(var u (unsigned int) 1)
|
||||||
|
(var u1 _ (+ i u))
|
||||||
|
(var u2 _ (+ u i))
|
||||||
|
(printf "unsigned wins either way: %u %u\n" (- u1 1) (- u2 1))
|
||||||
|
|
||||||
|
(printf "toplevel: %d %g %s %d\n" n d s a)
|
||||||
|
|
||||||
|
;; a closure literal is its own type, so it can be called where it is
|
||||||
|
;; written, the way a lambda already could
|
||||||
|
(printf "closure in place: %d\n"
|
||||||
|
((closure ((v int)) int () (return v)) 5))
|
||||||
|
|
||||||
|
;; a `fn' type's parameter list looks exactly like a call; with a
|
||||||
|
;; closure named `f' in scope it used to be read as one
|
||||||
|
(var f (closure ((int)) int) (make-adder 1))
|
||||||
|
(var fp (fn ((f int) (g int)) int) area)
|
||||||
|
(printf "a type is not a call: %d\n" (f 6))
|
||||||
|
(return 0))
|
||||||
@@ -86,8 +86,14 @@
|
|||||||
(compiled-file (create-temporary-file)))
|
(compiled-file (create-temporary-file)))
|
||||||
;; `process' returns one record; `process-input-port' is named from
|
;; `process' returns one record; `process-input-port' is named from
|
||||||
;; the child's side, so it is the port we write to.
|
;; the child's side, so it is the port we write to.
|
||||||
|
;;
|
||||||
|
;; Sex has no symbol escaping -- `|' is an operator there, not a
|
||||||
|
;; quote -- so the forms go out the way they were written. Left to
|
||||||
|
;; escape, `||' would leave here as `|\|\||' and reach sexc as a
|
||||||
|
;; different symbol.
|
||||||
(let* ((proc (process compiler (append (list "-o" compiled-file) flags)))
|
(let* ((proc (process compiler (append (list "-o" compiled-file) flags)))
|
||||||
(sexc-stdin (process-input-port proc)))
|
(sexc-stdin (process-input-port proc)))
|
||||||
|
(symbol-escape #f)
|
||||||
(with-output-to-port sexc-stdin
|
(with-output-to-port sexc-stdin
|
||||||
(fn (map (fn (fmt #t x)) src)))
|
(fn (map (fn (fmt #t x)) src)))
|
||||||
(close-output-port sexc-stdin)
|
(close-output-port sexc-stdin)
|
||||||
|
|||||||
When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With
nasize-t(an unparsed name, rank 1, same asint):ccaccepts both. C types1 + nassize_t, and theintdeclaration narrows. The same tie makes(+ i u)anintand(+ u i)anunsigned int.char + charis declaredchar.size-tnever reaches thelongrank because it is not a typedef Sex has parsed, so thestrlenexample's(+ 1 n)lands here.The forms that reach this walk are
&&,||,|,&,<<,>>,++.c-andandc-orare the names from before those spellings. The writer already emitsa && bfrom(&& a b).(var ok _ (&& a b))and(var x _ (<< a b))and(var x _ (++ a))all stop withcannot infer the type of.An array operand is returned as the array.
decayininfer.scmis the conversion this comment describes, and nothing in the walk calls it.emits
int p[4] = a + 1.cc:invalid initializer.A subscript types only when the base's surface form is already
(¤ ...). An(* int)is not, sostops with
cannot infer the type of. This is the other use named ondecay.resolve-closure-typesruns here andresolve-wildcarddoes not.(var n _ 1)at toplevel emitsstatic _ n = 1.cc:unknown type name '_'. The same form inside a function becomesint n = 1.walk-partswalks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside afntype.-mshows(var fp (fn ((ƛint_int_call c int)) int) ...), and the C isint (*fp)(c int). With no closure namedc, the same declaration emitsint (*fp)(int).The callee is typed before it is walked, so a closure literal has no type yet and falls through to
convert-arguments. After the walk the form is a call of the constructor:cc:called object is not a function or function pointer.((lambda ((x int)) int (return x)) 5)works, because the lifted function is registered before the call is typed.((make-adder 20) 22)works, because the callee is already a call with a closure return type.When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.
With
nasize-t(an unparsed name, rank 1, same asint):ccaccepts both. C types1 + nassize_t, and theintdeclaration narrows. The same tie makes(+ i u)anintand(+ u i)anunsigned int.char + charis declaredchar.size-tnever reaches thelongrank because it is not a typedef Sex has parsed, so thestrlenexample's(+ 1 n)lands here.The forms that reach this walk are
&&,||,|,&,<<,>>,++.c-andandc-orare the names from before those spellings. The writer already emitsa && bfrom(&& a b).(var ok _ (&& a b))and(var x _ (<< a b))and(var x _ (++ a))all stop withcannot infer the type of.An array operand is returned as the array.
decayininfer.scmis the conversion this comment describes, and nothing in the walk calls it.emits
int p[4] = a + 1.cc:invalid initializer.A subscript types only when the base's surface form is already
(¤ ...). An(* int)is not, sostops with
cannot infer the type of. This is the other use named ondecay.resolve-closure-typesruns here andresolve-wildcarddoes not.(var n _ 1)at toplevel emitsstatic _ n = 1.cc:unknown type name '_'. The same form inside a function becomesint n = 1.walk-partswalks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside afntype.-mshows(var fp (fn ((ƛint_int_call c int)) int) ...), and the C isint (*fp)(c int). With no closure namedc, the same declaration emitsint (*fp)(int).The callee is typed before it is walked, so a closure literal has no type yet and falls through to
convert-arguments. After the walk the form is a call of the constructor:cc:called object is not a function or function pointer.((lambda ((x int)) int (return x)) 5)works, because the lifted function is registered before the call is typed.((make-adder 20) 22)works, because the callee is already a call with a closure return type.