Removed out-of-date honu module.

svn: r2185
This commit is contained in:
Carl Eastlund 2006-02-09 18:14:51 +00:00
parent 2b47616f14
commit 871a696fb9
105 changed files with 0 additions and 9995 deletions

View File

@ -1,298 +0,0 @@
(module ast mzscheme
(require (lib "contract.ss")
(planet "hierarchy.ss" ("dherman" "struct.plt" 2 1))
(planet "inspector.ss" ("dherman" "inspector.plt" 1 0))
(planet "contract-utils.ss" ("cobbe" "contract-utils.plt" 1 0))
)
(with-public-inspector
(define-hierarchy/provide/contract
(ast ; parent structure for AST nodes
([syntax (optional/c syntax?)] ; all nodes store syntax locations
)
(ast:type () ; parent structure for types
(ast:type:top ()) ; "void" or "unit" type
(ast:type:bot ()) ; "error" type, or for non-returning operations
(ast:type:object () ; Object type
(ast:type:object:any ()) ; Distinguished Any type, top of hierarchy
(ast:type:object:null ()) ; Type of null, bottom of hierarchy
(ast:type:object:iface ; Interface type
([name identifier?] ; name of the interface
)))
(ast:type:primitive ; Builtin type (int, char, bool, etc.)
([name symbol?] ; builtins come from a fixed set of names
))
(ast:type:tuple ; Tuple type
([elems (listof ast:type?)] ; types of each tuple element
))
(ast:type:partial/tuple ; Tuple type as inferred from selector
([position integer?] ; position at which type is known
[elem ast:type?] ; type at that position
))
(ast:type:function ; Function type (without dispatch)
([input ast:type?] ; input type
[output ast:type?] ; output type
))
(ast:type:method ; Method type (with receiver dispatch)
([receiver ast:type:object?] ; type of the method's receiver
[input ast:type?] ; input type
[output ast:type?] ; input type
))
)
(ast:defn () ; parent structure for top-level definitions
(ast:defn:iface ; Interface definitions
([name identifier?] ; interface name
[supers (listof ast:type:object?)] ; parent interfaces
[members (listof ast:iface/member?)] ; members (methods and fields)
))
(ast:defn:class ; Class definitions
([name identifier?] ; interface name
[self-type ast:type:object?] ; class's type internally and for subclassing
[final? boolean?] ; whether the class may be extended
[client-types (listof ast:type:object?)] ; implemented interfaces
[formals (listof ast:formal?)] ; constructor arguments
[members (listof ast:class/member?)] ; member definitions
[exports (listof ast:export?)] ; export declarations
))
(ast:defn:mixin ; Mixin definition
([name identifier?] ; mixin name
[self-type ast:type:object?] ; mixin's type internally and for subclassing
[super-type ast:type:object?] ; input interface
[final? boolean?] ; whether the mixin can be extended
[client-types (listof ast:type:object?)] ; implemented interfaces
[formals (listof ast:formal?)] ; constructor arguments
[super-formals (listof ast:formal?)] ; expected parent arguments
[super-new ast:super-new?] ; parent initialization
[pre-members (listof ast:class/member?)] ; members defined before super-new
[post-members (listof ast:class/member?)] ; members defined after super-new
[exports (listof ast:export?)] ; export declarations
))
(ast:defn:subclass ; Subclass definition (applies a mixin to a class)
([name identifier?] ; new class's name
[base identifier?] ; superclass
[mixin identifier?] ; applied mixin
))
(ast:defn:structure ; Structure definition (class and type defined at once)
([name identifier?] ; structure name
[self-type ast:type:object?] ; internal/subclassing type (how does this relate to "structure" type?)
[final? boolean?] ; whether the structure can be extended
[client-types (listof ast:type:object?)] ; implemented interfaces
[formals (listof ast:formal?)] ; constructor arguments
[members (listof ast:class/member?)] ; member definitions
[exports (listof ast:export?)] ; export declarations
))
(ast:defn:substructure ; Substructure definition (defines and instantiates subclassing)
([name identifier?] ; substructure name
[self-type ast:type:object?] ; internal/subclassing type
[super-class identifier?] ; parent class
[super-type ast:type:object?] ; parent interface
[final? boolean?] ; whether the substructure can be extended
[client-types (listof ast:type:object?)] ; implemented interfaces
[formals (listof ast:formal?)] ; constructor arguments
[super-formals (listof ast:formal?)] ; expected parent arguments
[super-new ast:super-new?] ; parent initialization
[pre-members (listof ast:class/member?)] ; members defined before super-new
[post-members (listof ast:class/member?)] ; members defined after super-new
[exports (listof ast:export?)] ; export declarations
))
(ast:defn:function ; Function definition
([name identifier?] ; function name
[return-type ast:type?] ; output type
[formals (listof ast:formal?)] ; input names and types
[body ast:expr?] ; function implementation
))
(ast:defn:binding ; Top-level variable binding
([names (listof identifier?)] ; variable name or names (if binding a tuple)
[types (listof ast:type?)] ; variable type(s)
[init ast:expr?] ; expression providing the bound value(s)
))
)
(ast:iface/member ; Member declared in an interface
([name identifier?] ; member name
)
(ast:iface/member:field ; Field of an interface
([type ast:type?] ; field type
))
(ast:iface/member:method ; Method of an interface
([return-type ast:type?] ; output type
[formal-types (listof ast:type?)] ; input types
)))
(ast:class/member ; Member defined in a class/mixin
([name identifier?] ; member name
)
(ast:class/member:field ; Field of a class
([type ast:type?] ; field type
[default (optional/c ast:expr?)] ; default value
))
(ast:class/member:field/formal ; Field and constructor argument
([type ast:type?] ; field type
[default (optional/c ast:expr?)] ; default value
))
(ast:class/member:method ; Method of a class
([return-type ast:type?] ; output type
[formals (listof ast:formal?)] ; method arguments
[body ast:expr?] ; method implementation
)))
(ast:super-new ; Parent class initializer
([args (listof ast:named/arg?)] ; constructor arguments
))
(ast:expr () ; Parent structure for expressions
(ast:expr:self ()) ; Self-reference within an object
(ast:expr:var ; Variable reference
([name identifier?] ; variable name
))
(ast:expr:assign ; Assignment
([lhs ast:expr?] ; assignment destination
[rhs ast:expr?] ; assignment source
))
(ast:expr:apply ; Function call
([func ast:expr?] ; invoked function
[arg ast:expr?] ; actual arguments
))
(ast:expr:literal ; Primitive value
([type ast:type?] ; literal type
[value syntax?] ; literal value
))
(ast:expr:unary/op ; Prefix operation
(
[name symbol?] ; operator name
[rator-stx syntax?] ; operator syntax
[rator-type (optional/c ast:type?)] ; operator type (presumably added by typechecker)
[arg ast:expr?] ; operator argument
))
(ast:expr:binary/op ; Infix operation
(
[name symbol?] ; operator name
[rator-stx syntax?] ; operator syntax
[rator-type (optional/c ast:type?)] ; operator type (presumably added by typechecker)
[left ast:expr?] ; first argument
[right ast:expr?] ; second argument
))
(ast:expr:function ; Anonymous function value
([return-type ast:type?] ; output type
[formals (listof ast:formal?)] ; arguments
[body ast:expr?] ; function implementation
))
(ast:expr:if ; Simple conditional
([test ast:expr?] ; Boolean expression
[then ast:expr?] ; Result when true
[else ast:expr?] ; Result when false
))
(ast:expr:cast ; Typecast
([object ast:expr?] ; value to cast
[type ast:type:object?] ; type of cast
))
(ast:expr:isa ; Type conditional
([object ast:expr?] ; value to test
[type ast:type:object?] ; type of test
))
(ast:expr:member ; Access field or method
([object (union ast:expr? (symbols 'my))] ; receiver
[object-type (optional/c ast:type:object?)] ; receiver type
[name identifier?] ; member name
[method? (union boolean? (symbols 'unknown))] ; whether member is a method or field
))
(ast:expr:let ; Local bindings
([bindings (listof ast:defn:binding?)] ; new definitions
[body ast:expr?] ; expression in new scope
))
(ast:expr:sequence ; Sequential statements
([statements (listof ast:expr?)] ; executed in order for effect only
[result ast:expr?] ; executed last and returned
))
(ast:expr:new ; Object construction
([class identifier?] ; class to instantiate
[type (optional/c ast:type:object?)] ; static type of object (presumably added by typechecker)
[args (listof ast:named/arg?)] ; constructor arguments
))
(ast:expr:cond ; Multiple-branch conditional
([clauses (listof ast:cond/clause?)] ; conditional clauses
[else ast:expr?] ; result if all else fails
))
(ast:expr:while ; Imperative recursion
([test ast:expr?] ; controls loop
[body ast:expr?] ; loop body
))
(ast:expr:return ; Escapes function/method
([result ast:expr?] ; returned value
))
(ast:expr:tuple ; Tuple constructor
([elems (listof ast:expr?)] ; tuple elements
))
(ast:expr:tuple/select ; Tuple projection
([position integer?] ; selected element
[arg ast:expr?] ; tuple expression
)))
(ast:export ; Export declaration
([type ast:type:object?] ; exported type
[members (listof ast:export/member?)] ; exported members
))
(ast:formal ; Declared arguments
([name identifier?] ; variable name
[type ast:type?] ; argument type
))
(ast:cond/clause ; Conditional branches
([test ast:expr?] ; condition
[result ast:expr?] ; result if true
))
(ast:export/member ; Individual export specification
([internal identifier?] ; name inside class/mixin
[external identifier?] ; name from interface
))
(ast:named/arg ; By-name arguments
([name identifier?] ; argument name
[actual ast:expr?] ; argument value
))
)))
)

View File

@ -1,84 +0,0 @@
(module base mzscheme
(require (lib "class.ss"))
(define-syntax (honu:send stx)
(syntax-case stx ()
[(_ obj msg arg ...)
#'(if (is-a? obj null%)
(error "Attempt to access member of null")
(send obj msg arg ...))]))
(define null%
(class object%
(inspect #f)
(super-new)))
(define null-obj (new null%))
(define Any<%>
(interface ()))
(define (printString s)
(display s)
'())
(define (printLine s)
(display s)
(newline)
'())
(define (readChar arg-tuple)
(read-char))
(define (readLine arg-tuple)
(read-line))
(define (stringToInt s)
(let ([number (string->number s)])
(if (and number (integer? number))
number
(error (format "Tried to convert \"~a\" to an integer" s)))))
(define (stringToFloat s)
(let ([number (string->number s)])
(if (and number (inexact? number))
number
(error (format "Tried to convert \"~a\" to an float" s)))))
(define (intToString i)
(number->string i))
(define (floatToString f)
(number->string f))
(define (charToString c)
(string c))
(define (strlen s)
(string-length s))
(define (substr arg-tuple)
(let-values ([(s start end) (apply values arg-tuple)])
(cond
[(< start 0)
(error (format "Start index for substr must be positive, got ~a" start))]
[(> start end)
(error (format "Start index (~a) must be <= end index (~a)" start end))]
[(> end (string-length s))
(error (format "End index for substr must be <= strlen(s), got ~a" end))]
[else (substring s start end)])))
(define (charAt arg-tuple)
(let-values ([(s i) (apply values arg-tuple)])
(cond
[(< i 0)
(error (format "Index for charAt must be non-negative, got ~a" i))]
[(> i (- (string-length s) 1))
(error (format "Index for charAt must be < strlen(s), got ~a" i))]
[else (string-ref s i)])))
(provide (all-from mzscheme)
(rename ormap mz:ormap)
(all-from (lib "class.ss"))
(all-defined)))

View File

@ -1,41 +0,0 @@
Todo:
AST
- changed names in ast.ss, propagate to everywhere else
- added (some) contracts; add the rest and verify what's there
- finish writing, and use, define-structs[/provide[/contract]]
Mixin Sealing
- move to single, applicative environment
Test Suite Improvements
Numeric Library
------------------------------------------------------------
File purposes:
doc.txt: implementation notes
tool.ss: definition of language level
compile.ss: top-level compilation functions
util.ss: general functions (similar to list.ss)
tenv.ss: definition of type environment
- don't understand all the types defined
tenv-utils.ss: manipulate environments
base.ss: top-level honu definitions
ast.ss: ast structs
private/typechecker/type-utils.ss: simple type operations
------------------------------------------------------------
General structure:
3 phases:
- parser tools (-> AST)
- post-parsing
- static references to "my" references (my.x for static fields, etc.)
- references to "this" only in member access (this.x) or in casts ((IFace)this)
- adds casts to this.x
- simplify-ast : gather asts/sequences into big lets/sequences
.
.
.

View File

@ -1,62 +0,0 @@
(module compile mzscheme
(require (lib "boundmap.ss" "syntax")
(lib "contract.ss")
(lib "plt-match.ss")
"ast.ss"
"honu-context.ss"
"parameters.ss"
"readerr.ss"
"tenv.ss"
"tenv-utils.ss"
"parsers/post-parsing.ss"
"private/compiler/translate.ss"
"private/compiler/translate-expression.ss"
"private/typechecker/type-utils.ss"
"private/typechecker/typechecker.ss"
"private/typechecker/typecheck-expression.ss")
(provide/contract [compile/defns
((tenv? tenv? (listof ast:defn?))
. ->* .
(any/c (listof (syntax/c any/c))))]
[compile/interaction
((tenv?
tenv?
(union ast:defn:binding? ast:expr?))
. ->* .
((syntax/c any/c)
(union ast:type? false/c)))])
(define (compile/defns tenv lenv pgm)
(parameterize ([current-type-environment tenv]
[current-lexical-environment lenv])
(let ([pgm (post-parse-program (add-defns-to-tenv pgm))])
(let ([checked (typecheck pgm)])
(parameterize ([current-compile-context honu-compile-context])
(translate checked))))))
(define (check-bound-names names)
(for-each (lambda (n)
(if (and n (get-lenv-entry n))
(raise-read-error-with-stx
(format "~a already bound" (printable-key n))
n)))
names))
(define (compile/interaction tenv lenv ast)
(parameterize ([current-type-environment tenv]
[current-lexical-environment lenv])
(match (post-parse-interaction ast)
[(struct ast:defn:binding (stx names _ value))
(check-bound-names names)
(let ([checked (typecheck-defn ast)])
(parameterize ([current-compile-context honu-compile-context])
(values (translate-defn checked) #f)))]
[else
(let-values ([(checked type)
(typecheck-expression
(wrap-lenv) (make-top-type #f) ast)])
(parameterize ([current-compile-context honu-compile-context])
(values (translate-expression checked) type)))])))
)

View File

@ -1,409 +0,0 @@
_Honu_
_TODO_
* Admit statements as elements of mixin bodies, i.e.,
struct ExamplesC() : Examples {
IStack s0 = new StackC();
int d0 = s0.depth();
s0.push(s0);
}
should work. -- MF
* Work out details of standard library, including boxed versions of
primitive types.
* If you do have a standard library, document it please. -- MF
* Let's add arrays.
* Add new statement that uses positional initialization arguments.
* Add autoboxing of primitive types.
* Add generics (parametric polymorphism and bounded polymorphism).
RESEARCH!
_Primitive types_
int - integers
float - floating point numbers
string - strings (double quoted)
bool - booleans (true, false)
char - characters (single quoted)
_Built-in functions_
Error reporting:
> error(string message) => 'a
- Raises an error and prints the string as an error message.
- Calls to error() do not return.
Input/output:
> printString(string message) => void
- Takes a string and prints it on the standard output.
> printLine(string message) => void
- Like printString, but prints a newline after printing the string.
> readChar() => char
- Reads a single character from the standard input.
> readLine() => string
- Reads a line of text from the standard input.
Conversions to string:
> intToString(int val) => string
- Converts an integer to a string.
> floatToString(float val) => string
- Converts a floating point number to a string.
> charToString(char val) => string
- Converts a character to a string.
String conversions:
> stringToInt(string val) => int
- Converts a string to an integer.
- Raises an error if the string cannot be converted.
> stringToFloat(string val) => float
- Converts a string to a floating point number.
- Raises an error if the string cannot be converted.
String operations:
> strlen(string s) => int
- Takes a string and returns the string length.
> substr(string s, int start, int end) => string
- Takes a string, a start index, and an end index and
returns the corresponding substring.
- The indexes are zero-based.
- The start index cannot be negative or greater than the end index.
- The end index must be less than or equal to the string length.
> charAt(string s, int i) => char
- Takes a string and an index into the string and returns
the corresponding character.
- The zero-based index cannot be negative and must be less
than the string length.
Numeric operations:
> sqrt(float f) => float
- Produces the square root of its argument.
_Operators_
Unary operators:
> ! : bool -> bool
- Boolean negation (not)
> - : bool -> bool
- Arithmetic negation
Binary operators:
> || : bool * bool -> bool
- Boolean disjunction (or)
> && : bool * bool -> bool
- Boolean conjunction (and)
> == : bool * bool -> bool
> == : int * int -> bool
> == : char * char -> bool
> == : float * float -> bool
> == : string * string -> bool
- Equivalence for primitives (value equality)
> == : Any * Any -> bool
- Identity for classes (pointer equality)
> != (same types as ==)
- Boolean negation of equivalence/identity
> ==== : Any * Any -> bool
- Equivalence for classes (value equality)
> < : int * int -> bool
> < : float * float -> bool
> < : char * char -> bool
> < : string * string -> bool
- Less than (numeric / character set / lexiographic)
> > (same types as <)
- Greater than
> <= (same types as <)
- Less than or equal to
> >= (same types as <)
- Greater than or equal to
> + : int * int -> int
> + : float * float -> float
- Addition
> + : string * string -> string
- String concatenation
> - : int * int -> int
> - : float * float -> float
- Subtraction
> * : int * int -> int
> * : float * float -> float
- Multiplication
> / : int * int -> int
- Integer division
> / : float * float -> float
- Division
> % : int * int -> int
- Remainder (from integer division)
_Grammar_
NOTE: Since I want to use parentheses to mean "real" parentheses, I use
square brackets for grouping inside of rules.
<program> ::= <defn>*
<defn> ::= <function>
| <top-bind>
| <type>
| <class>
| <mixin>
| <subclass>
<top-bind> ::= <bind> = <expr> ;
| ( <bind> [, <bind>]* ) = <expr>;
<bind> ::= <tid> <id>
| _
<function> ::= <tid> <id> ( <argdecls> ) <block>
<tid> ::= <ifacet>
| <primtype>
| <funtype>
| <tuptype>
<funtype> ::= <tid> -> <tid>
<tuptype> ::= < >
| < <tid> [, <tid>]* >
<ifacet> ::= id
| Any
<primtype> ::= int
| float
| bool
| str
| char
| void
<type> ::= type <id> <extends> { <mfdecl>* }
| interface <id> <extends> { <mfdecl>* }
<extends> ::= extends <ifacet> [, <ifacet>]*
| <: <ifacet> [, <ifacet>]*
|
<mfdecl> ::= <tid> <fdid> ;
| <tid> <mdid> ( <argdecls>* ) ;
<argdecls> ::= <argdecl> [, <argdecl>]*
|
<argdecl> ::= <tid>
| <tid> <varid>
<struct> ::= struct <id> <initargs> : <ifacet> <impls> <clsbody>
| final struct <id> <initargs> : <ifacet> <impls> <clsbody>
| struct <id> <initargs> : <ifacet>
extends <id> <initargs> : <ifacet> <impls> <mixbody>
| final struct <id> <initargs> : <ifacet>
extends <id> <initargs> : <ifacet> <impls> <mixbody>
<class> ::= class <id> <initargs> : <ifacet> <impls> <clsbody>
| final class <initargs> <id> : <ifacet> <impls> <clsbody>
| class <id> = <id> ( <id> ) ;
| class <id> <initargs> : <ifacet>
extends <id> <initargs> : <ifacet> <impls> <mixbody>
| final class <id> <initargs> : <ifacet>
extends <id> <initargs> : <ifacet> <impls> <mixbody>
<mixin> ::= mixin <id> <initargs> : <ifacet> <initargs> -> <ifacet>
<impls> <mixbody>
| final mixin <id> <initargs> : <ifacet> <initargs> -> <ifacet>
<impls> <mixbody>
<initargs> ::= ( <tid> <id> [, <tid> <id>]* )
| ( )
<impls> ::= implements <ifacet> [, <ifacet>]*
| impl <ifacet> [, <ifacet>]*
|
<clsbody> ::= { <mfidefn>* <export>* }
<mixbody> ::= { <mfidefn>* <supernew> <mfidefn>* <export>* }
<mfidefn> ::= init <tid> <id> ;
| init <tid> <id> = <expr> ;
| <tid> <id> = <expr> ;
| <tid> <id> ( <argdefns> ) <block>
<supernew> ::= super( <newargs> ) ;
<argdefns> ::= <argdefn> [, <argdefn>]*
|
<argdefn> ::= <tid> <id>
<newargs> ::= <newarg> [, <newarg>]*
|
<newarg> ::= <id> = <expr>
<export> ::= export <ifacet> : <renames> ;
<renames> ::= <rename> [, <rename>]*
<rename> ::= <id>
| <id> as <id>
<expr> ::= <literal>
| <lambda>
| <tuple>
| #n <expr>
| <id>
| <expr> = <expr>
| <expr> <tuple>
| this
| <expr> : <ifacet>
| <expr> isa <ifacet>
| if <expr> <block> [else <block>]?
| cond { [<expr> => <expr> ;]+ }
| cond { [<expr> => <expr> ;]* else <expr> ; }
| while <expr> <block>
| new <id> : <ifacet> ( <newargs> )
| new <id> ( <newargs> )
| ! <expr>
| - <expr>
| <expr> || <expr>
| <expr> && <expr>
| <expr> == <expr>
| <expr> != <expr>
| <expr> ==== <expr>
| <expr> < <expr>
| <expr> > <expr>
| <expr> <= <expr>
| <expr> >= <expr>
| <expr> + <expr>
| <expr> - <expr>
| <expr> * <expr>
| <expr> / <expr>
| <expr> % <expr>
| <expr> . <id>
| return <expr>
| <block>
NOTE: Here's the precedence and associativity of things above.
Top is most strongly binding, bottom is least. Things on
the same line have same precedence. The : below refers to
casting, and the = is for assignment. else requires a
precedence to avoid shift/reduce errors, even though we
don't have the dangling else problem.
LEFT | RIGHT | NONASSOC
----------+----------+-----------
. | |
| | ( (function application)
| | #n (tuple selector)
| : isa |
| | !, - (un)
* / % | |
+ - | |
| | < <= > >=
| | ====
== != | |
&& | |
|| | |
= | |
else | |
| | return
<tuple> ::= ( )
| ( <exprs-cd> )
<lambda> ::= <tid> fun ( <argdecls> ) <block>
<exprs-cd> ::= <expr> [, <expr>]*
| <expr>
<literal> ::= <intlit>
| <floatlit>
| true
| false
| <strlit>
| <charlit>
| null
<block> ::= { <stmts> }
<stmts> ::= <expr-sc>
| <vardefn> <stmts>
| <expr-sc> <stmts>
<vardefn> ::= <bind> = <expr> ;
| ( <bind> [, <bind>]* ) = <expr> ;
<expr-sc> ::= <expr> ;
_Mixin Definitions_
Assume a mixin of the following form:
[final] mixin MixinName( initType1 initArg1, ..., initTypeN initArgN ) :
ParentIFace( superType1 superArg1, ..., superTypeM superArgM ) -> SelfIFace
[implements IFace1, ..., IFaceK]
{
Member1; ... MemberI;
SuperNew;
MemberI+1; ... MemberJ;
Exports;
}
This defines a mixin called MixinName. This mixin consumes a class with
selftype ParentIFace and produces one with selftype SelfIFace. The parent class
must have the initialization arguments listed after ParentIFace. These
arguments are supplied by the new class's initialization. The new class
provides interfaces IFace1 through IFaceK for clients and interface SelfIFace
(its selftype) for further mixins.
The new class introduces the arguments listed after MixinName as well as all
init fields declared in the members (Member1 through MemberJ). All init
arguments, whether declared in the header or the body of the mixin definition,
are both initialization arguments to the new class and fields usable within
the body of the class. Init field declarations in the body may include default
values. All other initialization arguments to the new class are passed on to
its superclass initializer.
Member definitions include fields, init fields, and methods, and exactly one
call to the superclass initializer; as mentioned above, init arguments are also
implicit field definitions. Export declarations define a mapping from exported
names to internal member names.

View File

@ -1,46 +0,0 @@
(module environment mzscheme
(require (lib "contract.ss")
(prefix env: (planet "environment.ss" ("cobbe" "environment.plt" 2 1)))
)
(provide/contract
[mapping? (any/c . -> . boolean?)]
[empty (-> mapping?)]
[extend (mapping? identifier? any/c . -> . mapping?)]
[contains? (mapping? identifier? . -> . boolean?)]
[lookup (([mapping
(lambda (mapping)
(and (mapping? mapping)
(contains? mapping id)))]
[id identifier?])
. ->r . any)]
)
;; mapping? : Any -> Boolean
;; Reports whether a value is a mapping.
(define (mapping? value)
(env:env? value))
;; empty : -> [Mapping X]
;; Contructs an empty mapping.
(define (empty)
(env:make-empty-env bound-identifier=?))
;; extend : [Mapping X] Identifier X -> [Mapping X]
;; Adds or shadows an environment binding.
(define (extend mapping id entry)
(env:extend-env (list id) (list entry) mapping))
;; contains? : [Mapping X] Identifier -> Boolean
;; Reports whether the given key has an entry.
(define (contains? mapping id)
(env:bound? mapping id))
;; lookup : [Mapping X] Identifier -> X
;; Returns the entry for the given key.
;; Raises exn:fail:contract if no entry exists.
(define (lookup mapping id)
(env:lookup mapping id))
)

View File

@ -1,41 +0,0 @@
(define (push stack num)
(send stack BoundedStack<%>-push (new IntegerC% [value num])))
(define s0 (emptyBoundedStack 5))
(define s1 (push s0 5))
(define s2 (push s1 3))
(define s3 (push s2 10))
(define s4 (push s3 20))
(define s5 (push s4 40))
(append (map interface? (list List<%>
Stack<%>
BoundedStack<%>
Integer<%>))
(map class? (list ConsList%
BoundedStackC%
ListStackC%
IntegerC%))
(map
(lambda (object)
(andmap
(lambda (spec) (is-a? object spec))
(list Stack<%> BoundedStack<%> BoundedStack<%>)))
(list s0 s1 s2 s3 s4 s5))
(list
(not (send s0 BoundedStack<%>-isFull '()))
(not (send s1 BoundedStack<%>-isFull '()))
(not (send s2 BoundedStack<%>-isFull '()))
(not (send s3 BoundedStack<%>-isFull '()))
(not (send s4 BoundedStack<%>-isFull '()))
(send s5 BoundedStack<%>-isFull '()))
(list
(let* ([expected (list 5 3 10 20 40)]
[actual (list)])
(send s5 BoundedStack<%>-foreach
(lambda (int)
(set! actual (cons (send int Integer<%>-value-get 'Dummy) actual))))
(equal? expected actual))
(with-handlers ([exn:fail? (lambda (exn) #t)])
(push s5 50)
#f)))

View File

@ -1,345 +0,0 @@
//
//
// -$@:@ @@
// @ -@ @ @
// $: @@@@@ $@$: $@+@ @ @@@
// -$@$ @ -@ $+ -@ @ *$
// *$ @ -$@$@ @ @$$
// @ @ $* @ @ @$$
// @+ -$ @: :$ @- *@ $* -$ @ -$
// @:@$- :@@$- -$$-@@ $@$- @@ @@@-
//
//
//
//
type Stack {
Stack push(Any x);
<Stack, Any> pop();
void foreach(Any -> void);
}
class ListStackC(List list) : Stack impl Stack {
Stack push(Any x) {
return new ListStackC(list = new ConsList(car = x, cdr = list));
}
<Stack, Any> pop() {
return (new ListStackC(list = list.rest()), list.first());
}
void foreach(Any -> void f) { list.foreach(f); }
export Stack : push, pop, foreach;
}
Stack emptyStack() {
return new ListStackC(list = new MTList());
}
//
//
//@@@@@: @@ @@ -$@:@ @@
// @ :@ @ @ @ -@ @ @
// @ -$ $@$ @@ @@ @@:@@: $@:@ -@@$ $@:@ $: @@@@@ $@$: $@+@ @ @@@
// @@@$ $- -$ @ @ @+ :@ $* *@ $ -$ $* *@ -$@$ @ -@ $+ -@ @ *$
// @ :$ @ @ @ @ @ @ @ @ @@@@@ @ @ *$ @ -$@$@ @ @$$
// @ @ @ @ @ @ @ @ @ @ $ @ @ @ @ $* @ @ @$$
// @ :@ $- -$ @: +@ @ @ $* *@ +: $* *@ @+ -$ @: :$ @- *@ $* -$ @ -$
//@@@@@: $@$ :@$-@@@@@ @@@ $@:@@ $@@+ $@:@@ @:@$- :@@$- -$$-@@ $@$- @@ @@@-
//
//
//
//
type BoundedStack <: Stack {
BoundedStack push(Any x);
<BoundedStack, Any> pop();
bool isFull();
int spaceRemaining();
}
// space = number of pushes possible on this stack
class BoundedStackC(Stack stack, int space) : BoundedStack impl BoundedStack {
bool isFull() { return space < 1; }
int spaceRemaining() { return space; }
BoundedStack push(Any x) {
if(isFull()) { error("Stack is full"); }
else {
return new BoundedStackC(stack = stack.push(x), space = space - 1);
};
}
<BoundedStack, Any> pop() {
(Stack s, Any obj) = stack.pop();
return (new BoundedStackC(stack = s, space = space + 1), obj);
}
void foreach(Any -> void f) { stack.foreach(f); }
export BoundedStack : push, pop, isFull, spaceRemaining, foreach;
}
BoundedStack emptyBoundedStack(int n) {
return new BoundedStackC(stack = emptyStack(), space = n);
}
//
//
// +@@@*
// @ @
// @ @@:@@: @@@@@ -@@$ $@-@@ -@@$ @@-$+
// @ @+ :@ @ $ -$ $* :@ $ -$ @$ :
// @ @ @ @ @@@@@ @ @ @@@@@ @
// @ @ @ @ $ @ @ $ @
// @ @ @ @: :$ +: $* :@ +: @
// -@@@: @@@ @@@ :@@$- $@@+ $@:@ $@@+ @@@@@
// -$
// -@@$
//
//
struct IntegerC(int value) : Integer { }
//
//
// @@@ @
// @ @
// @ -@@ :@@+@ @@@@@
// @ @ @$ -@ @
// @ @ :@@$- @
// @ @ @ *@ @
// @ @ @ @ :@ @: :$
// @@@@@ @@@@@ $+@@: :@@$-
//
//
//
//
type List {
List addToFront(Any);
List addToEnd(Any);
Any first();
Any atIndex(int);
Any last();
List rest();
List drop(int);
List take(int);
List appendToEnd(List);
List appendToFront(List);
List reverse();
int length();
bool empty();
List map(Any -> Any);
Any foldl(<Any, Any> -> Any, Any);
Any foldr(<Any, Any> -> Any, Any);
List filter(Any -> bool);
void foreach(Any -> void);
}
class MTList() : List impl List {
List add(Any elt) {
return new ConsList(car = elt, cdr = (this : List));
}
Any no_elts(int n) {
error("The empty list has no elements!");
}
Any no_elt() {
error("The empty list has no elements!");
}
List rest() {
error("Cannot get the rest of the empty list!");
}
List drop(int n) {
if n == 0 {
this : List;
} else {
error("Attempt to drop elements from an empty list!");
};
}
List take(int n) {
if n == 0 {
this : List;
} else {
error("Attempt to take elements from an empty list!");
};
}
List ret_other(List l) { return l; }
List reverse() { return (this : List); }
int length() { return 0; }
bool empty() { return true; }
List map(Any -> Any f) { return (this : List); }
Any fold(<Any, Any> -> Any f, Any i) { return i; }
List filter(Any -> bool f) { return (this : List); }
void foreach(Any -> void f) { return(); }
export List : add as addToFront, add as addToEnd,
no_elt as first, no_elts as atIndex, no_elt as last,
rest, drop, take, reverse,
ret_other as appendToEnd, ret_other as appendToFront,
length, empty,
map, fold as foldl, fold as foldr, filter, foreach;
}
// Since init slots get translated to init fields by need, we can put
// car and cdr here, and then use them appropriately inside the methods
// which will make them fields.
class ConsList(Any car, List cdr) : List impl List {
Any first() { return car; }
Any atIndex(int n) {
if n == 0 {
car;
} else {
cdr.atIndex(n - 1);
};
}
Any last() {
if cdr.empty() {
car;
} else {
cdr.last();
};
}
List rest() {
return cdr;
}
List drop(int n) {
if n == 0 {
this : List;
} else {
cdr.drop(n - 1);
};
}
List take(int n) {
if n == 0 {
new MTList();
} else {
new ConsList(car = car, cdr = cdr.take(n - 1));
};
}
List addToFront(Any x) {
return new ConsList(car = x, cdr = (this : List));
}
List addToEnd(Any x) {
return new ConsList(car = car, cdr = cdr.addToEnd(x));
}
List appendToFront(List other) {
if other.empty() {
this : List;
} else {
new ConsList(car = other.first(), cdr = other.drop(1));
};
}
List appendToEnd(List other) {
return new ConsList(car = car, cdr = cdr.appendToEnd(other));
}
List reverse() {
return cdr.reverse().addToEnd(car);
}
int length() { return 1 + cdr.length(); }
bool empty() { return false; }
List map(Any -> Any f) {
return new ConsList(car = f(car), cdr = cdr.map(f));
}
Any foldl(<Any, Any> -> Any f, Any i) {
return f(car, cdr.foldl(f, i));
}
Any foldr(<Any, Any> -> Any f, Any i) {
return cdr.foldr(f, f(car, i));
}
List filter(Any -> bool f) {
if f(car) {
new ConsList(car = car, cdr = cdr.filter(f));
} else {
cdr.filter(f);
};
}
void foreach(Any -> void f) {
f(car);
cdr.foreach(f);
}
export List : addToFront, addToEnd, first, atIndex, last, reverse,
rest, drop, take, appendToEnd, appendToFront, length, empty,
map, foldl, foldr, filter, foreach;
}
//
//
//@@@@@@ @@
// @ @ @
// @ @ @@ @@ $@$: @@+-$: @@:@$- @ -@@$ :@@+@
// @@@ $ -$- -@ @+@$@ @: -$ @ $ -$ @$ -@
// @ @ $$- -$@$@ @ @ @ @ @ @ @@@@@ :@@$-
// @ -$$ $* @ @ @ @ @ @ @ $ *@
// @ @ -$- $ @- *@ @ @ @ @: -$ @ +: @ :@
//@@@@@@ @@ @@ -$$-@@@@@@@@@ @-@$ @@@@@ $@@+ $+@@:
// @
// @@@
//
//
// Stack empty = emptyBoundedStack(5);
// Stack s1 = empty.push(new IntegerC(value = 5));
// Stack s2 = s1.push(new IntegerC(value = 3));
// Stack s3 = s2.push(new IntegerC(value = 10));
// Stack s4 = s3.push(new IntegerC(value = 20));
// Stack s5 = s4.push(new IntegerC(value = 40));
// use foreach + don't care(about binding) syntax
// _ = s5.foreach(void fun(Any x) {
// cond {
// x isa Integer => printLine(intToString((x : Integer).value));
// else printLine("Unknown type of value");
// };
// });
// Now try adding something to s5!
// Stack s6 = s5.push(new IntegerC(value = 50));

View File

@ -1,8 +0,0 @@
(define EO (new EvenOddC%))
(list (interface? EvenOdd<%>)
(class? EvenOddC%)
(send EO EvenOdd<%>-even 4)
(not (send EO EvenOdd<%>-even 5))
(send EO EvenOdd<%>-odd 7)
(not (send EO EvenOdd<%>-odd 6)))

View File

@ -1,24 +0,0 @@
type EvenOdd {
bool even(int);
bool odd(int);
}
// The following class tests mutually recursive methods.
class EvenOddC() : EvenOdd impl EvenOdd {
bool even(int n) {
cond {
n == 0 => return true;
n < 0 => return even(-n);
else return odd(n - 1);
};
}
bool odd(int n) {
cond {
n == 0 => return false;
n < 0 => return odd(-n);
else return even(n - 1);
};
}
export EvenOdd : even, odd;
}

View File

@ -1,19 +0,0 @@
(define MT (new MTList%))
(define (Cons first rest) (new ConsList% [car first] [cdr rest]))
(define l0 MT)
(define l1 (Cons 0 l0))
(define l2 (Cons 1 l1))
(define l3 (Cons 2 l2))
(list (interface? List<%>)
(class? MTList%)
(class? ConsList%)
(send l0 List<%>-empty '())
(not (send l1 List<%>-empty '()))
(not (send l2 List<%>-empty '()))
(not (send l3 List<%>-empty '()))
(equal? (send l0 List<%>-length '()) 0)
(equal? (send l1 List<%>-length '()) 1)
(equal? (send l2 List<%>-length '()) 2)
(equal? (send l3 List<%>-length '()) 3))

View File

@ -1,185 +0,0 @@
type List {
List addToFront(Any);
List addToEnd(Any);
Any first();
Any atIndex(int);
Any last();
List rest();
List drop(int);
List take(int);
List appendToEnd(List);
List appendToFront(List);
List reverse();
int length();
bool empty();
List map(Any -> Any);
Any foldl(<Any, Any> -> Any, Any);
Any foldr(<Any, Any> -> Any, Any);
List filter(Any -> bool);
void foreach(Any -> void);
}
class MTList() : List impl List {
List add(Any elt) {
return new ConsList(car = elt, cdr = (this : List));
}
Any no_elts(int n) {
error("The empty list has no elements!");
}
Any no_elt() {
error("The empty list has no elements!");
}
List rest() {
error("Cannot get the rest of an empty list!");
}
List drop(int n) {
if n == 0 {
this : List;
} else {
error("Attempt to drop elements from an empty list!");
};
}
List take(int n) {
if n == 0 {
this : List;
} else {
error("Attempt to take elements from an empty list!");
};
}
List ret_other(List l) { return l; }
List reverse() { return (this : List); }
int length() { return 0; }
bool empty() { return true; }
List map(Any -> Any f) { return (this : List); }
Any fold(<Any, Any> -> Any f, Any i) { return i; }
List filter(Any -> bool f) { return (this : List); }
void foreach(Any -> void f) { return(); }
export List : add as addToFront, add as addToEnd,
no_elt as first, no_elts as atIndex, no_elt as last,
rest, drop, take, reverse,
ret_other as appendToEnd, ret_other as appendToFront,
length, empty,
map, fold as foldl, fold as foldr, filter, foreach;
}
// Since init slots get translated to init fields by need, we can put
// car and cdr here, and then use them appropriately inside the methods
// which will make them fields.
class ConsList(Any car, List cdr) : List impl List {
Any first() { return car; }
Any atIndex(int n) {
if n == 0 {
car;
} else {
cdr.atIndex(n - 1);
};
}
Any last() {
if cdr.empty() {
car;
} else {
cdr.last();
};
}
List rest() { return cdr; }
List drop(int n) {
if n == 0 {
this : List;
} else {
cdr.drop(n - 1);
};
}
List take(int n) {
if n == 0 {
new MTList();
} else {
new ConsList(car = car, cdr = cdr.take(n - 1));
};
}
List addToFront(Any x) {
return new ConsList(car = x, cdr = (this : List));
}
List addToEnd(Any x) {
return new ConsList(car = car, cdr = cdr.addToEnd(x));
}
List appendToFront(List other) {
if other.empty() {
this : List;
} else {
new ConsList(car = other.first(), cdr = other.drop(1));
};
}
List appendToEnd(List other) {
return new ConsList(car = car, cdr = cdr.appendToEnd(other));
}
List reverse() {
return cdr.reverse().addToEnd(car);
}
int length() { return 1 + cdr.length(); }
bool empty() { return false; }
List map(Any -> Any f) {
return new ConsList(car = f(car), cdr = cdr.map(f));
}
Any foldl(<Any, Any> -> Any f, Any i) {
return f(car, cdr.foldl(f, i));
}
Any foldr(<Any, Any> -> Any f, Any i) {
return cdr.foldr(f, f(car, i));
}
List filter(Any -> bool f) {
if f(car) {
new ConsList(car = car, cdr = cdr.filter(f));
} else {
cdr.filter(f);
};
}
void foreach(Any -> void f) {
f(car);
cdr.foreach(f);
}
export List : addToFront, addToEnd, first, atIndex, last, reverse,
rest, drop, take, appendToEnd, appendToFront, length, empty,
map, foldl, foldr, filter, foreach;
}

View File

@ -1,7 +0,0 @@
(list (interface? T<%>)
(class? Y%)
(= (main 5) 120)
(= ((fix (lambda (f)
(lambda (n)
(if (zero? n) 0 (+ n (f (- n 1))))))) 5)
15))

View File

@ -1,15 +0,0 @@
int -> int fix(<int -> int> -> int -> int f) {
T -> int -> int g = int->int fun(T x) { f(int fun(int y) { x.f(x)(y); }); };
g (new Y(f = g));
}
struct Y(T -> int -> int f) : T { }
int -> int factorialor(int -> int factorial) {
int fun(int x) {
if(x == 0) { 1; }
else { x * factorial(x - 1); };
};
}
int main(int n) { fix(factorialor)(n); }

View File

@ -1 +0,0 @@
(list (= x 3) (= y 4))

View File

@ -1 +0,0 @@
(int x, int y) = { int x = 3; int y = 4; (x, y); };

View File

@ -1 +0,0 @@
(list (= x 2))

View File

@ -1,5 +0,0 @@
int x = cond {
1 > 3 => 4;
5 < 6 => 2;
else 8;
};

View File

@ -1,4 +0,0 @@
(list (even 4)
(not (even 5))
(not (odd 4))
(odd 5))

View File

@ -1,23 +0,0 @@
// This tests mutually recursive function definitions.
bool even(int n) {
cond {
n == 0 => return true;
n < 0 => return even(-n);
else return odd(n - 1);
};
}
// If the following line is uncommented, loading this file
// should fail because even and odd are no longer considered
// mutually recursive.
//
// _ = null;
bool odd(int n) {
cond {
n == 0 => return false;
n < 0 => return odd(-n);
else return even(n - 1);
};
}

View File

@ -1,19 +0,0 @@
(define (testfact fact)
(list (= (fact 1) 1)
(= (fact 2) 2)
(= (fact 3) 6)
(= (fact 4) 24)
(= (fact 5) 120)))
(define (testfib fib)
(list (= (fib 0) 0)
(= (fib 2) 1)
(= (fib 4) 3)
(= (fib 6) 8)))
(append (testfact fact)
(testfact fact2)
(testfact impfact)
(testfact (lambda (n) (cadr (fibfact n))))
(testfib fib)
(testfib (lambda (n) (car (fibfact n)))))

View File

@ -1,48 +0,0 @@
int fact(int n) {
if (n == 0) { return 1; }
else { return n * fact(n - 1); };
}
<int, int> divrem(int x, int y) {
(int a, int b) = (x / y, x % y);
return (a, b);
}
int impfact(int n) {
int ret = 1;
while(n > 1) {
ret = ret * n;
n = n - 1;
};
return ret;
}
int factacc(int n, int a) {
if (n == 0) { return a; }
else { return factacc(n - 1, n * a); };
}
int fact2(int n) {
return factacc(n, 1);
}
int fib_h(int n, int a, int b) {
if(n == 0) { return a; }
else { return fib_h(n - 1, b, a + b); };
}
int fib(int n) {
return fib_h(n, 0, 1);
}
<int, int> fibfact(int n) {
return (fib(n), fact(n));
}
void printFibUpTo(int n) {
int x = 0;
while(x < n) {
printLine(intToString(fib(x)));
x = x + 1;
};
}

View File

@ -1,12 +0,0 @@
type Character {
char value;
String toString();
}
class CharBox() : Character impl Character {
init char value;
String toString() { return new StrBox(value = charToStr(value)); }
export Character : value, toString;
}

View File

@ -1,78 +0,0 @@
type Integer {
int value;
Integer succ();
Integer plus(Integer y);
Integer times(Integer y);
}
type IFact {
Integer fact();
}
class Zero() : Integer impl Integer, IFact {
int value = 0;
Integer plus(Integer y) {
return y;
}
Integer times(Integer y) {
return (this : Integer);
}
Integer succ() {
return new Positive : Integer(pred = (this : Integer));
}
Integer fact() {
return new Positive : Integer(pred = (this : Integer));
}
export Integer : value, plus, times, succ;
export IFact : fact;
}
class Positive() : Integer impl Integer, IFact {
init Integer pred;
int value = pred.value + 1;
Integer plus(Integer y) {
return pred.plus(y.succ());
}
Integer times(Integer y) {
return pred.times(y).plus(y);
}
Integer succ() {
return new Positive : Integer(pred = (this : Integer));
}
Integer fact() {
return times((pred : IFact).fact());
}
export Integer : value, plus, times, succ;
export IFact : fact;
}
Integer main(){
Integer zero = new Zero : Integer();
Integer one = new Positive : Integer(pred = zero);
Integer two = new Positive : Integer(pred = one);
Integer three = one.plus(two);
Integer four = two.times(two);
Integer five = four.plus(one);
Integer six = two.plus(four);
Integer seven = one.plus(two.plus(four));
Integer eight = two.times(two);
Integer nine = three.times(three);
Integer ten = nine.plus(one);
return (five : IFact).fact();
}

View File

@ -1,33 +0,0 @@
type IFact {
int fact(int n);
}
class FactRec() : IFact impl IFact {
int fact(int n) {
return factA(n, 1);
}
int factA(int n, int a) {
if n == 0 { a; }
else { factA(n - 1, a * n); };
}
export IFact : fact;
}
class FactAcc() : IFact impl IFact {
int fact(int n) {
int ret = 1;
while (n > 1) {
ret = ret * n;
n = n - 1;
};
return ret;
}
export IFact : fact;
}
int main(){
(new FactRec:IFact()).fact(500) + (new FactAcc:IFact()).fact(500);
}

View File

@ -1,13 +0,0 @@
type Float {
float value;
String toString();
}
class FloatBox() : Float impl Float {
init float value;
String toString() { return new StrBox(value = floatToStr(value)); }
export Float : value, toString;
}

View File

@ -1,13 +0,0 @@
type Integer {
int value;
String toString();
}
class IntBox() : Integer impl Integer {
init int value;
String toString() { return new StrBox(value = intToStr(value)); }
export Integer : value, toString;
}

View File

@ -1,58 +0,0 @@
type Integer {
init();
Integer pred;
Integer succ();
Integer plus(Integer y);
Integer times(Integer y);
}
class Zero : Integer imp Integer {
init() {
my.pred = this;
}
Integer pred;
Integer plus(Integer y) {
return y;
}
Integer times(Integer y) {
return this;
}
Integer succ() {
Integer that = new Positive : Integer();
that.pred = this;
return that;
}
export Integer : pred as pred, plus as plus, times as times, succ as succ;
}
class Positive : Integer imp Integer {
init() {
my.pred = null;
}
Integer pred;
Integer plus(Integer y) {
return pred.plus(y.succ());
}
Integer times(Integer y) {
return pred.times(y).plus(y);
}
Integer succ() {
Integer that = new Positive : Integer();
that.pred = this;
return that;
}
export Integer : pred as pred, plus as plus, times as times, succ as succ;
}

View File

@ -1,62 +0,0 @@
type Integer {
int value;
Integer succ();
Integer plus(Integer y);
Integer times(Integer y);
}
class Zero() : Integer impl Integer {
int value = 0;
Integer plus(Integer y) {
return y;
}
Integer times(Integer y) {
return (this : Integer);
}
Integer succ() {
return new Positive : Integer(pred = (this : Integer));
}
export Integer : value, plus, times, succ;
}
class Positive() : Integer impl Integer {
init Integer pred;
int value = pred.value + 1;
Integer plus(Integer y) {
return pred.plus(y.succ());
}
Integer times(Integer y) {
return pred.times(y).plus(y);
}
Integer succ() {
return new Positive : Integer(pred = (this : Integer));
}
export Integer : value, plus, times, succ;
}
Integer main() {
Integer zero = new Zero : Integer();
Integer one = new Positive : Integer(pred = zero);
Integer two = new Positive : Integer(pred = one);
Integer three = one.plus(two);
Integer four = two.times(two);
Integer five = four.plus(one);
Integer six = two.plus(four);
Integer seven = one.plus(two.plus(four));
Integer eight = two.times(two);
Integer nine = three.times(three);
return nine.plus(one);
}

View File

@ -1,56 +0,0 @@
type Integer {
Integer succ();
Integer plus(Integer y);
Integer times(Integer y);
}
class Zero() : Integer impl Integer {
Integer plus(Integer y) {
return y;
}
Integer times(Integer y) {
return (this : Integer);
}
Integer succ() {
return new Positive : Integer(pred = (this : Integer));
}
export Integer : plus, times, succ;
}
class Positive() : Integer impl Integer {
init Integer pred;
Integer plus(Integer y) {
return pred.plus(y.succ());
}
Integer times(Integer y) {
return pred.times(y).plus(y);
}
Integer succ() {
return new Positive : Integer(pred = (this : Integer));
}
export Integer : plus, times, succ;
}
Integer main() {
Integer zero = new Zero : Integer();
Integer one = new Positive : Integer(pred = zero);
Integer two = new Positive : Integer(pred = one);
Integer three = one.plus(two);
Integer four = two.times(two);
Integer five = four.plus(one);
Integer six = two.plus(four);
Integer seven = one.plus(two.plus(four));
Integer eight = two.times(two);
Integer nine = three.times(three);
return nine.plus(one);
}

View File

@ -1,24 +0,0 @@
List iota(int n) {
List ret = new MTList : List();
while(n > 0) {
ret = new ConsList : List(car = new Int : IInt(value = n), cdr = ret);
n = n - 1;
};
return ret;
}
int main() {
List x = iota(100);
List y = x.map(fun(Any x) {
if(x isa IInt) {
new Int : IInt(value = (x : IInt).value * 2);
} else {
x;
};
});
(y.foldl(fun(Any x, Any i) {
if x isa IInt && i isa IInt {
new Int : IInt(value = (x : IInt).value + (i : IInt).value);
} else { i; } ;
}, new Int : IInt(value = 0)) : IInt).value;
}

View File

@ -1,3 +0,0 @@
"List" ; for List, MTList, ConsList
"struct-test" ; for Int/IInt
"List-main" ; for main

View File

@ -1,177 +0,0 @@
type List {
List addToFront(Any);
List addToEnd(Any);
Any first();
List rest();
Any atIndex(int);
Any last();
List drop(int);
List take(int);
List appendToEnd(List);
List appendToFront(List);
List reverse();
int length();
bool empty();
List map([Any] -> Any);
Any foldl([Any, Any] -> Any, Any);
Any foldr([Any, Any] -> Any, Any);
List filter([Any] -> bool);
}
class MTList() : List impl List {
List add(Any elt) {
return new ConsList(car = elt, cdr = (this : List));
}
Any no_elts(int n) {
error("The empty list has no elements!");
}
Any no_elt() {
error("The empty list has no elements!");
}
List rest() {
error("The empty list has no elements!");
}
List drop(int n) {
if n == 0 {
this : List;
} else {
error("Attempt to drop elements from an empty list!");
};
}
List take(int n) {
if n == 0 {
this : List;
} else {
error("Attempt to take elements from an empty list!");
};
}
List ret_other(List l) { return l; }
List reverse() { return (this : List); }
int length() { return 0; }
bool empty() { return true; }
List map([Any] -> Any f) { return (this : List); }
Any fold([Any, Any] -> Any f, Any i) { return i; }
List filter([Any] -> bool f) { return (this : List); }
export List : add as addToFront, add as addToEnd,
no_elt as first, rest, no_elts as atIndex,
no_elt as last, drop, take, reverse,
ret_other as appendToEnd, ret_other as appendToFront,
length, empty,
map, fold as foldl, fold as foldr, filter;
}
class ConsList() : List impl List {
init Any car;
init List cdr;
Any first() { return car; }
List rest() { return cdr; }
Any atIndex(int n) {
if n == 0 {
car;
} else {
cdr.atIndex(n - 1);
};
}
Any last() {
if cdr.empty() {
car;
} else {
cdr.last();
};
}
List drop(int n) {
if n == 0 {
this : List;
} else {
cdr.drop(n - 1);
};
}
List take(int n) {
if n == 0 {
new MTList();
} else {
new ConsList(car = car, cdr = cdr.take(n - 1));
};
}
List addToFront(Any x) {
return new ConsList(car = x, cdr = (this : List));
}
List addToEnd(Any x) {
return new ConsList(car = car, cdr = cdr.addToEnd(x));
}
List appendToFront(List other) {
if other.empty() {
this : List;
} else {
new ConsList(car = other.first(), cdr = other.drop(1));
};
}
List appendToEnd(List other) {
return new ConsList(car = car, cdr = cdr.appendToEnd(other));
}
List reverse() {
return cdr.reverse().addToEnd(car);
}
int length() { return 1 + cdr.length(); }
bool empty() { return false; }
List map([Any] -> Any f) {
return new ConsList(car = f(car), cdr = cdr.map(f));
}
Any foldl([Any, Any] -> Any f, Any i) {
return f(car, cdr.foldl(f, i));
}
Any foldr([Any, Any] -> Any f, Any i) {
return cdr.foldr(f, f(car, i));
}
List filter([Any] -> bool f) {
if f(car) {
new ConsList(car = car, cdr = cdr.filter(f));
} else {
cdr.filter(f);
};
}
export List : addToFront, addToEnd, first, rest, atIndex, last, reverse,
drop, take, appendToEnd, appendToFront, length, empty,
map, foldl, foldr, filter;
}

View File

@ -1,25 +0,0 @@
IStack main() {
IStack x = new CountedListStack : IStack();
IStack y = null;
x.push(new CharBox : Character(value = '5'));
x.push(new IntBox : Integer(value = 3));
y = x.copy();
while(!y.empty()) {
Any curr = y.pop();
if curr isa Character {
printLine("Got a character");
} else {
if curr isa Integer {
printLine("Got an integer");
} else {
printLine("Got something else");
};
};
};
x;
}

View File

@ -1,7 +0,0 @@
"List" ; For IList, MTList, and ConsList
"Character" ; For Character and CharBox
"Integer-box" ; For Integer and IntBox
"Float" ; For Float and FloatBox
"String" ; For String and StrBox
"Stack" ; For IStack, ListStack, and CountedListStack
"Stack-main" ; For the main expression

View File

@ -1,80 +0,0 @@
type IStack
{
void push (Any elt);
Any pop();
bool empty();
IStack copy();
}
class ListStack() : IStack impl IStack {
List stack = new MTList();
void push (Any elt) {
stack = new ConsList(car = elt, cdr = stack);
}
Any pop() {
if stack.empty() {
error("The stack is empty!");
} else {
Any x = stack.first();
stack = stack.drop(1);
return x;
};
}
bool empty() {
return stack.empty();
}
IStack copy() {
List tocopy = stack.reverse();
IStack newStack = new ListStack();
while(!tocopy.empty()) {
newStack.push(tocopy.first());
tocopy = tocopy.drop(1);
};
return newStack;
}
export IStack : push, pop, empty, copy;
}
type ICountedStack <: IStack
{
int numElements();
}
mixin addCount() : ICountedStack at IStack impl ICountedStack
{
int numElts = 0;
super();
void countedPush(Any elt)
{
numElts = numElts + 1;
push(elt);
}
Any countedPop()
{
Any x = pop();
numElts = numElts - 1;
return x;
}
int getSize()
{
numElts;
}
export ICountedStack :
countedPush as push,
countedPop as pop,
empty,
copy, // but this isn't a countable stack!
getSize as numElements;
}
subclass CountedListStack = addCount(ListStack);

View File

@ -1,36 +0,0 @@
type String {
str value;
void printStr();
void printLine();
Integer strToInt();
Float strToFloat();
Integer strLen();
String substr(int, int);
Character charAt(int);
}
class StrBox() : String impl String {
init str value;
void printStr() { printStr(value); }
void printLine() { printLine(value); }
Integer strToInt() { return new IntBox(value = strToInt(value)); }
Float strToFloat() { return new FloatBox(value = strToFloat(value)); }
Integer strLen() { return new IntBox(value = strLen(value)); }
String substr(int start, int end) {
return new StrBox(value = substr(value, start, end));
}
Character charAt(int i) {
return new CharBox(value = charAt(value, i));
}
export String : value, printStr, printLine, strToInt, strToFloat, strLen,
substr, charAt;
}

View File

@ -1,15 +0,0 @@
int -> int fix(<int -> int> -> int -> int f) {
T -> int -> int g = fun(T x) { f(fun(int y) { x.f x y; }); };
g (new Y(f = g));
}
struct Y : T {
init T -> int -> int f;
}
int factorialor(int -> int factorial) (int x) {
if(x == 0) 1
else x * factorial(x - 1);
}
int main(int n) { fix factorialor n; }

View File

@ -1,40 +0,0 @@
// compute the fixpoint of f
[int] -> int fix([[int] -> int] -> [int] -> int f) {
[T] -> [int] -> int g = fun(T x) {
[int] -> int h = fun (int y) { // will become: ((outT(x))(x))(y)
[T] -> [int] -> int g = outT(x);
[int] -> int i = g(x);
return i(y);
};
return f(h);
};
return g(inT(g));
}
// type T = Y of T -> int -> int
struct Y() : T {
init [T] -> [int] -> int f;
}
[T] -> [int] -> int outT(T x) { return x.f; }
T inT([T] -> [int] -> int x) { return new Y(f = x); }
// -----------------------------------------------------------------------------
[int] -> int factorialor([int] -> int factorial) {
return
fun (int x) {
if (x == 0) {
return 1;
}
else {
return x * factorial(x - 1);
};
};
}
int main(int n) {
[int] -> int factorial = fix(factorialor);
return factorial(n);
}

View File

@ -1,4 +0,0 @@
int main() {
int x = if true { 3; } else { error("I shouldn't be here!"); };
x + 4;
}

View File

@ -1,24 +0,0 @@
type t {
int x;
}
type t2 <: t {
int y;
}
type contains_t {
t x;
}
class c() : t2 impl t2 {
init int x;
init int y;
export t2 : x, y;
}
class cct() : contains_t impl contains_t {
init t2 x;
export contains_t : x;
}

View File

@ -1,12 +0,0 @@
type t {
int x;
}
class c(int x) : t impl t {
int y = x;
export t : y as x;
}
t main() {
new c:t();
}

View File

@ -1,12 +0,0 @@
int fact(int x) {
int ret = 1;
while(x > 1) {
ret = ret * x;
x = x - 1;
};
return ret;
}
int main() {
fact(5);
}

View File

@ -1,435 +0,0 @@
// -*- java -*-
/*
* General Notes:
*
* 1) we need some sort of error reporting mechanism. Full exceptions
* would be nice, but even a MzScheme-like error primitive would be
* sufficient for now.
* 2) We desperately need some sort of polymorphism -- even Java 1.4
* style would be an improvement!
* 3) What did we decide w.r.t typing _this_ again?
*/
/*
* Assumed built-in types, operations
* OCaml-style extensional equality
* null? (or, more generally, intensional equality)
* String (changed to str)
* int
* boolean (changed to bool)
*/
/*
**********************************************************************
* Infrastructure: sets, lists, etc.
**********************************************************************/
type StringList
{
bool contains(str s);
// Returns copy of this list with first occurrence of s removed.
// If no s, returns copy of this list.
StringList remove(str s);
// fold that produces a set.
StringSet setFold(StringSet initial, StringSetOp op);
bool hasDuplicates();
}
type StringSetOp
{
// invoke this closure.
StringSet run(StringSet accum, str s);
}
class EmptyStringList() : StringList impl StringList
{
bool contains(str s) { false; }
StringList remove(str s) { this : StringList; }
StringSet setFold(StringSet initial, StringSetOp op) { initial; }
bool hasDuplicates() { false; }
export StringList : contains, setFold, remove, hasDuplicates;
}
class ConsStringList(StringList rest) : StringList impl StringList
{
init str first;
StringList rest =
if rest == null {
error("ConsStringList.rest null");
} else { rest; };
bool contains(str s)
{
(s == first) || rest.contains(s);
}
StringList remove(str s)
{
if s == first { rest; }
else { new ConsStringList : StringList
(first = first,
rest = rest.remove(s)); };
}
StringSet setFold(StringSet initial, StringSetOp op)
{
rest.setFold(op.run(initial, first), op);
}
bool hasDuplicates()
{
rest.contains(first) || rest.hasDuplicates();
}
export StringList : contains, setFold, remove, hasDuplicates;
}
class UnionOp() : StringSetOp impl StringSetOp
{
StringSet run(StringSet accum, str s)
{
accum.singleUnion(s);
}
export StringSetOp : run;
}
type StringSet
{
StringSet singleUnion(str elt);
StringSet union(StringSet rhs);
StringSet subElt(str elt);
}
class StringSetCls() : StringSet impl StringSet
{
init StringList contents = new EmptyStringList : StringList();
// this showed up a bug in the parser where I wasn't adding
// the default expressions to things. This caused problems
// when relying on them (i.e. not giving a contents init arg).
// Fixed.
// How should this get translated? You have a default value
// for contents so it can't go into the init args in the header,
// but you want an additional check later (hasDuplicates()).
StringList contents =
if contents.hasDuplicates() {
error("StringList.contents must be set");
} else { contents; };
StringSet singleUnion(str elt)
{
if contents.contains(elt) { this : StringSet; }
else {
new StringSetCls : StringSet
(contents = new ConsStringList : StringList(first = elt,
rest = contents));
};
}
StringSet union(StringSet rhs)
{
contents.setFold(rhs, new UnionOp : StringSetOp());
}
StringSet subElt(str elt)
{
new StringSetCls : StringSet(contents = contents.remove(elt));
}
export StringSet : singleUnion, union, subElt;
// was export StringSetCls, typechecker caught this.
}
/*
**********************************************************************
* Values
**********************************************************************/
type Value
{
Value apply(Value arg);
}
class IntValue() : Value impl Value // was class Constant, typechecker caught this
// line 359 was the use of IntValue
{
init int n;
Value apply(Value arg) { error("cannot apply a constant"); }
export Value : apply;
}
class Closure(Ast body, Env rho) : Value impl Value
{
init str argName;
Ast body =
if body == null {
error("Closure.body null");
} else { body; };
Env rho =
if rho == null {
error("Closure.rho null");
} else { rho; }; // was else body, Typechecker caught this
Value apply(Value arg)
{
body.getValue(rho.extend(argName, arg));
// originally thought this was a bug in the interpreter,
// but it was a bug in the typechecker (did supertype
// checking on method arguments, not subtype checking). Fixed.
}
export Value : apply; // no export statement, typechecker caught this.
}
/*
**********************************************************************
* Types
**********************************************************************/
type Type
{
Type getRange(Type domain);
}
class IntType() : Type impl Type
{
Type getRange(Type domain) { error("IntType.getRange"); }
export Type : getRange;
}
class ArrowType(Type dom, Type rng) : Type impl Type
{
Type dom =
if dom == null {
error("ArrowType.dom null");
} else { dom; };
Type rng =
if rng == null {
error("ArrowType.rng null");
} else { rng; };
Type getRange(Type domain)
{
// extensional equality
if domain ==== dom { rng; }
else { error("arrowType.getRange: domain mismatch"); };
}
export Type : getRange;
}
/*
**********************************************************************
* Environments
**********************************************************************/
type Env
{
Env extend(str var, Any t);
Any lookup(str var);
}
class EmptyEnv() : Env impl Env
{
Env extend(str var, Any t)
{
new RibEnv : Env(id = var, bdg = t, rest = this : Env);
}
Any lookup(str var)
{
error("unbound id");
}
export Env : extend, lookup;
}
class RibEnv(Any bdg, Env rest) : Env impl Env
{
init str id;
Any bdg =
if bdg == null {
error("RibEnv.bdg null");
} else { bdg; };
Env rest =
if rest == null {
error("RibEnv.rest null");
} else { rest; };
Env extend(str var, Any t)
{
new RibEnv : Env(id = var, bdg = t, rest = this : Env);
}
Any lookup(str var)
{
if var == id { bdg; } else { rest.lookup(var); };
}
export Env : extend, lookup;
// was export TypeEnv, should be Env, typechecker caught this.
}
/*
**********************************************************************
* ASTS
**********************************************************************/
type Ast
{
StringSet vars();
StringSet freeVars();
Type getType(Env gamma);
Value getValue(Env rho);
}
class Constant() : Ast impl Ast
{
init int n;
StringSet vars()
{
new StringSetCls : StringSet();
}
StringSet fv()
{
vars();
}
Type getType(Env gamma)
{
new IntType : Type();
}
Value getValue(Env rho)
{
new IntValue : Value(n = n);
}
export Ast : vars, fv as freeVars, getType, getValue;
}
class Variable() : Ast impl Ast
{
init str name;
StringSet vars()
{
StringSet result = new StringSetCls : StringSet();
result.singleUnion(name);
}
StringSet fv() { vars(); }
Type getType(Env gamma)
{
gamma.lookup(name) : Type;
}
Value getValue(Env rho)
{
rho.lookup(name) : Value;
}
export Ast : vars, fv as freeVars, getType, getValue;
// last part was erroneously typed "getName" instead of "getValue",
// caught by typechecker.
}
class Lambda(Ast body, Type argType) : Ast impl Ast
{
init str argName;
Ast body =
if body == null {
error("Lambda.body null");
} else { body; };
Type argType =
if argType == null {
error("Lambda.argType null");
} else { argType; };
StringSet vars()
{
body.vars();
}
StringSet freeVars()
{
body.freeVars().subElt(argName);
// was arg (init field) instead of argName (field).
// typechecker caught this.
}
Type getType(Env gamma)
{
body.getType(gamma.extend(argName, argType));
// originally thought this was a bug in the interpreter,
// but it was a bug in the typechecker (did supertype
// checking on method arguments, not subtype checking). Fixed.
}
Value getValue(Env rho)
{
return new Closure : Value(argName = argName, body = body, rho = rho);
}
export Ast : vars, freeVars, getType, getValue;
}
class Application(Ast rator, Ast rand) : Ast impl Ast
{
Ast rator =
if rator == null {
error("Application.rator null");
} else { rator; };
Ast rand =
if rand == null {
error("Application.rand null");
} else { rand; };
StringSet vars()
{
StringSet ratorVars = rator.vars();
ratorVars.union(rand.vars());
}
StringSet fv()
{
StringSet ratorFv = rator.freeVars();
// rator.freeVars (public name) was rator.fv (private name).
// typechecker caught this (happened below also with rand)
ratorFv.union(rand.freeVars());
}
Type getType(Env gamma)
{
Type ratorType = rator.getType(gamma);
ratorType.getRange(rand.getType(gamma));
}
Value getValue(Env rho)
{
Value ratorVal = rator.getValue(rho);
ratorVal.apply(rand.getValue(rho));
// ratorVal.apply was rator.apply, which gave method not found error
// typechecker caught this.
// also, rand.getValue was rand.value. Same error.
// typechecker caught this.
}
export Ast : vars, fv as freeVars, getType, getValue;
}

View File

@ -1,465 +0,0 @@
// -*- java -*-
/*
* General Notes:
*
* 1) we need some sort of error reporting mechanism. Full exceptions
* would be nice, but even a MzScheme-like error primitive would be
* sufficient for now.
* 2) We desperately need some sort of polymorphism -- even Java 1.4
* style would be an improvement!
* 3) What did we decide w.r.t typing _this_ again?
*/
/*
* Assumed built-in types, operations
* OCaml-style extensional equality
* null? (or, more generally, intensional equality)
* String (changed to str)
* int
* boolean (changed to bool)
*/
/*
**********************************************************************
* Boxing: str -> String
**********************************************************************/
type String {
str val;
}
/*
**********************************************************************
* Infrastructure: sets, lists, etc.
**********************************************************************/
type StringList
{
bool contains(String s);
// Returns copy of this list with first occurrence of s removed.
// If no s, returns copy of this list.
StringList remove(String s);
// fold that produces a set.
StringSet setFold(StringSet initial, StringSetOp op);
bool hasDuplicates();
}
type StringSetOp
{
// invoke this closure.
StringSet run(StringSet accum, String s);
}
class EmptyStringList() : StringList impl StringList
{
bool contains(String s) { false; }
StringList remove(String s) { this : StringList; }
StringSet setFold(StringSet initial, StringSetOp op) { initial; }
bool hasDuplicates() { false; }
export StringList : contains, setFold, remove, hasDuplicates;
}
class ConsStringList(String init_first, StringList init_rest) : StringList impl StringList
{
String first =
if(init_first == null) {
error("ConsStringList.init_first null");
} else {
init_first;
};
StringList rest =
if init_rest == null {
error("ConsStringList.init_rest null");
} else { init_rest; };
bool contains(String s)
{
(s ==== first) || rest.contains(s);
}
StringList remove(String s)
{
if s ==== first {
rest;
} else {
new ConsStringList : StringList
(init_first = first,
init_rest = rest.remove(s));
};
}
StringSet setFold(StringSet initial, StringSetOp op)
{
rest.setFold(op.run(initial, first), op);
}
bool hasDuplicates()
{
rest.contains(first) || rest.hasDuplicates();
}
export StringList : contains, setFold, remove, hasDuplicates;
}
class UnionOp() : StringSetOp impl StringSetOp
{
StringSet run(StringSet accum, String s)
{
accum.singleUnion(s);
}
export StringSetOp : run;
}
type StringSet
{
StringSet singleUnion(String elt);
StringSet union(StringSet rhs);
StringSet subElt(String elt);
}
class StringSetCls() : StringSet impl StringSet
{
init StringList init_contents = new EmptyStringList : StringList();
// this showed up a bug in the parser where I wasn't adding
// the default expressions to things. This caused problems
// when relying on them (i.e. not giving a contents init arg).
// Fixed.
// How should this get translated? You have a default value
// for contents so it can't go into the init args in the header,
// but you want an additional check later (hasDuplicates()).
StringList contents =
if init_contents.hasDuplicates() {
error("StringList.contents must be set");
} else { init_contents; };
StringSet singleUnion(String elt)
{
if contents.contains(elt) {
this : StringSet;
} else {
new StringSetCls : StringSet
(init_contents = new ConsStringList : StringList(init_first = elt,
init_rest = contents));
};
}
StringSet union(StringSet rhs)
{
contents.setFold(rhs, new UnionOp : StringSetOp());
}
StringSet subElt(String elt)
{
new StringSetCls : StringSet(init_contents = contents.remove(elt));
}
export StringSet : singleUnion, union, subElt;
// was export StringSetCls, typechecker caught this.
}
/*
**********************************************************************
* Values
**********************************************************************/
type Value
{
Value apply(Value arg);
}
class IntValue() : Value impl Value // was class Constant, typechecker caught this
// line 359 was the use of IntValue
{
init int init_n;
Value apply(Value arg) { error("cannot apply a constant"); }
export Value : apply;
}
class Closure(String init_argName, Ast init_body, Env init_rho) : Value impl Value
{
String argName =
if init_argName == null {
error("Closure.argName null");
} else { init_argName; };
Ast body =
if init_body == null {
error("Closure.body null");
} else { init_body; };
Env rho =
if init_rho == null {
error("Closure.rho null") ;
} else { init_rho; }; // was else body, Typechecker caught this
Value apply(Value arg)
{
body.getValue(rho.extend(argName, arg));
// originally thought this was a bug in the interpreter,
// but it was a bug in the typechecker (did supertype
// checking on method arguments, not subtype checking). Fixed.
}
export Value : apply; // no export statement, typechecker caught this.
}
/*
**********************************************************************
* Types
**********************************************************************/
type Type
{
Type getRange(Type domain);
}
class IntType() : Type impl Type
{
Type getRange(Type domain) { error("IntType.getRange"); }
export Type : getRange;
}
class ArrowType(Type init_dom, Type init_rng) : Type impl Type
{
Type dom =
if init_dom == null {
error("ArrowType.dom null");
} else { init_dom; };
Type rng =
if init_rng == null {
error("ArrowType.rng null");
} else { init_rng; };
Type getRange(Type domain)
{
// extensional equality
if domain ==== dom { rng; }
else { error("arrowType.getRange: domain mismatch"); };
}
export Type : getRange;
}
/*
**********************************************************************
* Environments
**********************************************************************/
type Env
{
Env extend(String var, Any t);
Any lookup(String var);
}
class EmptyEnv() : Env impl Env
{
Env extend(String var, Any t)
{
new RibEnv : Env(init_id = var, init_bdg = t, init_rest = this : Env);
}
Any lookup(String var)
{
error("unbound id");
}
export Env : extend, lookup;
}
class RibEnv(String init_id, Any init_bdg, Env init_rest) : Env impl Env
{
String id =
if init_id == null {
error("RibEnv.id null");
} else { init_id; };
Any bdg =
if init_bdg == null {
error("RibEnv.bdg null");
} else { init_bdg; };
Env rest =
if init_rest == null {
error("RibEnv.rest null");
} else { init_rest; };
Env extend(String var, Any t)
{
new RibEnv : Env(init_id = var, init_bdg = t, init_rest = this : Env);
}
Any lookup(String var)
{
if var ==== id { bdg; }
else { rest.lookup(var); };
}
export Env : extend, lookup;
// was export TypeEnv, should be Env, typechecker caught this.
}
/*
**********************************************************************
* ASTS
**********************************************************************/
type Ast
{
StringSet vars();
StringSet freeVars();
Type getType(Env gamma);
Value getValue(Env rho);
}
class Constant() : Ast impl Ast
{
init int n;
StringSet vars()
{
new StringSetCls : StringSet();
}
StringSet fv()
{
vars();
}
Type getType(Env gamma)
{
new IntType : Type();
}
Value getValue(Env rho)
{
new IntValue : Value(init_n = n);
}
export Ast : vars, fv as freeVars, getType, getValue;
}
class Variable(String init_name) : Ast impl Ast
{
String name =
if init_name == null {
error("Variable.name null");
} else { init_name; };
StringSet vars()
{
StringSet result = new StringSetCls : StringSet();
result.singleUnion(name);
}
StringSet fv() { vars(); }
Type getType(Env gamma)
{
gamma.lookup(name) : Type;
}
Value getValue(Env rho)
{
rho.lookup(name) : Value;
}
export Ast : vars, fv as freeVars, getType, getValue;
// last part was erroneously typed "getName" instead of "getValue",
// caught by typechecker.
}
class Lambda(String init_arg, Ast init_body, Type init_argType) : Ast impl Ast
{
String argName =
if init_arg == null {
error("Lambda.argName null");
} else { init_arg; };
Ast body =
if init_body == null {
error("Lambda.body null");
} else { init_body; };
Type argType =
if init_argType == null {
error("Lambda.argType null");
} else { init_argType; };
StringSet vars()
{
body.vars();
}
StringSet freeVars()
{
body.freeVars().subElt(argName);
// was arg (init field) instead of argName (field).
// typechecker caught this.
}
Type getType(Env gamma)
{
body.getType(gamma.extend(argName, argType));
// originally thought this was a bug in the interpreter,
// but it was a bug in the typechecker (did supertype
// checking on method arguments, not subtype checking). Fixed.
}
Value getValue(Env rho)
{
return new Closure : Value(init_argName = argName, init_body = body, init_rho = rho);
}
export Ast : vars, freeVars, getType, getValue;
}
class Application(Ast init_rator, Ast init_rand) : Ast impl Ast
{
Ast rator =
if init_rator == null {
error("Application.rator null");
} else { init_rator; };
Ast rand =
if init_rand == null {
error("Application.rand null");
} else { init_rand; };
StringSet vars()
{
StringSet ratorVars = rator.vars();
ratorVars.union(rand.vars());
}
StringSet fv()
{
StringSet ratorFv = rator.freeVars();
// rator.freeVars (public name) was rator.fv (private name).
// typechecker caught this (happened below also with rand)
ratorFv.union(rand.freeVars());
}
Type getType(Env gamma)
{
Type ratorType = rator.getType(gamma);
ratorType.getRange(rand.getType(gamma));
}
Value getValue(Env rho)
{
Value ratorVal = rator.getValue(rho);
ratorVal.apply(rand.getValue(rho));
// ratorVal.apply was rator.apply, which gave method not found error
// typechecker caught this.
// also, rand.getValue was rand.value. Same error.
// typechecker caught this.
}
export Ast : vars, fv as freeVars, getType, getValue;
}

View File

@ -1,4 +0,0 @@
int main() {
[int, int] -> int x = fun(int x, int y) { x + y; };
x(3, 4);
}

View File

@ -1,23 +0,0 @@
type t {
void m();
}
class A():t { // no implements necessary
t state = null;
void m() {
state = this; // do we need coercions here?
}
export t : m;
}
type s <: t { }
subclass B():s extends A at t {
super();
// use of m somewhere
void m2 { m(); }
// .: the type of this is s
// .: the assignment of state = this still works
// because s is below t
export s : m2 as m;
}

View File

@ -1,35 +0,0 @@
type t {
void m();
}
class A():t { // no implements necessary
t state = null;
void m() {
state = (this : t); // do we need coercions here? -- yes!
}
export t : m;
}
type s <: t { }
type u {
void m();
}
subclass B():s extends A at t implements u {
super();
// use of m somewhere
void m2() {
m();
}
// .: the type of this is s
// .: the assignment of state = this still works
// because s is below t
export s : m;
export u : m2 as m;
}
void main() {
u x = new B:u();
x.m();
}

View File

@ -1,8 +0,0 @@
type t {
int md(int);
}
int main() {
t x = null;
x.md(3);
}

View File

@ -1,15 +0,0 @@
type t {
int md(int);
}
class c() : t impl t {
int my_md(int x) {
return this.md(x);
}
export t : my_md as md;
}
int main() {
t x = new c:t();
x.md(3);
}

View File

@ -1,26 +0,0 @@
type t {
int x;
}
type t2 <: t {
int y;
}
type contains_t {
t x(t2);
}
class c() : t2 impl t2 {
init int x;
init int y;
export t2 : x, y;
}
class cct() : contains_t impl contains_t {
t2 x(t x) {
return new c : t2 (x = x.x, y = x.x);
}
export contains_t : x;
}

View File

@ -1,31 +0,0 @@
/* should parse & type check. */
type T
{
int x;
int y;
int get_x();
}
class BaseCls() : T impl T
{
init int x;
init int y;
int get_x() { x; }
export T : x, y, get_x;
}
mixin mx() : T at T impl T with int x
{
init int z;
super(x = 3);
export T : z as x, y as y, get_x as get_x;
}
subclass DerivedCls = mx(BaseCls);
int main() {
T t = new DerivedCls : T (y = 4, z = 5);
t.get_x() + t.x + t.y; // should evaluate to 12
}

View File

@ -1,98 +0,0 @@
/* Again, should parse and type-check. */
type charList
{
charList cons(char);
bool isEmpty();
char car();
charList cdr();
}
final class MTCList() : charList impl charList {
charList cons(char x) {
return new ConsCList : charList (car = x, cdr = (this : charList));
}
bool isEmpty() { return true; }
char car() { error("There are no elements in the empty list!"); }
charList cdr() { return (this : charList); }
export charList : car, cdr, isEmpty, cons;
}
final class ConsCList() : charList impl charList {
init char car;
init charList cdr;
charList cons(char x) {
return new ConsCList : charList (car = x, cdr = (this : charList));
}
bool isEmpty() { return false; }
char car_func() { return car; }
charList cdr_func() { return cdr; }
export charList : car_func as car, cdr_func as cdr, isEmpty, cons;
}
type stack
{
char push (char elt);
char pop();
}
class listStack() : stack impl stack {
charList stack = new MTCList : charList();
char push (char elt) {
stack = stack.cons(elt);
return elt;
}
char pop() {
if stack.isEmpty() {
error("The stack is empty!");
} else {
char x = stack.car();
stack = stack.cdr();
return x;
};
}
export stack : push, pop;
}
type countedStack <: stack
{
int numElements();
}
mixin addCount() : countedStack at stack impl countedStack
{
int numElts = 0;
super();
char countedPush(char elt)
{
numElts = numElts + 1;
push(elt);
}
char countedPop()
{
char x = pop();
numElts = numElts - 1;
return x;
}
int getSize()
{
numElts;
}
export countedStack :
countedPush as push,
countedPop as pop,
getSize as numElements;
}
subclass countedListStack = addCount(listStack);
char main() {
(new countedListStack : stack()).push('5');
}

View File

@ -1,56 +0,0 @@
/* Again, should parse and typecheck, though watch out for constructor
* syntax.
*/
type Point
{
int x;
int y;
}
type ColorPoint extends Point
{
int color;
}
type MovingPoint extends Point
{
float dx;
float dy;
}
class PtClass() : Point implements Point
{
init int x;
init int y;
export Point : x as x, y as y;
}
class ColorPtClass() : ColorPoint implements Point, ColorPoint
{
/* We should add syntactic sugar for init fields. */
init int x;
init int y;
init int color;
export Point : x as x, y as y;
export ColorPoint : x as x, y as y, color as color;
}
mixin makeMovingPoint() : MovingPoint at Point impl MovingPoint
{
init float dx;
init float dy;
super();
export MovingPoint : x, y, dx, dy;
}
subclass MvPtCls = makeMovingPoint(PtClass);
subclass MvClrPtCls = makeMovingPoint(ColorPtClass);
MovingPoint main() {
new MvClrPtCls : MovingPoint(x = 3, y = 4, color = 42, dx = 0.4, dy = -3.2);
}

View File

@ -1,17 +0,0 @@
type t1 {
bool x();
}
class c() : t1 impl t1 {
bool x() { return true; }
export t1 : x;
}
bool main() {
t1 x = new c:t1();
if (1 < 3) && (2.0 >= 1.5) {
!x.x();
} else {
error("How'd I get here?");
};
}

View File

@ -1,12 +0,0 @@
type t {
int x;
}
class c(int x) : t impl t {
int y = x;
export t : y as x;
}
t main() {
new c:t(x = 5);
}

View File

@ -1,38 +0,0 @@
/* This should parse and type-check correctly.
Note the field initialization in unitSquare: the declaration of the
field x should shadow the init arg x from that point forward, but
of course the RHS of x's declaration should refer to the init arg.
*/
type shape
{
int x;
int y;
int area();
}
type square extends shape
{
int length;
}
class unitSquare() : shape impl shape, square
{
init int x;
init int y;
int x = x;
int y = y;
int size = 1;
int area() { size * size; }
export shape : x as x,
y as y,
area as area;
export square : x as x,
y as y,
area as area,
size as length;
}

View File

@ -1,4 +0,0 @@
float main() {
if ("foo" + "bar" == "foobar") { 1.3 + 5.7; }
else { error("Oops!"); }
}

View File

@ -1,3 +0,0 @@
struct Int() : IInt {
init int value;
}

View File

@ -1,11 +0,0 @@
type t {}
class c() : t { init int x; export t; }
mixin mx() : t at t with int x, int y {
init int z;
super(x = 1, y = 2);
export t;
}
subclass c2 = mx(c); // should fail thanks to y = 2 above.

View File

@ -1,7 +0,0 @@
type t {}
final class c() : t { init int x; export t; }
mixin mx() : t at t with int x { init int z; super(x = 1); export t; }
subclass c2 = mx(c); // should fail because c is final

View File

@ -1,30 +0,0 @@
type t1 {
int x;
int y;
}
type t2 <: t1 {
int add();
}
class c1() : t1 implements t1 {
init int x;
init int y;
export t1 : x, y;
}
subclass c2() : t2 extends c1 at t1 implements t2 with int x, int y {
init int x;
init int y;
super(x = x, y = y);
int add() { return x + y; }
export t2: x, y, add;
}
int main() {
new c2:t2(x = 4, y = 6).add();
}

View File

@ -1,13 +0,0 @@
type t1 {
int x();
}
class c() : t1 impl t1 {
int x() { return 7; }
export t1 : x;
}
int main() {
t1 x = new c:t1();
-x.x();
}

View File

@ -1,15 +0,0 @@
(append (map interface? (list MovingPoint<%>
Point3D<%>
Point<%>
ColorPoint<%>
Color<%>))
(map class? (list ColorC%
Point3DC%
ColorPointC%
ColorMovingPointC%
MovingColorPointC%
PointC%
MovingPointC%))
(map mixin? (list makeMobile-mixin
addColor-mixin
$Point3DC-mixin)))

View File

@ -1,36 +0,0 @@
struct PointC(int x, int y) : Point { }
struct ColorC(int r, int g, int b) : Color { }
// Make extends clause look more like the first part of a class/struct,
// where the "with" args come in the same place as the init slots normally.
struct Point3DC(int z) : Point3D extends PointC() : Point { super(); }
type ColorPoint <: Point { Color c; }
type MovingPoint <: Point { void movePoint(int, int); }
// Make mixins look more like functions for classes to classes by
// making their "type" look more like the following:
//
// <input class type>(<with args>) -> <output class type>
mixin addColor(Color c) : Point() -> ColorPoint impl ColorPoint {
super();
export ColorPoint : x, y, c;
}
mixin makeMobile() : Point() -> MovingPoint impl MovingPoint {
super();
void movePoint(int dx, int dy) {
x = x + dx;
y = y + dy;
}
export MovingPoint : x, y, movePoint;
}
class ColorPointC = addColor(PointC);
class MovingPointC = makeMobile(PointC);
// only useable as a MovingPoint
class MovingColorPointC = makeMobile(ColorPointC);
// only usable as a ColorPoint
class ColorMovingPointC = addColor(MovingPointC);

View File

@ -1,3 +0,0 @@
(append (map interface? (list Color<%> Posn<%> ColorPosn<%>))
(map class? (list PosnC% ColorC% ColorPosnC%))
(map mixin? (list $ColorPosnC-mixin)))

View File

@ -1,5 +0,0 @@
struct PosnC(int x, int y) : Posn { }
struct ColorC(int r, int g, int b) : Color { }
struct ColorPosnC(Color c) : ColorPosn extends PosnC() : Posn { super(); }

View File

@ -1,5 +0,0 @@
(list (interface? T<%>)
(class? C%)
(equal? (f 'dummy) '(dummy dummy))
(= (send (new C%) T<%>-x-get '()) 3)
(= (send (new C%) T<%>-y-get '()) 3))

View File

@ -1,6 +0,0 @@
<int, int> f(int x) { return (x, x); }
struct C() : T {
int x = 3;
int y = { (int x, int y) = f(x); x; };
}

View File

@ -1,13 +0,0 @@
type t1 {
int x;
}
type t2 {
string x;
int m(int);
}
type t3 <: t1, t2 {
int y;
int m2(int, int);
}

View File

@ -1 +0,0 @@
(map interface? (list t1<%> t2<%> t3<%>))

View File

@ -1,12 +0,0 @@
type t1 {
int x;
}
type t2 {
int m(int);
}
type t3 <: t1, t2 {
int y;
int m2(int, int);
}

View File

@ -1,75 +0,0 @@
(module format mzscheme
(require (lib "contract.ss")
(lib "list.ss")
(lib "class.ss")
(lib "plt-match.ss")
(only "base.ss" null%)
"ast.ss"
)
(provide/contract
[honu-value->string (any/c . -> . string?)]
[honu-type->string (ast:type? . -> . string?)]
)
(define (string-append-delimited pre mid post strings)
(string-append
pre
(if (null? strings)
""
(foldl (lambda (str prefix)
(string-append prefix mid str))
(car strings)
(cdr strings)))
post))
(define (honu-value->string value)
(cond
[(number? value) (format "~a" value)]
[(char? value) (format "'~a'" value)]
[(string? value) (format "~s" value)]
[(boolean? value) (if value "true" "false")]
[(procedure? value) "procedure"]
[(null? value) "()"]
[(list? value) ; Always non-empty
(honu-tuple->string value)]
[(is-a? value null%) "null"]
[(object? value) ; Always non-null
(honu-object->string value)]
[else (error 'honu-value->string "Unknown value ~s" value)]))
(define (honu-tuple->string tuple)
(string-append-delimited "(" ", " ")" (map honu-value->string tuple)))
(define (honu-object->string value)
(send value format-class-name))
(define (honu-type->string t)
(match t
[(struct ast:type:top (_))
"(top type / any value)"]
[(struct ast:type:bot (_))
"(bottom type / no value)"]
[(struct ast:type:primitive (_ name))
(symbol->string name)]
[(struct ast:type:tuple (_ args))
(string-append-delimited "tuple(" ", " ")" (map honu-type->string args))]
[(struct ast:type:partial/tuple (_ slot type))
(format "tuple of size >= ~a where the type in position ~a is ~a"
slot slot (honu-type->string type))]
[(struct ast:type:function (_ arg ret))
(if (ast:type:function? arg)
(string-append "(" (honu-type->string arg) ") -> " (honu-type->string ret))
(string-append (honu-type->string arg) " -> " (honu-type->string ret)))]
[(struct ast:type:method (_ disp arg ret))
(string-append "[" (honu-type->string disp) "] "
(honu-type->string arg) " -> " (honu-type->string ret))]
[(struct ast:type:object:iface (_ name))
(symbol->string (syntax-e name))]
[(struct ast:type:object:any (_))
"Any"]
[(struct ast:type:object:null (_))
"null"]))
)

View File

@ -1,4 +0,0 @@
(module honu-context (lib "base.ss" "honu")
(provide honu-compile-context)
(define honu-compile-context #'here))

View File

@ -1,20 +0,0 @@
(module honu-tests mzscheme
(require (lib "contract.ss")
(planet "test.ss" ("schematics" "schemeunit.plt" 1 1))
"private/tests/typechecker-tests.ss"
"private/tests/program-tests.ss"
)
(provide/contract [honu-tests test-suite?])
;; honu-tests : TestSuite
;; Honu Test Suite
(define honu-tests
(make-test-suite
"Honu"
program-tests
typechecker-tests
))
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 B

View File

@ -1,5 +0,0 @@
(module info (lib "infotab.ss" "setup")
(define name "Honu")
(define doc.txt "doc.txt")
(define tools (list (list "tool.ss")))
(define tool-icons '(("honu.png" "honu"))))

View File

@ -1,11 +0,0 @@
(module parameters mzscheme
(provide (all-defined))
(define current-compile-context (make-parameter #f))
;; tenv and lenv, respectively
(define current-type-environment (make-parameter #f))
(define current-lexical-environment (make-parameter #f))
)

View File

@ -1,276 +0,0 @@
(module lex mzscheme
(require (lib "lex.ss" "parser-tools")
(prefix : (lib "lex-sre.ss" "parser-tools"))
"../readerr.ss")
(define-lex-abbrevs
[lex:letter (:or (:/ #\a #\z) (:/ #\A #\Z))]
[lex:digit (:/ #\0 #\9)]
[lex:whitespace (:or #\newline #\return #\tab #\space #\vtab)]
[lex:keyword (:or "type" "interface" "class" "mixin" "struct" "extends" "final"
"impl" "implements" "init" "export" "as" "at" "with" "fun"
"this" "my" "isa" "int" "bool" "string" "float" "char" "Any"
"while" "if" "cond" "else" "new" "super" "cast" "return")]
[lex:grouping (:or "{" "}" "[" "]" "(" ")")]
[lex:separator (:or "," ":" ";" "=" "." "<:" "->" "=>" "@" "_")]
[lex:operator (:or "!" "||" "&&" "!=" "==" "<" "<=" ">" ">=" "+" "-" "*" "/" "%" "====")]
[lex:selector (:: "#" (:+ lex:digit))]
[lex:string (:: #\" ;; A quoted string starts with a "
(:* (:or (:~ #\\ #\") ;; and has things in it which are
(:: #\\ any-char))) ;; not "s (but \" is okay)
#\")] ;; and ends with a ".
[lex:character (:: #\' any-char #\')]
[lex:ident (:: (:or lex:letter) (:* (:or #\_ lex:letter lex:digit)))]
[lex:integer (:: (:? #\-) (:+ lex:digit))]
[lex:float (:: (:? #\-) (:: (:+ lex:digit) #\. (:+ lex:digit)))]
[lex:line-comment (:: "//" (:* (:~ #\newline)))])
(provide EOF for-prec lex-errors keywords separators operators val-tokens)
(define-tokens EOF
(EOF))
(define-empty-tokens for-prec
(UMINUS))
(define-tokens lex-errors
(UNPARSEABLE))
(define-tokens keywords
(type interface class mixin struct
extends final impl implements
init export as at with
this my null isa
int bool string float char Any void
if cond else true false while fun
new super cast return))
(define-tokens separators
(O_CURLY C_CURLY O_BRACE C_BRACE O_PAREN C_PAREN COMMA COLON SEMI_COLON BINDS DOT SUBTYPE ARROW THICK_ARROW AT USCORE))
(define-tokens operators
(NOT OR AND NEQ EQUALS LT LE GT GE PLUS MINUS TIMES DIV MOD CLS_EQ))
(define-tokens val-tokens
(character floatnum string-lit integer id selector))
(define stx-for-original-property (read-syntax #f (open-input-string "original")))
(provide create-src-stx)
(define (create-src-stx val source-name start-pos end-pos)
(datum->syntax-object #f val
(list
source-name
(position-line start-pos)
(position-col start-pos)
(position-offset start-pos)
(- (position-offset end-pos)
(position-offset start-pos)))
stx-for-original-property))
(define-syntax (token stx)
(syntax-case stx ()
[(_ name val)
(identifier? (syntax name))
(let ([name (syntax name)])
(with-syntax ([token-name (datum->syntax-object
name
(string->symbol
(format "token-~a" (syntax-e name))))]
[source-name (datum->syntax-object name 'source-name)]
[start-pos (datum->syntax-object name 'start-pos)]
[end-pos (datum->syntax-object name 'end-pos)])
(syntax
(token-name
(create-src-stx val source-name start-pos end-pos)))))]))
(define-syntax (ttoken stx)
(syntax-case stx ()
[(_ name)
(identifier? (syntax name))
(syntax (token name 'name))]))
(provide generate-honu-lexer)
(define (generate-honu-lexer source-name)
(define honu-lexer
(lexer-src-pos
;; can we just use lex:keyword somehow?
["type" (ttoken type)]
["interface" (ttoken interface)]
["class" (ttoken class)]
["mixin" (ttoken mixin)]
["struct" (ttoken struct)]
["extends" (ttoken extends)]
["final" (ttoken final)]
["impl" (ttoken impl)]
["implements" (ttoken implements)]
["init" (ttoken init)]
["export" (ttoken export)]
["as" (ttoken as)]
["at" (ttoken at)]
["with" (ttoken with)]
["fun" (ttoken fun)]
["this" (ttoken this)]
["my" (ttoken my)]
["null" (ttoken null)]
["isa" (ttoken isa)]
["int" (ttoken int)]
["bool" (ttoken bool)]
["string" (ttoken string)]
["float" (ttoken float)]
["char" (ttoken char)]
["Any" (ttoken Any)]
["void" (ttoken void)]
["while" (ttoken while)]
["if" (ttoken if)]
["cond" (ttoken cond)]
["else" (ttoken else)]
["new" (ttoken new)]
["super" (ttoken super)]
["cast" (ttoken cast)]
["return" (ttoken return)]
["true" (token true #t)]
["false" (token false #f)]
["{" (ttoken O_CURLY)]
["}" (ttoken C_CURLY)]
["[" (ttoken O_BRACE)]
["]" (ttoken C_BRACE)]
["(" (ttoken O_PAREN)]
[")" (ttoken C_PAREN)]
["," (ttoken COMMA)]
[":" (ttoken COLON)]
[";" (ttoken SEMI_COLON)]
["->" (ttoken ARROW)]
["=>" (ttoken THICK_ARROW)]
["@" (ttoken AT)]
["_" (token USCORE '_)]
["=" (token BINDS 'binds)]
["!=" (token NEQ 'neq)]
["==" (token EQUALS 'equal)]
["====" (token CLS_EQ 'cls_eq)]
["!" (token NOT 'not)]
["&&" (token AND 'and)]
["||" (token OR 'or)]
["<" (token LT 'lt)]
["<=" (token LE 'le)]
[">" (token GT 'gt)]
[">=" (token GE 'ge)]
["+" (token PLUS 'plus)]
["-" (token MINUS 'minus)]
["*" (token TIMES 'times)]
["/" (token DIV 'div)]
["%" (token MOD 'mod)]
["." (token DOT 'dot)]
["<:" (token SUBTYPE 'subtype)]
[lex:selector
(token selector (string->number (substring lexeme 1 (string-length lexeme))))]
[lex:ident
(token id (string->symbol lexeme))]
[lex:integer
(token integer (string->number lexeme))]
[lex:float
(token floatnum (string->number lexeme))]
[lex:character
(token character (string-ref lexeme 1))]
[lex:string
(token string-lit (substring lexeme 1 (- (string-length lexeme) 1)))]
[lex:line-comment
(return-without-pos (honu-lexer input-port))]
[(:: #\/ #\*)
(begin (comment-lexer source-name start-pos input-port) ;; Get the rest of the comment...
(return-without-pos (honu-lexer input-port)))] ;; then get the next token.
[(:+ lex:whitespace)
(return-without-pos (honu-lexer input-port))]
[(eof)
(ttoken EOF)]
[any-char (token UNPARSEABLE (string->symbol lexeme))]))
honu-lexer)
(define comment-lexer
(lambda (source-name first-pos port)
(letrec ([lxr (lexer-src-pos
[(:: #\/ #\*)
(begin (lxr input-port) ;; once for the nested comment
(return-without-pos (lxr input-port)))] ;; now finish out the current one
[(:: #\* #\/)
#f] ;; This will get ignored by the call to comment-lexer (whether nested or no)
[(eof)
(raise-read-error-with-stx
"Unexpected end of file while inside block comment."
(create-src-stx eof source-name first-pos end-pos))]
[(:~)
(return-without-pos (lxr input-port))])])
(lxr port))))
(define (syn-val lex a b c d)
(values lex a b (position-offset c) (position-offset d)))
(define get-block-comment
(lexer
[(:: #\/ #\*)
(begin (get-block-comment input-port) ;; once for the nested comment
(get-block-comment input-port))] ;; now finish out the current one
[(:: #\* #\/)
end-pos] ;; This will get ignored by the call to comment-lexer (whether nested or no)
[(eof)
end-pos]
[(:~)
(get-block-comment input-port)]))
(define (colorize-string my-start-pos)
(define lxr
(lexer
[#\" (syn-val "" 'string #f my-start-pos end-pos)]
[(eof) (syn-val "" 'error #f my-start-pos end-pos)]
[(:: #\\ #\") (lxr input-port)]
[any-char (lxr input-port)]))
lxr)
(provide get-syntax-token)
(define get-syntax-token
(lexer
[lex:keyword
(syn-val lexeme 'keyword #f start-pos end-pos)]
[lex:operator
(syn-val lexeme 'keyword #f start-pos end-pos)]
[lex:selector
(syn-val lexeme 'keyword #f start-pos end-pos)]
[lex:separator
(syn-val lexeme 'default #f start-pos end-pos)]
[lex:grouping
(syn-val lexeme 'parenthesis (string->symbol lexeme) start-pos end-pos)]
[lex:ident
(syn-val lexeme 'identifier #f start-pos end-pos)]
[(:or "true" "false" "null")
(syn-val lexeme 'literal #f start-pos end-pos)]
[lex:integer
(syn-val lexeme 'literal #f start-pos end-pos)]
[lex:float
(syn-val lexeme 'literal #f start-pos end-pos)]
[lex:character
(syn-val lexeme 'literal #f start-pos end-pos)]
[#\"
((colorize-string start-pos) input-port)]
[(:+ lex:whitespace)
(syn-val lexeme 'whitespace #f start-pos end-pos)]
[lex:line-comment
(syn-val lexeme 'comment #f start-pos end-pos)]
[(:: #\/ #\*)
(syn-val lexeme 'comment #f start-pos (get-block-comment input-port))]
[(eof)
(syn-val lexeme 'eof #f start-pos end-pos)]
[any-char
(syn-val lexeme 'error #f start-pos end-pos)]))
)

View File

@ -1,673 +0,0 @@
(module parse mzscheme
(require (lib "yacc.ss" "parser-tools")
"lex.ss"
"../readerr.ss"
"../ast.ss"
"../private/tools/general.ss"
"../private/typechecker/type-utils.ss")
(define (generate-honu-parser source-name)
(define honu-parser
(parser
(start <program> <interact>)
(end EOF)
(src-pos)
;; (debug "honu.debug")
;; (yacc-output "honu.yacc")
;; Since we have things that can look like x.y.z.w(...), we need to
;; actually specify a precedence for DOT. There are 3 shift/reduce
;; conflicts for it, so if that warning is seen, it can be safely
;; ignored. I don't want to turn off the warnings yet in case this
;; number increases, which means that I've added additional
;; conflicts.
(precs (right ARROW) ;; for types
(nonassoc return)
(left else) ;; for expressions
(left BINDS)
(left OR)
(left AND)
(left NEQ EQUALS)
(nonassoc CLS_EQ)
(nonassoc LT LE GT GE)
(left PLUS MINUS)
(left TIMES DIV MOD)
(nonassoc NOT UMINUS) ;; unary operators
(right COLON isa)
(nonassoc selector)
(left O_PAREN) ;; this gives application a precedence
(left DOT))
(tokens keywords separators operators val-tokens lex-errors EOF for-prec)
(error (lambda (a b stx start end)
(raise-read-error-with-stx
(format "parse error near ~a" (syntax-e stx))
stx)))
(grammar
(<program>
[(<defns>)
$1])
(<defns>
[(<defn> <defns>)
(if (ast? $1)
(cons $1 $2)
(append $1 $2))]
[()
(list)])
(<defn>
[(<function-defn>)
$1]
[(<iface-defn>)
$1]
[(<class-defn>)
$1]
[(<struct-defn>)
$1]
[(<mixin-defn>)
$1]
[(<binding-defn>)
$1])
(<binding-defn>
[(<bind> BINDS <expr> SEMI_COLON)
(make-ast:defn:binding
(create-src-stx 'ast:defn:binding source-name $1-start-pos $4-end-pos)
(list (ast:formal-name $1)) (list (ast:formal-type $1)) $3)]
[(O_PAREN <binds-cd> C_PAREN BINDS <expr> SEMI_COLON)
(let-values ([(names types) (map-two-values (lambda (f)
(values (ast:formal-name f)
(ast:formal-type f)))
$2)])
(make-ast:defn:binding
(create-src-stx 'ast:defn:binding source-name $1-start-pos $6-end-pos)
names types $5))])
(<binds-cd>
[(<bind> COMMA <binds-cd>)
(cons $1 $3)]
[(<bind>)
(list $1)])
(<bind>
[(<any-type> id)
(make-ast:formal
(create-src-stx 'ast:formal source-name $1-start-pos $2-end-pos)
$2 $1)]
[(USCORE)
(make-ast:formal
(create-src-stx 'ast:formal source-name $1-start-pos $1-end-pos)
#f (make-top-type $1))])
(<function-defn>
[(<any-type> id O_PAREN <args> C_PAREN <block>)
(make-ast:defn:function
(create-src-stx 'ast:defn:function source-name $1-start-pos $6-end-pos)
$2 $1 $4 $6)])
;; Type definitions and needed parts
(<iface-defn>
[(<iface-tag> id <ext-clause> O_CURLY <fmdecs> C_CURLY)
(make-ast:defn:iface
(create-src-stx 'ast:defn:iface source-name $1-start-pos $6-end-pos)
$2 $3 $5)])
(<iface-tag>
[(type) (void)]
[(interface) (void)])
(<type-id>
[(id)
(make-iface-type $1 $1)]
[(Any)
(make-any-type $1)])
(<any-type>
[(<type-id>)
$1]
[(void)
(make-void-type $1)]
[(int)
(make-int-type $1)]
[(bool)
(make-bool-type $1)]
[(float)
(make-float-type $1)]
[(char)
(make-char-type $1)]
[(string)
(make-string-type $1)]
[(<tup-type>)
$1]
[(<any-type> ARROW <any-type>)
(make-func-type
(create-src-stx 'honu:func-type source-name $1-start-pos $3-end-pos)
$1 $3)])
(<tup-type>
[(LT GT)
(make-tuple-type
(create-src-stx 'ast:type:tuple source-name $1-start-pos $2-end-pos)
(list))]
[(LT <any-type+> GT)
(if (null? (cdr $2))
(car $2)
(make-tuple-type
(create-src-stx 'ast:type:tuple source-name $1-start-pos $3-end-pos)
$2))])
(<any-type+>
[(<any-type>)
(list $1)]
[(<any-type> COMMA <any-type+>)
(cons $1 $3)])
(<ext-clause>
[(extends <type-ids+>)
$2]
[(SUBTYPE <type-ids+>)
$2]
[()
'()])
(<type-ids+>
[(<type-id> COMMA <type-ids+>)
(cons $1 $3)]
[(<type-id>)
(list $1)])
(<args>
[(<args-cd>)
$1]
[()
(list)])
(<args-cd>
[(<arg> COMMA <args-cd>)
(cons $1 $3)]
[(<arg>)
(list $1)])
(<arg>
[(<any-type> id)
(make-ast:formal
(create-src-stx 'ast:formal source-name $1-start-pos $2-end-pos)
$2 $1)])
(<fmdecs>
[(<fdec> <fmdecs>)
(cons $1 $2)]
[(<mdec> <fmdecs>)
(cons $1 $2)]
[()
(list)])
(<fdec>
[(<any-type> id SEMI_COLON)
(make-ast:iface/member:field
(create-src-stx 'ast:iface/member:field source-name $1-start-pos $3-end-pos)
$2 $1)])
(<mdec>
[(<any-type> id O_PAREN <mdec-args> C_PAREN SEMI_COLON)
(make-ast:iface/member:method
(create-src-stx 'ast:iface/member:method source-name $1-start-pos $6-end-pos)
$2 $1 $4)])
(<mdec-args>
[(<mdec-args-cd>)
$1]
[()
(list)])
(<mdec-args-cd>
[(<mdec-arg> COMMA <mdec-args-cd>)
(cons $1 $3)]
[(<mdec-arg>)
(list $1)])
(<mdec-arg>
[(<any-type>)
$1]
[(<any-type> id)
$1])
(<struct-defn>
[(struct id <init-slots> COLON <type-id> <imp-clause> O_CURLY <fmidefns> <exports> C_CURLY)
(make-ast:defn:structure
(create-src-stx 'ast:defn:structure source-name $1-start-pos $10-end-pos)
$2 $5 #f $6 $3 $8 $9)]
[(final struct id <init-slots> COLON <type-id> <imp-clause> O_CURLY <fmidefns> <exports> C_CURLY)
(make-ast:defn:structure
(create-src-stx 'ast:defn:structure source-name $1-start-pos $11-end-pos)
$3 $6 #t $7 $4 $9 $10)]
[(struct id <init-slots> COLON <type-id> extends id <init-slots> COLON <type-id> <imp-clause>
O_CURLY <fmidefns> <supernew> <fmidefns> <exports> C_CURLY)
(make-ast:defn:substructure
(create-src-stx 'ast:defn:substructure source-name $1-start-pos $17-end-pos)
$2 $5 $7 $10 #f $11 $3 $8 $14 $13 $15 $16)]
[(final struct id <init-slots> COLON <type-id> extends id <init-slots> COLON <type-id> <imp-clause>
O_CURLY <fmidefns> <supernew> <fmidefns> <exports> C_CURLY)
(make-ast:defn:substructure
(create-src-stx 'ast:defn:substructure source-name $1-start-pos $18-end-pos)
$3 $6 $8 $11 #t $12 $4 $9 $15 $14 $16 $17)])
;; Class and subclass definitions and needed parts
(<class-defn>
[(class id <init-slots> COLON <type-id> <imp-clause> O_CURLY <fmidefns> <exports> C_CURLY)
(make-ast:defn:class
(create-src-stx 'ast:defn:class source-name $1-start-pos $10-end-pos)
$2 $5 #f $6 $3 $8 $9)]
[(final class id <init-slots> COLON <type-id> <imp-clause> O_CURLY <fmidefns> <exports> C_CURLY)
(make-ast:defn:class
(create-src-stx 'ast:defn:class source-name $1-start-pos $11-end-pos)
$3 $6 #t $7 $3 $9 $10)]
[(class id BINDS id O_PAREN id C_PAREN SEMI_COLON)
(make-ast:defn:subclass
(create-src-stx 'ast:defn:subclass source-name $1-start-pos $8-end-pos)
$2 $6 $4)]
[(class id <init-slots> COLON <type-id> extends id <init-slots> COLON <type-id> <imp-clause>
O_CURLY <fmidefns> <supernew> <fmidefns> <exports> C_CURLY)
(let ([mixin-name (datum->syntax-object $2 (string->symbol (string-append "$" (symbol->string (syntax-e $2)))) $2)]
[subclass-stx (create-src-stx 'ast:defn:subclass source-name $1-start-pos $17-end-pos)])
(list (make-ast:defn:mixin subclass-stx mixin-name $5 $10 #f $11 $3 $8 $14 $13 $15 $16)
(make-ast:defn:subclass subclass-stx $2 $7 mixin-name)))]
[(final class id <init-slots> COLON <type-id> extends id <init-slots> COLON <type-id> <imp-clause>
O_CURLY <fmidefns> <supernew> <fmidefns> <exports> C_CURLY)
(let ([mixin-name (datum->syntax-object $3 (string->symbol (string-append "$" (symbol->string (syntax-e $3)))))]
[subclass-stx (create-src-stx 'ast:defn:subclass source-name $1-start-pos $18-end-pos)])
(list (make-ast:defn:mixin subclass-stx mixin-name $6 $10 #t $12 $4 $9 $15 $14 $16 $17)
(make-ast:defn:subclass subclass-stx $3 $8 mixin-name)))])
(<imp-clause>
[(impl <type-ids+>)
$2]
[(implements <type-ids+>)
$2]
[()
'()])
(<init-slots>
[(O_PAREN <args> C_PAREN)
$2])
(<at-clause>
[(at <type-id>)
$2]
[(AT <type-id>)
$2])
(<fmidefns>
[(<fdefn> <fmidefns>)
(cons $1 $2)]
[(<mdefn> <fmidefns>)
(cons $1 $2)]
[(<initdefn> <fmidefns>)
(cons $1 $2)]
[()
(list)])
(<fdefn>
[(<any-type> id BINDS <expr> SEMI_COLON)
(make-ast:class/member:field
(create-src-stx 'ast:class/member:field source-name $1-start-pos $5-end-pos)
$2 $1 $4)])
(<mdefn>
[(<any-type> id O_PAREN <args> C_PAREN <block>)
(make-ast:class/member:method
(create-src-stx 'ast:class/member:method source-name $1-start-pos $6-end-pos)
$2 $1 $4 $6)])
(<initdefn>
[(init <any-type> id SEMI_COLON)
(make-ast:class/member:field/formal
(create-src-stx 'ast:class/member:field/formal source-name $1-start-pos $4-end-pos)
$3 $2 #f)]
[(init <any-type> id BINDS <expr> SEMI_COLON)
(make-ast:class/member:field/formal
(create-src-stx 'ast:class/member:field/formal source-name $1-start-pos $4-end-pos)
$3 $2 $5)])
(<exports>
[(<expdefn> <exports>)
(cons $1 $2)]
[()
(list)])
(<expdefn>
[(export <type-id> COLON <expdecs> SEMI_COLON)
(make-ast:export
(create-src-stx 'ast:export source-name $1-start-pos $5-end-pos)
$2 $4)]
[(export <type-id> SEMI_COLON)
(make-ast:export
(create-src-stx 'ast:export source-name $1-start-pos $3-end-pos)
$2 (list))])
(<expdecs>
[(<expdec> COMMA <expdecs>)
(cons $1 $3)]
[(<expdec>)
(list $1)])
(<expdec>
[(id as id)
(make-ast:export/member
(create-src-stx 'ast:export/member source-name $1-start-pos $3-end-pos)
$1 $3)]
[(id)
(make-ast:export/member
(create-src-stx 'ast:export/member source-name $1-start-pos $1-end-pos)
$1 $1)])
;; Mixin definitions
(<mixin-defn>
[(mixin id <init-slots> COLON <type-id> <init-slots> ARROW <type-id> <imp-clause>
O_CURLY <fmidefns> <supernew> <fmidefns> <exports> C_CURLY)
(make-ast:defn:mixin
(create-src-stx 'ast:defn:mixin source-name $1-start-pos $15-end-pos)
$2 $8 $5 #f $9 $3 $6 $12 $11 $13 $14)]
[(final mixin id <init-slots> COLON <type-id> <init-slots> ARROW <type-id> <imp-clause>
O_CURLY <fmidefns> <supernew> <fmidefns> <exports> C_CURLY)
(make-ast:defn:mixin
(create-src-stx 'ast:defn:mixin source-name $1-start-pos $16-end-pos)
$3 $9 $6 #t $10 $4 $7 $13 $12 $14 $15)])
(<with-clause>
[(with <args-cd>)
$2]
[()
(list)])
(<supernew>
[(super O_PAREN <newargs> C_PAREN SEMI_COLON)
(make-ast:super-new
(create-src-stx 'ast:super-new source-name $1-start-pos $4-end-pos)
$3)])
(<newargs>
[(<newargs-cd>)
$1]
[()
(list)])
(<newargs-cd>
[(<newarg> COMMA <newargs-cd>)
(cons $1 $3)]
[(<newarg>)
(list $1)])
(<newarg>
[(id BINDS <expr>)
(make-ast:named/arg
(create-src-stx 'ast:named/arg source-name $1-start-pos $3-end-pos)
$1 $3)])
;; Expressions
(<block>
[(O_CURLY <block-stmts*> C_CURLY)
(if $2
$2
(raise-read-error-with-stx
"Blocks must have at least one expression"
(create-src-stx 'honu:block source-name $1-start-pos $3-end-pos)))])
(<block-stmts*>
[(<expr> SEMI_COLON <block-stmts*>)
(if $3
(make-ast:expr:sequence
(create-src-stx 'ast:expr:sequence source-name $1-start-pos $3-end-pos)
(list $1) $3)
$1)]
[(<binding> <block-stmts*>)
(if $2
(make-ast:expr:let
(create-src-stx 'ast:expr:let source-name $1-start-pos $2-end-pos)
(list $1) $2)
(raise-read-error-with-stx
"Block must end with an expression"
(create-src-stx 'honu:block source-name $1-start-pos $1-end-pos)))]
[()
#f])
(<expr>
;; unary operators
[(selector <expr>)
(make-ast:expr:tuple/select
(create-src-stx 'ast:expr:tuple/select source-name $1-start-pos $2-end-pos)
(syntax-e $1) $2)]
[(MINUS <expr>)
(prec UMINUS)
(make-ast:expr:unary/op
(create-src-stx 'ast:expr:unary/op source-name $1-start-pos $2-end-pos)
'minus $1 #f $2)]
[(NOT <expr>)
(make-ast:expr:unary/op
(create-src-stx 'ast:expr:unary/op source-name $1-start-pos $2-end-pos)
'not $1 #f $2)]
;; binary operators
[(<expr> OR <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'or $2 #f $1 $3)]
[(<expr> AND <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'and $2 #f $1 $3)]
[(<expr> CLS_EQ <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'clseq $2 #f $1 $3)]
[(<expr> NEQ <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'neq $2 #f $1 $3)]
[(<expr> EQUALS <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'equal $2 #f $1 $3)]
[(<expr> LT <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'lt $2 #f $1 $3)]
[(<expr> LE <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'le $2 #f $1 $3)]
[(<expr> GT <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'gt $2 #f $1 $3)]
[(<expr> GE <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'ge $2 #f $1 $3)]
[(<expr> PLUS <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'plus $2 #f $1 $3)]
[(<expr> MINUS <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'minus $2 #f $1 $3)]
[(<expr> TIMES <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'times $2 #f $1 $3)]
[(<expr> DIV <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'div $2 #f $1 $3)]
[(<expr> MOD <expr>)
(make-ast:expr:binary/op
(create-src-stx 'ast:expr:binary/op source-name $1-start-pos $3-end-pos)
'mod $2 #f $1 $3)]
;; member access
[(<expr> DOT id)
(make-ast:expr:member
(create-src-stx 'honu-member source-name $1-start-pos $3-end-pos)
$1 #f $3 #f)]
[(my DOT id)
(make-ast:expr:member
(create-src-stx 'ast:expr:member source-name $1-start-pos $3-end-pos)
'my #f $3 #f)]
[(<any-type> fun O_PAREN <args> C_PAREN <block>)
(make-ast:expr:function
(create-src-stx 'ast:expr:function source-name $1-start-pos $6-end-pos)
$1 $4 $6)]
[(<literal>)
$1]
[(this)
(make-ast:expr:self $1)]
[(id)
(make-ast:expr:var $1 $1)]
[(<expr> BINDS <expr>)
(make-ast:expr:assign
(create-src-stx 'ast:expr:assign source-name $1-start-pos $3-end-pos)
$1 $3)]
;; application
[(<expr> <tuple>)
(make-ast:expr:apply
(create-src-stx 'ast:expr:apply source-name $1-start-pos $2-end-pos)
$1 $2)]
[(new id COLON <type-id> O_PAREN <newargs> C_PAREN)
(make-ast:expr:new
(create-src-stx 'ast:expr:new source-name $1-start-pos $7-end-pos)
$2 $4 $6)]
[(new id O_PAREN <newargs> C_PAREN)
(make-ast:expr:new
(create-src-stx 'ast:expr:new source-name $1-start-pos $5-end-pos)
$2 #f $4)]
[(<expr> COLON <type-id>)
(make-ast:expr:cast
(create-src-stx 'ast:expr:cast source-name $1-start-pos $3-end-pos)
$1 $3)]
[(<expr> isa <type-id>)
(make-ast:expr:isa
(create-src-stx 'ast:expr:isa source-name $1-start-pos $3-end-pos)
$1 $3)]
[(if <expr> <block>)
(make-ast:expr:if
(create-src-stx 'ast:expr:if source-name $1-start-pos $3-end-pos)
$2 $3 #f)]
[(if <expr> <block> else <block>)
(make-ast:expr:if
(create-src-stx 'ast:expr:if source-name $1-start-pos $5-end-pos)
$2 $3 $5)]
[(cond O_CURLY <cond-clauses> C_CURLY)
(make-ast:expr:cond
(create-src-stx 'ast:expr:cond source-name $1-start-pos $4-end-pos)
(car $3) (cadr $3))]
[(while <expr> <block>)
(make-ast:expr:while
(create-src-stx 'ast:expr:while source-name $1-start-pos $3-end-pos)
$2 $3)]
[(<tuple>)
$1]
[(return <expr>)
(make-ast:expr:return
(create-src-stx 'ast:expr:return source-name $1-start-pos $2-end-pos)
$2)]
[(<block>)
$1])
(<tuple>
[(O_PAREN C_PAREN)
(make-ast:expr:tuple
(create-src-stx 'ast:expr:tuple source-name $1-start-pos $2-end-pos)
(list))]
[(O_PAREN <exprs-cd> C_PAREN)
(if (null? (cdr $2))
(car $2)
(make-ast:expr:tuple
(create-src-stx 'ast:expr:tuple source-name $1-start-pos $3-end-pos)
$2))])
(<literal>
[(true)
(make-ast:expr:literal $1 (make-bool-type $1) $1)]
[(false)
(make-ast:expr:literal $1 (make-bool-type $1) $1)]
[(integer)
(make-ast:expr:literal $1 (make-int-type $1) $1)]
[(floatnum)
(make-ast:expr:literal $1 (make-float-type $1) $1)]
[(character)
(make-ast:expr:literal $1 (make-char-type $1) $1)]
[(string-lit)
(make-ast:expr:literal $1 (make-string-type $1) $1)]
[(null)
(make-ast:expr:literal $1 (make-null-type $1) (datum->syntax-object $1 'null-obj $1))])
(<cond-clauses>
[(<expr> THICK_ARROW <expr> SEMI_COLON <cond-clauses>)
(list (cons (make-ast:cond/clause
(create-src-stx 'ast:cond/clause source-name $1-start-pos $4-end-pos)
$1 $3)
(car $5))
(cadr $5))]
[(<expr> THICK_ARROW <expr> SEMI_COLON)
(list (list (make-ast:cond/clause
(create-src-stx 'ast:cond/clause source-name $1-start-pos $4-end-pos)
$1 $3))
#f)]
[(else <expr> SEMI_COLON)
(list '() $2)])
(<exprs-cd>
[(<expr> COMMA <exprs-cd>)
(cons $1 $3)]
[(<expr>)
(list $1)])
(<binding>
[(<bind> BINDS <expr> SEMI_COLON)
(make-ast:defn:binding
(create-src-stx 'ast:defn:binding source-name $1-start-pos $4-end-pos)
(list (ast:formal-name $1)) (list (ast:formal-type $1)) $3)]
[(O_PAREN <binds-cd> C_PAREN BINDS <expr> SEMI_COLON)
(let-values ([(names types) (map-two-values (lambda (f)
(values (ast:formal-name f)
(ast:formal-type f)))
$2)])
(make-ast:defn:binding
(create-src-stx 'ast:defn:binding source-name $1-start-pos $6-end-pos)
names types $5))])
(<interact>
[(<binding-defn>)
$1]
[(<expr>)
$1]))))
honu-parser)
(define (parse-interaction port file)
(let ([lexer (generate-honu-lexer file)]
[parser (cadr (generate-honu-parser file))])
(port-count-lines! port)
(parser
(lambda ()
(lexer port)))))
(define (parse-port port file)
(let ([lexer (generate-honu-lexer file)]
[parser (car (generate-honu-parser file))])
(port-count-lines! port)
(parser
(lambda ()
(lexer port)))))
(define (parse-file file)
(with-input-from-file file
(lambda ()
(parse-port (current-input-port)
(simplify-path (path->complete-path file))))))
(define (parse-stdin)
(parse-port (current-input-port) #f))
(define (parse-string string)
(parse-port (open-input-string string) #f))
(define (read-cm port)
(let loop ((filenames '())
(val (read port)))
(if (eof-object? val)
(reverse filenames)
(loop (cons (string-append val ".honu") filenames)
(read port)))))
(define (parse-group port name)
(let ([filenames (read-cm port)])
(if (null? filenames)
(list)
(let loop ((filenames filenames)
(defns '()))
(let ((parsed (parse-file
(simplify-path
(path->complete-path (car filenames))))))
(if (null? (cdr filenames))
(append parsed defns)
(loop (cdr filenames)
(append parsed defns))))))))
(define (parse-group-file dirname filename)
(let ([filenames (call-with-input-file
(string-append dirname "/" filename)
read-cm)])
(if (null? filenames)
(list)
(let loop ((filenames filenames)
(defns '()))
(let ((parsed (parse-file (string-append dirname "/"
(car filenames)))))
(if (null? (cdr filenames))
(append parsed defns)
(loop (cdr filenames)
(append parsed defns))))))))
(provide parse-file parse-port parse-stdin parse-string parse-group parse-group-file parse-interaction)
)

View File

@ -1,818 +0,0 @@
(module post-parsing mzscheme
(require (lib "list.ss" "srfi" "1")
(lib "plt-match.ss")
(lib "struct.ss")
"../ast.ss"
"../parameters.ss"
"../readerr.ss"
"../tenv.ss"
"../private/tools/general.ss")
;;;; Here are descriptions of what each of the three functions herein do:
;;;;
;;;; convert-static : converts bareword references to static slots/fields/methods <member>
;;;; into my.<member>
;;;; convert-slots : converts init slots that are used in methods or exports into
;;;; init fields instead. Since everything is exported from a struct,
;;;; all init slots are converted in those.
;;;; check-this : checks to make sure that all uses of this that are not before a dot
;;;; are on the LHS of a cast or isa expression. Else an error is thrown.
;;;; (also until we resolve the mixin safety issue, uses of this before a
;;;; dot are wrapped in a cast to the class's/mixin's selftype).
;;;; We also go ahead and implement the check that this is only used inside
;;;; a class or mixin form.
;;;; simplify-ast : converts lets inside lets or seqs inside seqs into a single let or seq.
;;;; since the current parser generates a new let or seq for every binding
;;;; or expression inside of a block, this merges them.
;;;; convert-static MUST be run before convert-slots.
;;;; add-defns-to-tenv (from tenv-utils.ss) must be run before
;;;; post-parse-program. This means that ast:defn:structure and
;;;; ast:defn:substructure structures will not appear in the defns,
;;;; and so we no longer need to cover them.
(provide post-parse-program post-parse-interaction)
(define (post-parse-program defns)
(convert-slots (convert-static (check-this (simplify-ast defns)))))
(define (post-parse-interaction ast)
(cond
[(ast:expr? ast)
(convert-static-expression (check-this-expression (simplify-expression ast) #f) '())]
[(ast:defn:binding? ast)
(convert-static-defn (check-this-defn (simplify-defn ast)))]))
;
;
; @
; @ @ @
; $@+@ $@$ @@:@@: @@@ @@@ -@@$ @@-$+ @@@@@ :@@+@ @@@@@ $@$: @@@@@ -@@ $@+@
; $+ -@ $- -$ @+ :@ $ $ $ -$ @$ : @ @$ -@ @ -@ @ @ $+ -@
; @ @ @ @ @ +: ++ @@@@@ @ @ @@@@@ :@@$- @ -$@$@ @ @ @
; @ @ @ @ @ $ $ $ @ @ *@ @ $* @ @ @ @
; $* -$ $- -$ @ @ $:+ +: @ @: :$ @ :@ @: :$ @- *@ @: :$ @ $* -$
; $@$- $@$ @@@ @@@ :@ $@@+ @@@@@ :@@$- $+@@: :@@$- -$$-@@ :@@$- @@@@@ $@$-
;
;
;
;
(define (convert-static defns)
(map convert-static-defn defns))
(define (convert-static-defn defn)
(match defn
[(struct ast:defn:iface (_ _ _ _))
defn]
[(struct ast:defn:class (_ _ _ _ _ inits members _))
(let-values ([(members _)
(convert-static-members members (map ast:formal-name inits))])
(copy-struct ast:defn:class defn
[ast:defn:class-members members]))]
[(struct ast:defn:mixin (_ _ _ arg-type _ _ inits _ super-new members-before members-after _))
(let*-values ([(members-before env)
(convert-static-members members-before (map ast:formal-name inits))]
[(super-new)
(convert-static-super-new super-new env)]
[(env)
(extend-env-with-type-members env arg-type)]
[(members-after _)
(convert-static-members members-after env)])
(copy-struct ast:defn:mixin defn
[ast:defn:mixin-super-new super-new]
[ast:defn:mixin-pre-members members-before]
[ast:defn:mixin-post-members members-after]))]
[(struct ast:defn:subclass (_ _ _ _))
defn]
[(struct ast:defn:function (_ _ _ _ _))
defn]
[(struct ast:defn:binding (_ _ _ _))
defn]))
(define (extend-env-with-type-members env type)
(let ([type-entry (get-type-entry type)])
(fold (lambda (m e)
(cons (tenv:member-name m) e))
env
(tenv:type-members type-entry))))
(define (convert-static-members members env)
(let loop ([members members]
[env env]
[results '()])
(cond
[(null? members) (values (reverse results) env)]
[(ast:class/member:method? (car members))
(let-values ([(methods remaining) (span ast:class/member:method? members)])
(let ([env (append (map ast:class/member-name methods) env)])
(loop remaining
env
;; reverse is here just to keep the order
(append (reverse (map (lambda (m)
(convert-static-member m env))
members))
results))))]
[else
(let ([name (ast:class/member-name (car members))])
(loop (cdr members)
(cons name env)
(cons (convert-static-member (car members) env) results)))])))
(define (convert-static-member member env)
(match member
[(struct ast:class/member:field/formal (_ name _ value))
(if value
(copy-struct ast:class/member:field/formal member
[ast:class/member:field/formal-default (convert-static-expression value env)])
member)]
[(struct ast:class/member:field (_ name _ value))
(copy-struct ast:class/member:field member
[ast:class/member:field-default (convert-static-expression value env)])]
[(struct ast:class/member:method (_ name _ args body))
;; remember to remove lexical bindings!
(let ([env (fold (lambda (name env)
(delete name env bound-identifier=?))
env (map ast:formal-name args))])
(copy-struct ast:class/member:method member
[ast:class/member:method-body (convert-static-expression body env)]))]))
(define (convert-static-super-new snew env)
(match snew
[(struct ast:super-new (_ args))
(copy-struct ast:super-new snew
[ast:super-new-args (map (lambda (a)
(convert-static-name-arg a env))
args)])]))
(define (convert-static-name-arg arg env)
(match arg
[(struct ast:named/arg (_ _ value))
(copy-struct ast:named/arg arg
[ast:named/arg-actual (convert-static-expression value env)])]))
(define (convert-static-expression expr env)
(match expr
[(struct ast:expr:self (_))
expr]
[(struct ast:expr:tuple/select (_ _ arg))
(copy-struct ast:expr:tuple/select expr
[ast:expr:tuple/select-arg (convert-static-expression arg env)])]
[(struct ast:expr:var (stx name))
(if (s:member name env bound-identifier=?)
(make-ast:expr:member stx 'my #f name #f)
expr)]
[(struct ast:expr:assign (_ lhs rhs))
(copy-struct ast:expr:assign expr
[ast:expr:assign-lhs (convert-static-expression lhs env)]
[ast:expr:assign-rhs (convert-static-expression rhs env)])]
[(struct ast:expr:apply (_ func arg))
(copy-struct ast:expr:apply expr
[ast:expr:apply-func (convert-static-expression func env)]
[ast:expr:apply-arg (convert-static-expression arg env)])]
[(struct ast:expr:literal (_ _ _))
expr]
[(struct ast:expr:unary/op (_ _ _ _ arg))
(copy-struct ast:expr:unary/op expr
[ast:expr:unary/op-arg (convert-static-expression arg env)])]
[(struct ast:expr:binary/op (_ _ _ _ larg rarg))
(copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-left (convert-static-expression larg env)]
[ast:expr:binary/op-right (convert-static-expression rarg env)])]
;; originally forgot to remove the identifiers bound by
;; the lambda from the environment
[(struct ast:expr:function (_ _ args body))
(let ([env (fold (lambda (name env)
(delete name env bound-identifier=?))
env (map ast:formal-name args))])
(copy-struct ast:expr:function expr
[ast:expr:function-body (convert-static-expression body env)]))]
[(struct ast:expr:if (_ cond then else))
(copy-struct ast:expr:if expr
[ast:expr:if-test (convert-static-expression cond env)]
[ast:expr:if-then (convert-static-expression then env)]
[ast:expr:if-else (if else (convert-static-expression else env) #f)])]
[(struct ast:expr:cast (_ obj _))
(copy-struct ast:expr:cast expr
[ast:expr:cast-object (convert-static-expression obj env)])]
[(struct ast:expr:isa (_ obj _))
(copy-struct ast:expr:isa expr
[ast:expr:isa-object (convert-static-expression obj env)])]
[(struct ast:expr:member (_ 'my _ _ _))
expr]
[(struct ast:expr:member (_ obj _ _ _))
(copy-struct ast:expr:member expr
[ast:expr:member-object (convert-static-expression obj env)])]
[(struct ast:expr:new (_ _ _ args))
(copy-struct ast:expr:new expr
[ast:expr:new-args (map (lambda (a)
(convert-static-name-arg a env))
args)])]
[(struct ast:expr:while (_ cond body))
(copy-struct ast:expr:while expr
[ast:expr:while-test (convert-static-expression cond env)]
[ast:expr:while-body (convert-static-expression body env)])]
[(struct ast:expr:cond (_ clauses else))
(copy-struct ast:expr:cond expr
[ast:expr:cond-clauses (map (lambda (c)
(convert-static-cond-clause c env))
clauses)]
[ast:expr:cond-else (if else (convert-static-expression else env) #f)])]
[(struct ast:expr:return (_ body))
(copy-struct ast:expr:return expr
[ast:expr:return-result (convert-static-expression body env)])]
[(struct ast:expr:tuple (_ vals))
(copy-struct ast:expr:tuple expr
[ast:expr:tuple-elems (map (lambda (e)
(convert-static-expression e env))
vals)])]
[(struct ast:expr:let (_ bindings body))
(let*-values ([(bindings env) (map-and-fold convert-static-binding env bindings)]
[(body) (convert-static-expression body env)])
(copy-struct ast:expr:let expr
[ast:expr:let-bindings bindings]
[ast:expr:let-body body]))]
[(struct ast:expr:sequence (_ effects value))
(let ([effects (map (lambda (e)
(convert-static-expression e env))
effects)]
[value (convert-static-expression value env)])
(copy-struct ast:expr:sequence expr
[ast:expr:sequence-statements effects]
[ast:expr:sequence-result value]))]))
(define (convert-static-binding binding env)
(match binding
[(struct ast:defn:binding (_ names _ value))
(values
(copy-struct ast:defn:binding binding
[ast:defn:binding-init (convert-static-expression value env)])
(fold (lambda (name env)
(if name
(delete name env bound-identifier=?)
env))
env names))]))
(define (convert-static-cond-clause clause env)
(match clause
[(struct ast:cond/clause (_ pred rhs))
(copy-struct ast:cond/clause clause
[ast:cond/clause-test (convert-static-expression pred env)]
[ast:cond/clause-result (convert-static-expression rhs env)])]))
;
;
; @@
; @ @ @
; $@+@ $@$ @@:@@: @@@ @@@ -@@$ @@-$+ @@@@@ :@@+@ @ $@$ @@@@@ :@@+@
; $+ -@ $- -$ @+ :@ $ $ $ -$ @$ : @ @$ -@ @ $- -$ @ @$ -@
; @ @ @ @ @ +: ++ @@@@@ @ @ @@@@@ :@@$- @ @ @ @ :@@$-
; @ @ @ @ @ $ $ $ @ @ *@ @ @ @ @ *@
; $* -$ $- -$ @ @ $:+ +: @ @: :$ @ :@ @ $- -$ @: :$ @ :@
; $@$- $@$ @@@ @@@ :@ $@@+ @@@@@ :@@$- $+@@: @@@@@ $@$ :@@$- $+@@:
;
;
;
;
;; CONVERT-SLOTS ASSUMES THAT CONVERT-STATIC HAS BEEN RUN FIRST, SO THAT WE DON'T HAVE TO WORRY
;; ABOUT SLOT NAMES BEING CAPTURED BY LEXICAL BINDINGS (AS ALL SLOT ACCESSES SHOULD HAVE BEEN
;; CONVERTED TO MY.<SLOTNAME>)
(define (convert-slots defns)
(map convert-slots-defn defns))
(define (convert-slots-defn defn)
(match defn
[(struct ast:defn:iface (_ _ _ _))
defn]
[(struct ast:defn:class (_ _ _ _ _ inits members exports))
(let* ([env (map ast:formal-name inits)]
[used-slots-members (apply append (map (lambda (m) (convert-slots-member m env)) members))]
[used-slots-exports (apply append (map (lambda (e) (convert-slots-export e env)) exports))]
[used-slots (append used-slots-members used-slots-exports)])
(let loop ([inits inits]
[kept-inits '()]
[new-fields '()])
(if (null? inits)
(copy-struct ast:defn:class defn
[ast:defn:class-formals (reverse kept-inits)]
[ast:defn:class-members (append (reverse new-fields) members)])
(if (s:member (ast:formal-name (car inits)) used-slots bound-identifier=?)
(loop (cdr inits)
kept-inits
(cons (make-ast:class/member:field/formal (ast-syntax (car inits))
(ast:formal-name (car inits))
(ast:formal-type (car inits))
#f)
new-fields))
(loop (cdr inits)
(cons (car inits) kept-inits)
new-fields)))))]
[(struct ast:defn:mixin (_ _ _ _ _ _ inits _ _ members-before members-after exports))
(let* ([env (map ast:formal-name inits)]
[used-slots-before (apply append (map (lambda (m) (convert-slots-member m env)) members-before))]
[used-slots-after (apply append (map (lambda (m) (convert-slots-member m env)) members-after))]
[used-slots-exports (apply append (map (lambda (e) (convert-slots-export e env)) exports))]
[used-slots (append used-slots-before used-slots-after used-slots-exports)])
(let loop ([inits inits]
[kept-inits '()]
[new-fields '()])
(if (null? inits)
(copy-struct ast:defn:mixin defn
[ast:defn:mixin-formals (reverse kept-inits)]
[ast:defn:mixin-pre-members (append (reverse new-fields) members-before)])
(if (s:member (ast:formal-name (car inits)) used-slots bound-identifier=?)
(loop (cdr inits)
kept-inits
(cons (make-ast:class/member:field/formal (ast-syntax (car inits))
(ast:formal-name (car inits))
(ast:formal-type (car inits))
#f)
new-fields))
(loop (cdr inits)
(cons (car inits) kept-inits)
new-fields)))))]
[(struct ast:defn:subclass (_ _ _ _))
defn]
[(struct ast:defn:function (_ _ _ _ _))
defn]
[(struct ast:defn:binding (_ _ _ _))
defn]))
(define (convert-slots-member member env)
(match member
;; init fields and fields do not necessitate converting init slots into init fields
[(struct ast:class/member:field/formal (_ name _ value))
(list)]
[(struct ast:class/member:field (_ name _ value))
(list)]
;; methods do, though.
[(struct ast:class/member:method (_ name _ _ body))
(convert-slots-expression body env)]))
(define (convert-slots-export export env)
(match export
[(struct ast:export (_ _ binds))
(filter (lambda (old)
(s:member old env bound-identifier=?))
(map ast:export/member-internal binds))]))
(define (convert-slots-name-arg arg env)
(match arg
[(struct ast:named/arg (_ _ value))
(convert-slots-expression value env)]))
(define (convert-slots-expression expr env)
(match expr
[(struct ast:expr:self (_))
(list)]
[(struct ast:expr:tuple/select (_ _ arg))
(convert-slots-expression arg env)]
[(struct ast:expr:var (_ _))
(list)]
[(struct ast:expr:assign (_ lhs rhs))
(append (convert-slots-expression lhs env)
(convert-slots-expression rhs env))]
[(struct ast:expr:apply (_ func arg))
(append (convert-slots-expression func env)
(convert-slots-expression arg env))]
[(struct ast:expr:literal (_ _ _))
(list)]
[(struct ast:expr:unary/op (_ _ _ _ arg))
(convert-slots-expression arg env)]
[(struct ast:expr:binary/op (_ _ _ _ larg rarg))
(append (convert-slots-expression larg env)
(convert-slots-expression rarg env))]
[(struct ast:expr:function (_ _ _ body))
(convert-slots-expression body env)]
[(struct ast:expr:if (_ cond then else))
(append (convert-slots-expression cond env)
(convert-slots-expression then env)
(if else (convert-slots-expression else env) (list)))]
[(struct ast:expr:cast (_ obj _))
(convert-slots-expression obj env)]
[(struct ast:expr:isa (_ obj _))
(convert-slots-expression obj env)]
[(struct ast:expr:member (_ 'my _ name _))
(cond
;; if this is a (bare-referenced) init slot,
;; then we return a "set" of it, else we return
;; an empty "set"
[(s:member name env bound-identifier=?)
=>
(lambda (l) (list (car l)))]
[else (list)])]
[(struct ast:expr:member (_ obj _ _ _))
(convert-slots-expression obj env)]
[(struct ast:expr:new (_ _ _ args))
(apply append
(map (lambda (a)
(convert-slots-name-arg a env))
args))]
[(struct ast:expr:while (_ cond body))
(append (convert-slots-expression cond env)
(convert-slots-expression body env))]
[(struct ast:expr:cond (_ clauses else))
(apply append (cons (if else (convert-slots-expression else env) (list))
(map (lambda (c)
(convert-slots-cond-clause c env))
clauses)))]
[(struct ast:expr:return (_ body))
(convert-slots-expression body env)]
[(struct ast:expr:tuple (_ vals))
(apply append
(map (lambda (e)
(convert-slots-expression e env))
vals))]
[(struct ast:expr:let (_ bindings body))
(let ([bindings (map (lambda (b)
(convert-slots-binding b env))
bindings)]
[body (convert-slots-expression body env)])
(apply append (cons body bindings)))]
[(struct ast:expr:sequence (_ effects value))
(apply append (cons (convert-slots-expression value env)
(map (lambda (e)
(convert-slots-expression e env))
effects)))]))
(define (convert-slots-binding binding env)
(match binding
[(struct ast:defn:binding (_ _ _ value))
(convert-slots-expression value env)]))
(define (convert-slots-cond-clause clause env)
(match clause
[(struct ast:cond/clause (_ pred rhs))
(append (convert-slots-expression pred env)
(convert-slots-expression rhs env))]))
;
;
; @@ @@ @@ @
; @ @ @ @
; $@+@ @-@@: -@@$ $@+@ @ @@@ @@@@@ @-@@: -@@ :@@+@
; $+ -@ @+ :@ $ -$ $+ -@ @ *$ @ @+ :@ @ @$ -@
; @ @ @ @@@@@ @ @$$ @@@@@ @ @ @ @ :@@$-
; @ @ @ $ @ @$$ @ @ @ @ *@
; $* -$ @ @ +: $* -$ @ -$ @: :$ @ @ @ @ :@
; $@$- @@@ @@@ $@@+ $@$- @@ @@@- :@@$-@@@ @@@ @@@@@ $+@@:
;
;
;
;
(define (check-this defns)
(map check-this-defn defns))
(define (check-this-defn defn)
(match defn
[(struct ast:defn:iface (_ _ _ _))
defn]
[(struct ast:defn:class (_ _ type _ _ _ members _))
(let ([members (map (lambda (m) (check-this-member m type)) members)])
(copy-struct ast:defn:class defn
[ast:defn:class-members members]))]
[(struct ast:defn:mixin (_ _ type _ _ _ _ _ super-new members-before members-after _))
(let ([members-before (map (lambda (m) (check-this-member m type)) members-before)]
[super-new (check-this-super-new super-new type)]
[members-after (map (lambda (m) (check-this-member m type)) members-after)])
(copy-struct ast:defn:mixin defn
[ast:defn:mixin-super-new super-new]
[ast:defn:mixin-pre-members members-before]
[ast:defn:mixin-post-members members-after]))]
[(struct ast:defn:subclass (_ _ _ _))
defn]
[(struct ast:defn:function (_ _ _ _ body))
;; we only use check-this-expression here for side-effects (we should not get
;; a changed AST if this passes, only an exception if the this keyword occurs here).
(begin
(check-this-expression body #f)
defn)]
[(struct ast:defn:binding (_ _ _ rhs))
;; same check as in ast:defn:function.
(begin
(check-this-expression rhs #f)
defn)]))
(define (check-this-member member type)
(match member
[(struct ast:class/member:field/formal (_ name _ value))
(if value
(copy-struct ast:class/member:field/formal member
[ast:class/member:field/formal-default (check-this-expression value type)])
member)]
[(struct ast:class/member:field (_ name _ value))
(copy-struct ast:class/member:field member
[ast:class/member:field-default (check-this-expression value type)])]
[(struct ast:class/member:method (_ name _ args body))
(copy-struct ast:class/member:method member
[ast:class/member:method-body (check-this-expression body type)])]))
(define (check-this-super-new snew type)
(match snew
[(struct ast:super-new (_ args))
(copy-struct ast:super-new snew
[ast:super-new-args (map (lambda (a)
(check-this-name-arg a type))
args)])]))
(define (check-this-name-arg arg type)
(match arg
[(struct ast:named/arg (_ _ value))
(copy-struct ast:named/arg arg
[ast:named/arg-actual (check-this-expression value type)])]))
(define (check-this-expression expr type)
(match expr
[(struct ast:expr:self (stx))
(if type
(raise-read-error-with-stx
"Unprotected use of this in a client context"
stx)
(raise-read-error-with-stx
"Use of this keyword found outside of a class or mixin"
stx))]
[(struct ast:expr:tuple/select (_ _ arg))
(copy-struct ast:expr:tuple/select expr
[ast:expr:tuple/select-arg (check-this-expression arg type)])]
[(struct ast:expr:var (_ _))
expr]
[(struct ast:expr:assign (_ lhs rhs))
(copy-struct ast:expr:assign expr
[ast:expr:assign-lhs (check-this-expression lhs type)]
[ast:expr:assign-rhs (check-this-expression rhs type)])]
[(struct ast:expr:apply (_ func arg))
(copy-struct ast:expr:apply expr
[ast:expr:apply-func (check-this-expression func type)]
[ast:expr:apply-arg (check-this-expression arg type)])]
[(struct ast:expr:literal (_ _ _))
expr]
[(struct ast:expr:unary/op (_ _ _ _ arg))
(copy-struct ast:expr:unary/op expr
[ast:expr:unary/op-arg (check-this-expression arg type)])]
[(struct ast:expr:binary/op (_ _ _ _ larg rarg))
(copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-left (check-this-expression larg type)]
[ast:expr:binary/op-right (check-this-expression rarg type)])]
[(struct ast:expr:function (_ _ _ body))
(copy-struct ast:expr:function expr
[ast:expr:function-body (check-this-expression body type)])]
[(struct ast:expr:if (_ cond then else))
(copy-struct ast:expr:if expr
[ast:expr:if-test (check-this-expression cond type)]
[ast:expr:if-then (check-this-expression then type)]
[ast:expr:if-else (if else (check-this-expression else type) #f)])]
[(struct ast:expr:cast (_ obj _))
(if (ast:expr:self? obj)
(if type
expr
(raise-read-error-with-stx
"Use of this keyword found outside of a class or mixin"
(ast-syntax obj)))
(copy-struct ast:expr:cast expr
[ast:expr:cast-object (check-this-expression obj type)]))]
[(struct ast:expr:isa (_ obj _))
(if (ast:expr:self? obj)
(if type
expr
(raise-read-error-with-stx
"Use of this keyword found outside of a class or mixin"
(ast-syntax obj)))
(copy-struct ast:expr:isa expr
[ast:expr:isa-object (check-this-expression obj type)]))]
[(struct ast:expr:member (_ 'my _ _ _))
expr]
[(struct ast:expr:member (_ obj _ _ _))
(if (ast:expr:self? obj)
(if type
;; to deal with the fact that mixins can mess up the selftype
;; property, we hack by creating casts in this case.
(copy-struct ast:expr:member expr
[ast:expr:member-object (make-ast:expr:cast (ast-syntax obj)
obj
type)])
(raise-read-error-with-stx
"Use of this keyword found outside of a class or mixin"
(ast-syntax obj)))
(copy-struct ast:expr:member expr
[ast:expr:member-object (check-this-expression obj type)]))]
[(struct ast:expr:new (_ _ _ args))
(copy-struct ast:expr:new expr
[ast:expr:new-args (map (lambda (a)
(check-this-name-arg a type))
args)])]
[(struct ast:expr:while (_ cond body))
(copy-struct ast:expr:while expr
[ast:expr:while-test (check-this-expression cond type)]
[ast:expr:while-body (check-this-expression body type)])]
[(struct ast:expr:cond (_ clauses else))
(copy-struct ast:expr:cond expr
[ast:expr:cond-clauses (map (lambda (c)
(check-this-cond-clause c type))
clauses)]
[ast:expr:cond-else (if else (check-this-expression else type) #f)])]
[(struct ast:expr:return (_ body))
(copy-struct ast:expr:return expr
[ast:expr:return-result (check-this-expression body type)])]
[(struct ast:expr:tuple (_ vals))
(copy-struct ast:expr:tuple expr
[ast:expr:tuple-elems (map (lambda (e)
(check-this-expression e type))
vals)])]
[(struct ast:expr:let (_ bindings body))
(let ([bindings (map (lambda (b)
(check-this-binding b type))
bindings)]
[body (check-this-expression body type)])
(copy-struct ast:expr:let expr
[ast:expr:let-bindings bindings]
[ast:expr:let-body body]))]
[(struct ast:expr:sequence (_ effects value))
(let ([effects (map (lambda (e)
(check-this-expression e type))
effects)]
[value (check-this-expression value type)])
(copy-struct ast:expr:sequence expr
[ast:expr:sequence-statements effects]
[ast:expr:sequence-result value]))]))
(define (check-this-binding binding type)
(match binding
[(struct ast:defn:binding (_ names _ value))
(copy-struct ast:defn:binding binding
[ast:defn:binding-init (check-this-expression value type)])]))
(define (check-this-cond-clause clause type)
(match clause
[(struct ast:cond/clause (_ pred rhs))
(copy-struct ast:cond/clause clause
[ast:cond/clause-test (check-this-expression pred type)]
[ast:cond/clause-result (check-this-expression rhs type)])]))
;
;
; @ @@ @ :@@$
; @ @: @
; :@@+@ -@@ @@+-$: @@:@$- @ -@@ @@@@@ @@@ @@@ $@$: :@@+@ @@@@@
; @$ -@ @ @+@$@ @: -$ @ @ @ $- $- -@ @$ -@ @
; :@@$- @ @ @ @ @ @ @ @ @ -$ $ @@@@@ -$@$@ :@@$- @
; *@ @ @ @ @ @ @ @ @ @ $*$: $* @ *@ @
; @ :@ @ @ @ @ @: -$ @ @ @ $$ @- *@ @ :@ @: :$
; $+@@: @@@@@ @@@@@@@ @-@$ @@@@@ @@@@@ @@@@@ $* -$$-@@ $+@@: :@@$-
; @ $
; @@@ @@@@
;
;
(define (simplify-ast defns)
(map simplify-defn defns))
(define (simplify-defn defn)
(match defn
[(struct ast:defn:iface (_ _ _ _))
defn]
[(struct ast:defn:class (_ _ _ _ _ _ members _))
(copy-struct ast:defn:class defn
[ast:defn:class-members (map simplify-member members)])]
[(struct ast:defn:mixin (_ _ _ _ _ _ _ _ super-new members-before members-after _))
(copy-struct ast:defn:mixin defn
[ast:defn:mixin-super-new (simplify-super-new super-new)]
[ast:defn:mixin-pre-members (map simplify-member members-before)]
[ast:defn:mixin-post-members (map simplify-member members-after)])]
[(struct ast:defn:subclass (_ _ _ _))
defn]
[(struct ast:defn:function (_ _ _ _ body))
(copy-struct ast:defn:function defn
[ast:defn:function-body (simplify-expression body)])]
[(struct ast:defn:binding (_ _ _ value))
(copy-struct ast:defn:binding defn
[ast:defn:binding-init (simplify-expression value)])]))
(define (simplify-member member)
(match member
[(struct ast:class/member:field/formal (_ _ _ value))
(if value
(copy-struct ast:class/member:field/formal member
[ast:class/member:field/formal-default (simplify-expression value)])
member)]
[(struct ast:class/member:field (_ _ _ value))
(copy-struct ast:class/member:field member
[ast:class/member:field-default (simplify-expression value)])]
[(struct ast:class/member:method (_ _ _ _ body))
(copy-struct ast:class/member:method member
[ast:class/member:method-body (simplify-expression body)])]))
(define (simplify-super-new snew)
(match snew
[(struct ast:super-new (_ args))
(copy-struct ast:super-new snew
[ast:super-new-args (map simplify-name-arg args)])]))
(define (simplify-name-arg arg)
(match arg
[(struct ast:named/arg (_ _ value))
(copy-struct ast:named/arg arg
[ast:named/arg-actual (simplify-expression value)])]))
(define (simplify-expression expr)
(match expr
[(struct ast:expr:self (_))
expr]
[(struct ast:expr:tuple/select (_ _ arg))
(copy-struct ast:expr:tuple/select expr
[ast:expr:tuple/select-arg (simplify-expression arg)])]
[(struct ast:expr:var (_ _))
expr]
[(struct ast:expr:assign (_ lhs rhs))
(copy-struct ast:expr:assign expr
[ast:expr:assign-lhs (simplify-expression lhs)]
[ast:expr:assign-rhs (simplify-expression rhs)])]
[(struct ast:expr:apply (_ func arg))
(copy-struct ast:expr:apply expr
[ast:expr:apply-func (simplify-expression func)]
[ast:expr:apply-arg (simplify-expression arg)])]
[(struct ast:expr:literal (_ _ _))
expr]
[(struct ast:expr:unary/op (_ _ _ _ arg))
(copy-struct ast:expr:unary/op expr
[ast:expr:unary/op-arg (simplify-expression arg)])]
[(struct ast:expr:binary/op (_ _ _ _ larg rarg))
(copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-left (simplify-expression larg)]
[ast:expr:binary/op-right (simplify-expression rarg)])]
[(struct ast:expr:function (_ _ _ body))
(copy-struct ast:expr:function expr
[ast:expr:function-body (simplify-expression body)])]
[(struct ast:expr:if (_ cond then else))
(copy-struct ast:expr:if expr
[ast:expr:if-test (simplify-expression cond)]
[ast:expr:if-then (simplify-expression then)]
[ast:expr:if-else (if else (simplify-expression else) #f)])]
[(struct ast:expr:cast (_ obj _))
(copy-struct ast:expr:cast expr
[ast:expr:cast-object (simplify-expression obj)])]
[(struct ast:expr:isa (_ obj _))
(copy-struct ast:expr:isa expr
[ast:expr:isa-object (simplify-expression obj)])]
[(struct ast:expr:member (_ 'my _ _ _))
expr]
[(struct ast:expr:member (_ obj _ _ _))
(copy-struct ast:expr:member expr
[ast:expr:member-object (simplify-expression obj)])]
[(struct ast:expr:new (_ _ _ args))
(copy-struct ast:expr:new expr
[ast:expr:new-args (map simplify-name-arg args)])]
[(struct ast:expr:cond (_ clauses else))
(copy-struct ast:expr:cond expr
[ast:expr:cond-clauses (map simplify-cond-clause clauses)]
[ast:expr:cond-else (if else (simplify-expression else) #f)])]
[(struct ast:expr:while (_ cond body))
(copy-struct ast:expr:while expr
[ast:expr:while-test (simplify-expression cond)]
[ast:expr:while-body (simplify-expression body)])]
[(struct ast:expr:return (_ body))
(copy-struct ast:expr:return expr
[ast:expr:return-result (simplify-expression body)])]
[(struct ast:expr:tuple (_ vals))
(copy-struct ast:expr:tuple expr
[ast:expr:tuple-elems (map simplify-expression vals)])]
[(struct ast:expr:let (stx bindings body))
(let ([bindings (map simplify-binding bindings)]
[body (simplify-expression body)])
(match body
[(struct ast:expr:let (_ sub-bindings sub-body))
(make-ast:expr:let stx (append bindings sub-bindings) sub-body)]
[_
(copy-struct ast:expr:let expr
[ast:expr:let-bindings bindings]
[ast:expr:let-body body])]))]
[(struct ast:expr:sequence (stx effects value))
(let ([effects (map simplify-expression effects)]
[value (simplify-expression value)])
(match value
[(struct ast:expr:sequence (_ sub-effects sub-value))
(make-ast:expr:sequence stx (append effects sub-effects) sub-value)]
[_
(copy-struct ast:expr:sequence expr
[ast:expr:sequence-statements effects]
[ast:expr:sequence-result value])]))]))
(define (simplify-binding binding)
(match binding
[(struct ast:defn:binding (_ _ _ value))
(copy-struct ast:defn:binding binding
[ast:defn:binding-init (simplify-expression value)])]))
(define (simplify-cond-clause clause)
(match clause
[(struct ast:cond/clause (_ pred rhs))
(copy-struct ast:cond/clause clause
[ast:cond/clause-test (simplify-expression pred)]
[ast:cond/clause-result (simplify-expression rhs)])]))
)

View File

@ -1,184 +0,0 @@
(module translate-class-utils mzscheme
(require (lib "list.ss" "srfi" "1")
(only (lib "list.ss") quicksort)
(lib "plt-match.ss")
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss"
"../tools/general.ss"
"../typechecker/type-utils.ss"
"translate-expression.ss"
"translate-utils.ss")
(define-struct comp:export (stx type binds) #f)
(define-struct comp:exp-bind (old new method?) #f)
(provide translate-class-exports translate-subclass-exports)
(define (translate-class-exports exports)
(let ([exports (filter-exports (generate-exports exports))])
(map (lambda (e)
(translate-export #f e))
exports)))
(define (translate-subclass-exports super-types exports)
(let ([exports (filter-exports (generate-exports exports))])
(map (lambda (e)
(if (ormap (lambda (t)
(<:_P t (comp:export-type e)))
super-types)
(translate-export #t e)
(translate-export #f e)))
exports)))
(define (generate-super-exports type-entry comp-binds)
(let loop ([super-types (tenv:type-supers type-entry)]
[super-comp-exps '()])
(if (null? super-types)
super-comp-exps
(let ([super-entry (get-type-entry (car super-types))])
(let loop2 ([super-members (append (tenv:type-members super-entry)
(tenv:type-inherited super-entry))]
[super-comp-binds '()])
(if (null? super-members)
(loop (cdr super-types)
(cons (make-comp:export #f (car super-types) super-comp-binds)
(append (generate-super-exports super-entry comp-binds)
super-comp-exps)))
(let ([matched (find (lambda (eb)
(tenv-key=? (tenv:member-name (car super-members))
(comp:exp-bind-new eb)))
comp-binds)])
(loop2 (cdr super-members)
(cons matched super-comp-binds)))))))))
(define (generate-exports exports)
(let loop ([exports exports]
[comp-exps '()])
(if (null? exports)
comp-exps
(let* ([export (car exports)]
[type-entry (get-type-entry (ast:export-type export))])
(let loop2 ([exp-binds (ast:export-members export)]
[members (append (tenv:type-members type-entry)
(tenv:type-inherited type-entry))]
[comp-binds '()])
(if (null? exp-binds)
(let ([super-exports (generate-super-exports type-entry comp-binds)])
(loop (cdr exports)
(cons (make-comp:export (ast-syntax export)
(ast:export-type export)
comp-binds)
(append super-exports comp-exps))))
(let-values ([(matched non-matches) (partition-first (lambda (m)
(tenv-key=? (ast:export/member-external (car exp-binds))
(tenv:member-name m)))
members)])
(loop2 (cdr exp-binds)
non-matches
(cons (make-comp:exp-bind (ast:export/member-internal (car exp-binds))
(ast:export/member-external (car exp-binds))
(ast:type:method? (tenv:member-type matched)))
comp-binds)))))))))
(define (sort-binds export)
(quicksort (comp:export-binds export)
(lambda (b1 b2)
(tenv-key<? (comp:exp-bind-new b1)
(comp:exp-bind-new b2)))))
(define (check-exports exports)
(let* ([main-export (car exports)]
[main-export-binds (sort-binds main-export)])
(let loop ([exports (cdr exports)])
(if (null? exports)
(void)
(let loop2 ([binds-1 main-export-binds]
[binds-2 (sort-binds (car exports))])
;; if one's empty, both must be since we passed the typechecker
(cond
[(null? binds-1)
(loop (cdr exports))]
[(tenv-key=? (comp:exp-bind-old (car binds-1))
(comp:exp-bind-old (car binds-2)))
(loop2 (cdr binds-1) (cdr binds-2))]
[else
(raise-read-error-with-stx
(format "Different local names exported for member ~a of type ~a: ~a here and ~a elsewhere"
(printable-type (comp:export-type main-export))
(printable-key (comp:exp-bind-new (car binds-1)))
(printable-key (comp:exp-bind-old (car binds-1)))
(printable-key (comp:exp-bind-old (car binds-2))))
(comp:exp-bind-old (car binds-1)))]))))))
(define (filter-exports exports)
(let loop ([exports exports]
[kept-exps '()])
(if (null? exports)
kept-exps
(let-values ([(matches non-matches) (partition (lambda (exp)
(type-equal?
(comp:export-type (car exports))
(comp:export-type exp)))
exports)])
(check-exports matches)
(let ([exp-with-stx (find comp:export-stx (cons (car exports) matches))])
(if exp-with-stx
(loop non-matches (cons exp-with-stx kept-exps))
(loop non-matches (cons (car exports) kept-exps))))))))
(define (translate-export in-super? export)
(cons 'begin
(map (lambda (b)
(translate-exp-bind in-super? (comp:export-type export) b))
(comp:export-binds export))))
(define (translate-exp-bind in-super? type binding)
(let ([right-defn (if in-super? 'define/override 'define/public)])
(match binding
[(struct comp:exp-bind (old-name new-name #t))
(at #f `(,right-defn (,(translate-method-name type new-name) arg-tuple)
,(translate-static-method old-name 'arg-tuple)))]
[(struct comp:exp-bind (old-name new-name #f))
(at #f `(begin
(,right-defn (,(translate-field-getter-name type new-name) args)
,(translate-static-field-getter old-name))
(,right-defn (,(translate-field-setter-name type new-name) set-arg)
,(translate-static-field-setter old-name 'set-arg))))])))
(provide translate-super-new translate-inits translate-member)
(define (translate-super-new super-new)
(at (ast-syntax super-new)
(cons 'super-new (map (lambda (a)
(list (at-ctxt (ast:named/arg-name a))
(translate-expression (ast:named/arg-actual a))))
(ast:super-new-args super-new)))))
(define (translate-inits inits)
(cons 'init (map (lambda (i)
(at-ctxt (ast:formal-name i)))
inits)))
(define (mangle-init-name name)
(at name (string->symbol (string-append "init-" (symbol->string (syntax-e name))))))
(define (translate-member member)
(match member
[(struct ast:class/member:field/formal (stx name type value))
(if value
(at stx`(begin (init ([,(mangle-init-name name) ,(at-ctxt name)]
,(translate-expression value)))
(define ,(at-ctxt name) ,(mangle-init-name name))))
(at stx `(begin (init ([,(mangle-init-name name) ,(at-ctxt name)]))
(define ,(at-ctxt name) ,(mangle-init-name name)))))]
[(struct ast:class/member:field (stx name type value))
(at stx `(define ,(at-ctxt name) ,(translate-expression value)))]
[(struct ast:class/member:method (stx name type formals body))
(translate-function stx name formals (translate-expression body))]))
)

View File

@ -1,308 +0,0 @@
(module translate-expression mzscheme
(require (lib "contract.ss")
(lib "plt-match.ss")
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss"
"../typechecker/type-utils.ss"
"translate-utils.ss")
(provide/contract [translate-expression (ast:expr?
. -> .
(syntax/c any/c))])
(define (translate-expression expr)
(match expr
[(struct ast:expr:literal (stx _ value))
(at stx value)]
[(struct ast:expr:var (stx name))
(at-ctxt name)]
[(struct ast:expr:tuple (stx args))
;; list is a bindable name in Honu, so... we use list*, which isn't.
(at stx `(list* ,@(map translate-expression args) ()))]
[(struct ast:expr:function (stx _ formals body))
(translate-function stx #f formals (translate-expression body))]
[(struct ast:expr:apply (stx func arg))
(match func
[(struct ast:expr:member (stx 'my _ name #t))
(at stx (translate-static-method name (translate-expression arg)))]
[(struct ast:expr:member (stx obj elab name #t))
(at stx `(honu:send ,(translate-expression obj)
,(translate-method-name elab name)
,(translate-expression arg)))]
[else
(at stx `(,(translate-expression func)
,(translate-expression arg)))])]
[(struct ast:expr:tuple/select (stx slot arg))
(at stx `(list-ref ,(translate-expression arg)
(- ,slot 1)))]
[(struct ast:expr:if (stx test then else))
(if else
(at stx `(if ,(translate-expression test)
,(translate-expression then)
,(translate-expression else)))
(at stx `(if ,(translate-expression test)
,(translate-expression then)
,void-value)))]
[(struct ast:expr:cond (stx clauses else))
(if else
(at stx `(cond ,@(map (lambda (c)
`(,(translate-expression (ast:cond/clause-test c))
,(translate-expression (ast:cond/clause-result c))))
clauses)
(else ,(translate-expression else))))
(at stx `(cond ,@(map (lambda (c)
`(,(translate-expression (ast:cond/clause-test c))
,(translate-expression (ast:cond/clause-result c))))
clauses)
(else ,void-value))))]
[(struct ast:expr:unary/op (stx op op-stx op-type arg))
(case op
[(not)
(at stx
`(,(at op-stx 'not) ,(translate-expression arg)))]
[(minus)
(at stx
`(,(at op-stx '-) ,(translate-expression arg)))]
[else (raise-read-error-with-stx
"Haven't translated unary operator yet."
op-stx)])]
[(struct ast:expr:binary/op (stx op op-stx op-type larg rarg))
(case op
[(equal)
(if (and (ast:type:primitive? op-type)
(eqv? (ast:type:primitive-name op-type) 'string))
(at stx
`(,(at op-stx 'string=?)
,(translate-expression larg)
,(translate-expression rarg)))
(at stx
`(,(at op-stx 'eqv?)
,(translate-expression larg)
,(translate-expression rarg))))]
[(neq)
(if (and (ast:type:primitive? op-type)
(eqv? (ast:type:primitive-name op-type) 'string))
(at stx
`(,(at op-stx 'not)
(,(at op-stx 'string=?)
,(translate-expression larg)
,(translate-expression rarg))))
(at stx
`(,(at op-stx 'not)
(,(at op-stx 'eqv?)
,(translate-expression larg)
,(translate-expression rarg)))))]
[(clseq)
(at stx
`(,(at op-stx 'equal?)
,(translate-expression larg)
,(translate-expression rarg)))]
[(and)
(at stx
`(,(at op-stx 'and)
,(translate-expression larg)
,(translate-expression rarg)))]
[(or)
(at stx
`(,(at op-stx 'or)
,(translate-expression larg)
,(translate-expression rarg)))]
[(lt)
(case (ast:type:primitive-name op-type)
[(int float)
(at stx
`(,(at op-stx '<)
,(translate-expression larg)
,(translate-expression rarg)))]
[(string)
(at stx
`(,(at op-stx 'string<?)
,(translate-expression larg)
,(translate-expression rarg)))]
[(char)
(at stx
`(,(at op-stx 'char<?)
,(translate-expression larg)
,(translate-expression rarg)))])]
[(le)
(case (ast:type:primitive-name op-type)
[(int float)
(at stx
`(,(at op-stx '<=)
,(translate-expression larg)
,(translate-expression rarg)))]
[(string)
(at stx
`(,(at op-stx 'string<=?)
,(translate-expression larg)
,(translate-expression rarg)))]
[(char)
(at stx
`(,(at op-stx 'char<=?)
,(translate-expression larg)
,(translate-expression rarg)))])]
[(gt)
(case (ast:type:primitive-name op-type)
[(int float)
(at stx
`(,(at op-stx '>)
,(translate-expression larg)
,(translate-expression rarg)))]
[(string)
(at stx
`(,(at op-stx 'string>?)
,(translate-expression larg)
,(translate-expression rarg)))]
[(char)
(at stx
`(,(at op-stx 'char>?)
,(translate-expression larg)
,(translate-expression rarg)))])]
[(ge)
(case (ast:type:primitive-name op-type)
[(int float)
(at stx
`(,(at op-stx '>=)
,(translate-expression larg)
,(translate-expression rarg)))]
[(string)
(at stx
`(,(at op-stx 'string>=?)
,(translate-expression larg)
,(translate-expression rarg)))]
[(char)
(at stx
`(,(at op-stx 'char>=?)
,(translate-expression larg)
,(translate-expression rarg)))])]
[(plus)
(case (ast:type:primitive-name op-type)
[(int float)
(at stx
`(,(at op-stx '+)
,(translate-expression larg)
,(translate-expression rarg)))]
[(string)
(at stx
`(,(at op-stx 'string-append)
,(translate-expression larg)
,(translate-expression rarg)))])]
[(minus)
(at stx
`(,(at op-stx '-)
,(translate-expression larg)
,(translate-expression rarg)))]
[(times)
(at stx
`(,(at op-stx '*)
,(translate-expression larg)
,(translate-expression rarg)))]
[(div)
(case (ast:type:primitive-name op-type)
[(int)
(at stx
`(,(at op-stx 'quotient)
,(translate-expression larg)
,(translate-expression rarg)))]
[(float)
(at stx
`(,(at op-stx '/)
,(translate-expression larg)
,(translate-expression rarg)))])]
[(mod)
(at stx
`(,(at op-stx 'remainder)
,(translate-expression larg)
,(translate-expression rarg)))]
[else (raise-read-error-with-stx
"Haven't translated binary operator yet."
op-stx)])]
[(struct ast:expr:return (stx body))
(at stx
`(last-k ,(translate-expression body)))]
[(struct ast:expr:let (stx bindings body))
(at stx
`(let*-values ,(map (lambda (b)
(let-values ([(bound-names body)
(translate-binding-clause (ast:defn:binding-names b)
(translate-expression (ast:defn:binding-init b)))])
;; make sure to give the let binding the appropriate syntax,
;; otherwise errors will highlight the entire let expression.
(at (ast-syntax b) `(,bound-names ,body))))
bindings)
,(translate-expression body)))]
[(struct ast:expr:sequence (stx effects value))
(at stx
`(begin ,@(map translate-expression effects)
,(translate-expression value)))]
[(struct ast:expr:while (stx test body))
(at stx
`(let loop ()
(if ,(translate-expression test)
(begin ,(translate-expression body) (loop))
,void-value)))]
[(struct ast:expr:assign (stx lhs rhs))
(match lhs
[(struct ast:expr:var (_ _))
(at stx `(begin (set! ,(translate-expression lhs)
,(translate-expression rhs))
,void-value))]
[(struct ast:expr:member (mstx 'my _ name method?))
(if method?
(raise-read-error-with-stx
"Left-hand side of assignment cannot be a method name"
mstx)
(at stx (translate-static-field-setter name (translate-expression rhs))))]
[(struct ast:expr:member (mstx obj elab name method?))
(if method?
(raise-read-error-with-stx
"Left-hand side of assignment cannot be a method name"
mstx)
(at stx `(honu:send ,(translate-expression obj)
,(translate-field-setter-name elab name)
,(translate-expression rhs))))]
[else
(raise-read-error-with-stx
"Left-hand side of assignment is invalid"
stx)])]
[(struct ast:expr:member (stx 'my _ name method?))
(if method?
(at stx (translate-static-method name))
(at stx (translate-static-field-getter name)))]
[(struct ast:expr:member (stx obj elab name method?))
(if method?
(at stx `(lambda (args)
(honu:send ,(translate-expression obj)
,(translate-method-name elab name)
args)))
(at stx `(honu:send ,(translate-expression obj)
,(translate-field-getter-name elab name)
,void-value)))]
[(struct ast:expr:new (stx class _ args))
(at stx `(new ,(translate-class-name class)
,@(map (lambda (a)
`(,(ast:named/arg-name a)
,(translate-expression (ast:named/arg-actual a))))
args)))]
[(struct ast:expr:cast (stx obj type))
(at stx `(let ([cast-obj ,(translate-expression obj)])
;; you can always cast null to an interface type
(if (or (is-a? cast-obj null%)
(honu:send cast-obj implements? ,(translate-iface-name type)))
cast-obj
(error (format "Class ~a does not implement ~a"
(honu:send cast-obj format-class-name)
(quote ,(syntax-e (iface-name type))))))))]
[(struct ast:expr:isa (stx obj type))
(at stx `(let ([cast-obj ,(translate-expression obj)])
;; null is a member of any interface type
(or (is-a? cast-obj null%)
(honu:send cast-obj implements? ,(translate-iface-name type)))))]
[(struct ast:expr:self (stx))
(at stx 'this)]
[else (raise-read-error-with-stx
"Haven't translated that type of expression yet."
(ast-syntax expr))]))
)

View File

@ -1,7 +0,0 @@
(module translate-parameters mzscheme
(provide (all-defined))
(define current-mixin-argument-type (make-parameter #f))
)

View File

@ -1,168 +0,0 @@
(module translate-unwanted-types mzscheme
(require (lib "list.ss" "srfi" "1")
(lib "plt-match.ss")
"../../ast.ss"
"translate-utils.ss")
(provide build-unwanted-type-syntax)
(define (build-unwanted-type-syntax defns)
(map build-unwanted-type-syntax-defn defns))
;; since we're never going to run the result anyway, it doesn't matter
;; how we build things -- no need to flatten.
(define (build-unwanted-type-syntax-defn defn)
(match defn
[(struct ast:defn:binding (_ _ types value))
(cons (build-unwanted-type-syntax-expression value)
;; remember to filter out the top types used whenever _ appears
(map translate-type-for-syntax (filter (lambda (t) (not (ast:type:top? t))) types)))]
[(struct ast:defn:function (_ _ type formals body))
(list (translate-type-for-syntax type)
(build-unwanted-type-syntax-expression body)
(map (lambda (f)
(translate-type-for-syntax (ast:formal-type f)))
formals))]
[(struct ast:defn:iface (_ _ _ members))
(map build-unwanted-type-syntax-member-decl members)]
[(struct ast:defn:class (_ _ selftype _ _ inits members exports))
(list (translate-type-for-syntax selftype)
(map (lambda (f)
(translate-type-for-syntax (ast:formal-type f)))
inits)
(map build-unwanted-type-syntax-member members)
(map (lambda (e)
(translate-type-for-syntax (ast:export-type e)))
exports))]
[(struct ast:defn:mixin (_ _ selftype arg-type _ _ inits withs super-new
members-before members-after exports))
(list (translate-type-for-syntax selftype)
(translate-type-for-syntax arg-type)
(map (lambda (f)
(translate-type-for-syntax (ast:formal-type f)))
inits)
(map (lambda (f)
(translate-type-for-syntax (ast:formal-type f)))
withs)
(map (lambda (a)
(build-unwanted-type-syntax-expression (ast:named/arg-actual a)))
(ast:super-new-args super-new))
(map build-unwanted-type-syntax-member members-before)
(map build-unwanted-type-syntax-member members-after)
(map (lambda (e)
(translate-type-for-syntax (ast:export-type e)))
exports))]
[(struct ast:defn:subclass (_ _ _ mixin))
;; okay, this isn't a type, but we still want to see it as a use
;; until we can translate mixins correctly.
(list (translate-mixin-name mixin))]))
(define (build-unwanted-type-syntax-member-decl member)
(match member
[(struct ast:iface/member:field (_ _ type))
(translate-type-for-syntax type)]
[(struct ast:iface/member:method (_ _ type arg-types))
(list (translate-type-for-syntax type)
(map translate-type-for-syntax arg-types))]))
(define (build-unwanted-type-syntax-member member)
(match member
[(struct ast:class/member:field/formal (_ _ type value))
(list (translate-type-for-syntax type)
(if value (build-unwanted-type-syntax-expression value) '()))]
[(struct ast:class/member:field (_ _ type value))
(list (translate-type-for-syntax type)
(build-unwanted-type-syntax-expression value))]
[(struct ast:class/member:method (_ _ type formals body))
(list (translate-type-for-syntax type)
(map (lambda (f)
(translate-type-for-syntax (ast:formal-type f)))
formals)
(build-unwanted-type-syntax-expression body))]))
(define (build-unwanted-type-syntax-expression expr)
(match expr
[(struct ast:expr:function (_ type formals body))
(list (translate-type-for-syntax type)
(map (lambda (f)
(translate-type-for-syntax (ast:formal-type f)))
formals)
(build-unwanted-type-syntax-expression body))]
[(struct ast:expr:let (_ bindings body))
(list (map (lambda (b)
;; again, make sure to remove types corresponding to _
(list (map translate-type-for-syntax (filter (lambda (t)
(not (ast:type:top? t)))
(ast:defn:binding-types b)))
(build-unwanted-type-syntax-expression (ast:defn:binding-init b))))
bindings)
(build-unwanted-type-syntax-expression body))]
[(struct ast:expr:sequence (_ effects result))
(list (map (lambda (e)
(build-unwanted-type-syntax-expression e))
effects)
(build-unwanted-type-syntax-expression result))]
[(struct ast:expr:apply (_ func arg))
(list (build-unwanted-type-syntax-expression func)
(build-unwanted-type-syntax-expression arg))]
[(struct ast:expr:assign (_ lhs rhs))
(list (build-unwanted-type-syntax-expression lhs)
(build-unwanted-type-syntax-expression rhs))]
[(struct ast:expr:return (_ body))
(build-unwanted-type-syntax-expression body)]
[(struct ast:expr:tuple/select (_ _ arg))
(build-unwanted-type-syntax-expression arg)]
[(struct ast:expr:tuple (_ args))
(map build-unwanted-type-syntax-expression args)]
[(struct ast:expr:member (_ obj _ _ _))
(if (ast:expr? obj)
(build-unwanted-type-syntax-expression obj)
(list))]
[(struct ast:expr:new (_ obj type args))
(list (build-unwanted-type-syntax-expression obj)
(translate-type-for-syntax type)
(map (lambda (a)
(build-unwanted-type-syntax-expression (ast:named/arg-actual a)))
args))]
;; here are the two cases where the type already appears in the compiled code
[(struct ast:expr:cast (_ obj _))
(build-unwanted-type-syntax-expression obj)]
[(struct ast:expr:isa (_ obj _))
(build-unwanted-type-syntax-expression obj)]
[(struct ast:expr:unary/op (_ _ _ _ arg))
(build-unwanted-type-syntax-expression arg)]
[(struct ast:expr:binary/op (_ _ _ _ larg rarg))
(list (build-unwanted-type-syntax-expression larg)
(build-unwanted-type-syntax-expression rarg))]
[(struct ast:expr:if (_ cond then else))
(list (build-unwanted-type-syntax-expression cond)
(build-unwanted-type-syntax-expression then)
(build-unwanted-type-syntax-expression else))]
[(struct ast:expr:cond (_ clauses else))
(list (map (lambda (c)
(list (build-unwanted-type-syntax-expression (ast:cond/clause-test c))
(build-unwanted-type-syntax-expression (ast:cond/clause-result c))))
clauses)
(if else (build-unwanted-type-syntax-expression else) '()))]
[else '()]))
;; Yes, this is just part of the hack that gives us Check Syntax-correctness on all the types that
;; are not otherwise used in the compiled code.
(provide translate-type-for-syntax)
(define (translate-type-for-syntax type)
(define (real-translation type)
(match type
[(struct ast:type:object:iface (stx name))
(translate-iface-name type)]
[(struct ast:type:object:any (stx))
(translate-iface-name type)]
[(struct ast:type:primitive (stx name))
'()]
[(struct ast:type:function (stx arg ret))
(list (real-translation arg)
(real-translation ret))]
[(struct ast:type:tuple (stx args))
(map real-translation args)]))
(real-translation type))
)

View File

@ -1,139 +0,0 @@
(module translate-utils mzscheme
(require (all-except (lib "list.ss" "srfi" "1") any)
(lib "contract.ss")
"../../ast.ss"
"../../parameters.ss"
"../../tenv.ss"
"translate-parameters.ss")
(define stx-for-original-property (read-syntax #f (open-input-string "original")))
(provide/contract [at ((union (syntax/c any/c) false/c)
any/c
. -> .
(syntax/c any/c))]
[at-ctxt ((syntax/c any/c) . -> . (syntax/c any/c))])
(define (at stx expr)
(datum->syntax-object (current-compile-context) expr stx stx-for-original-property))
(define (at-ctxt stx)
(datum->syntax-object (current-compile-context) (syntax-e stx) stx stx-for-original-property))
(provide void-value)
(define void-value '())
(provide translate-function)
(define (translate-function stx name args body)
(define (wrapping-syntax arg body)
(if name
(at stx `(define (,(at-ctxt name) ,arg)
(let/ec last-k ,body)))
(at stx `(lambda (,arg)
(let/ec last-k ,body)))))
(if (= (length args) 1)
(wrapping-syntax (at-ctxt (ast:formal-name (car args)))
body)
(wrapping-syntax (at #f 'arg-tuple)
`(let-values ([,(map (lambda (a)
(at-ctxt (ast:formal-name a)))
args)
(apply values ,(at #f 'arg-tuple))])
,body))))
(provide translate-binding-clause)
(define (translate-binding-clause names value)
(define (grab-indices names)
(let loop ([names names]
[n 0]
[ret '()])
(cond
[(null? names)
(reverse ret)]
[(car names)
(loop (cdr names)
(+ n 1)
(cons `(list-ref arg-tuple ,n) ret))]
[else
(loop (cdr names)
(+ n 1)
ret)])))
(values (filter (lambda (n) n) names)
`(let ([arg-tuple ,(if (= (length names) 1)
`(list* ,value ())
value)])
,(cons 'values (grab-indices names)))))
(provide translate-iface-name translate-class-name translate-mixin-name translate-method-name
translate-field-getter-name translate-field-setter-name)
(define (translate-iface-name type)
(let ([name (if (ast:type:object:any? type)
(datum->syntax-object #f 'Any (ast-syntax type))
(ast:type:object:iface-name type))])
(at name (string->symbol (string-append (symbol->string (syntax-e name)) "<%>")))))
(define (translate-class-name class)
(at class (string->symbol (string-append (symbol->string (syntax-e class)) "%"))))
(define (translate-mixin-name mixin)
(at mixin (string->symbol (string-append (symbol->string (syntax-e mixin)) "-mixin"))))
(define (translate-method-name type name)
(at name (string->symbol (string-append (symbol->string (syntax-e (translate-iface-name type)))
"-"
(symbol->string (syntax-e name))))))
(define (translate-field-getter-name type name)
(at name (string->symbol (string-append (symbol->string (syntax-e (translate-iface-name type)))
"-"
(symbol->string (syntax-e name))
"-get"))))
(define (translate-field-setter-name type name)
(at name (string->symbol (string-append (symbol->string (syntax-e (translate-iface-name type)))
"-"
(symbol->string (syntax-e name))
"-set!"))))
(provide translate-static-method translate-static-field-getter translate-static-field-setter)
(define (translate-static-method name arg)
(if (current-mixin-argument-type)
(let ([type-entry (get-type-entry (current-mixin-argument-type))])
(if (s:member name
(map tenv:member-name (append (tenv:type-members type-entry)
(tenv:type-inherited type-entry)))
tenv-key=?)
(if arg
`(super ,(translate-method-name (current-mixin-argument-type) name) ,arg)
`(lambda (arg-tuple)
(super ,(translate-method-name (current-mixin-argument-type) name) arg-tuple)))
(if arg
`(,(at-ctxt name) ,arg)
(at-ctxt name))))
(if arg
`(,(at-ctxt name) ,arg)
(at-ctxt name))))
(define (translate-static-field-getter name)
(if (current-mixin-argument-type)
(let ([type-entry (get-type-entry (current-mixin-argument-type))])
(if (s:member name
(map tenv:member-name (append (tenv:type-members type-entry)
(tenv:type-inherited type-entry)))
tenv-key=?)
`(super ,(translate-field-getter-name (current-mixin-argument-type) name) ,void-value)
(at-ctxt name)))
(at-ctxt name)))
(define (translate-static-field-setter name arg)
(if (current-mixin-argument-type)
(let ([type-entry (get-type-entry (current-mixin-argument-type))])
(if (s:member name
(map tenv:member-name (append (tenv:type-members type-entry)
(tenv:type-inherited type-entry)))
tenv-key=?)
`(super ,(translate-field-setter-name (current-mixin-argument-type) name) ,arg)
`(begin (set! ,(at-ctxt name) ,arg)
,void-value)))
`(begin (set! ,(at-ctxt name) ,arg)
,void-value)))
)

View File

@ -1,159 +0,0 @@
(module translate mzscheme
(require (all-except (lib "list.ss" "srfi" "1") any)
(lib "contract.ss")
(lib "plt-match.ss")
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss"
"../typechecker/type-utils.ss"
"translate-class-utils.ss"
"translate-expression.ss"
"translate-parameters.ss"
"translate-unwanted-types.ss"
"translate-utils.ss")
(provide/contract [translate (((listof ast:defn?))
. ->* .
(any/c (listof (syntax/c any/c))))]
[translate-defn (ast:defn?
. -> .
(syntax/c any/c))])
(define (translate defns)
(let loop ([defns-to-go defns]
[syntaxes '()])
(cond
[(null? defns-to-go)
(values (build-unwanted-type-syntax defns)
( reverse syntaxes))]
[(ast:defn:subclass? (car defns-to-go))
(let ([mixin (find (lambda (d)
(and (ast:defn:mixin? d)
(tenv-key=? (ast:defn:mixin-name d)
(ast:defn:subclass-mixin (car defns-to-go)))))
defns)])
(loop (cdr defns-to-go) (cons (translate-subclass mixin (car defns-to-go)) syntaxes)))]
[else
(loop (cdr defns-to-go) (cons (translate-defn (car defns-to-go)) syntaxes))])))
(define (translate-iface-member-names name)
(let* ([iface (make-iface-type name name)]
[type-entry (get-type-entry iface)])
(let loop ([members (append (tenv:type-members type-entry) (tenv:type-inherited type-entry))]
[names '()])
(if (null? members)
(reverse names)
(if (ast:type:method? (tenv:member-type (car members)))
(loop (cdr members)
(cons (translate-method-name iface (tenv:member-name (car members)))
names))
(loop (cdr members)
(cons (translate-field-setter-name iface (tenv:member-name (car members)))
(cons (translate-field-getter-name iface (tenv:member-name (car members)))
names))))))))
(define (translate-defn defn)
(match defn
[(struct ast:defn:binding (stx names types value))
(let-values ([(bound-names body) (translate-binding-clause names (translate-expression value))])
(at stx `(define-values ,bound-names ,body)))]
[(struct ast:defn:function (stx name type args body))
(translate-function stx name args (translate-expression body))]
[(struct ast:defn:iface (stx name supers members))
(at stx `(define ,(translate-iface-name (make-iface-type name name))
(interface ,(if (null? supers)
(list (translate-iface-name (make-any-type #f)))
(map translate-iface-name supers))
,@(translate-iface-member-names name))))]
[(struct ast:defn:class (stx name selftype _ impls inits members exports))
(at stx `(define ,(translate-class-name name)
(class* object% ,(map translate-iface-name impls)
(inspect #f)
,(translate-inits inits)
,@(map translate-member members)
,@(translate-class-exports exports)
,(translate-impl-method impls)
,(translate-formatter name members)
(super-new))))]
[(struct ast:defn:mixin (stx name _ _ _ _ _ _ _ _ _ _))
;; just a dummy definition to get the bindings set up correctly
(at stx `(define ,(translate-mixin-name name)
'()))]
[else (raise-read-error-with-stx
"Haven't translated that type of definition yet."
(ast-syntax defn))]))
(define (translate-subclass mixin-defn defn)
(match (list mixin-defn defn)
[(list (struct ast:defn:mixin (mstx mname selftype arg-type _ impls inits withs super-new members-before members-after exports))
(struct ast:defn:subclass (stx name base mixin)))
(parameterize ([current-mixin-argument-type arg-type])
(let* ([base-entry (get-class-entry base)]
[base-types (cons (tenv:class-sub-type base-entry)
(tenv:class-impls base-entry))])
(at stx `(define ,(translate-class-name name)
(class* ,(translate-class-name base) ,(map translate-iface-name impls)
(inspect #f)
,(translate-inits inits)
,@(map translate-member members-before)
,(translate-super-new super-new)
,@(map translate-member members-after)
,@(translate-subclass-exports base-types exports)
,(translate-impl-method impls)
,(translate-formatter name (append members-before members-after)))))))]))
(define (translate-impl-method impls)
(let ([right-define (if (current-mixin-argument-type) 'define/override 'define/public)])
`(,right-define (implements? iface)
(mz:ormap (lambda (i)
(interface-extension? i iface))
(list* ,@(map translate-iface-name impls) '())))))
(define (translate-formatter name members)
(let ([right-define (if (current-mixin-argument-type) 'define/override 'define/public)])
`(begin
(,right-define (format-class-name)
,(format "~a" (syntax-e name)))
(,right-define (format-class renderer indent)
(format "~a {~a}"
(format-class-name)
,(cons 'string-append
(let ([printable-members (filter (lambda (m)
(not (ast:class/member:method? m)))
members)]
[printable-smembers (if (current-mixin-argument-type)
(filter-map (lambda (m)
(if (not (ast:type:method? (tenv:member-type m)))
(tenv:member-name m)
#f))
(tenv:type-members (get-type-entry (current-mixin-argument-type))))
'())]
;; how much more do we want the members indented? Let's try 2 spaces more.
[indent-delta 2])
(if (and (null? printable-members)
(null? printable-smembers))
'("")
(fold-right (lambda (m l)
(list* "\n" (translate-super-member-formatter m indent-delta) l))
(fold-right (lambda (m l)
(list* "\n" (translate-member-formatter m indent-delta) l))
'("\n" (make-string indent #\space))
printable-members)
printable-smembers)))))))))
(define (translate-member-formatter member indent-delta)
(let ([name (ast:class/member-name member)])
`(format "~a~a = ~a;"
(make-string (+ indent ,indent-delta) #\space)
(quote ,(syntax-e name))
;; the 3 is for " = "
(renderer ,name (+ indent ,(+ indent-delta (string-length (symbol->string (syntax-e name))) 3))))))
(define (translate-super-member-formatter name indent-delta)
`(format "~a~a = ~a;"
(make-string (+ indent ,indent-delta) #\space)
(quote ,(syntax-e name))
;; as before, the 3 is for " = "
(renderer ,(translate-static-field-getter name)
(+ indent ,(+ indent-delta (string-length (symbol->string (syntax-e name))) 3)))))
)

View File

@ -1,48 +0,0 @@
(module program-tests mzscheme
(require (lib "contract.ss")
(planet "test.ss" ("schematics" "schemeunit.plt" 1 1))
(prefix srfi1: (lib "1.ss" "srfi"))
"../../top.ss"
)
(provide/contract [program-tests test-suite?])
(define program-files
(list "examples/BoundedStack.honu"
"examples/EvenOddClass.honu"
"examples/List.honu"
"examples/Y.honu"
"examples/bind-tup-top.honu"
"examples/cond-test.honu"
"examples/even-odd.honu"
"examples/exprs.honu"
"examples/point.honu"
"examples/struct.honu"
"examples/tup-bind.honu"
; "examples/types-error.honu"
"examples/types.honu"
; "examples/nonexistent.honu"
))
(define-assertion (assert-test-file program-file)
(let* ([results (test-file program-file)]
[indices (srfi1:iota (length results))]
[errors
(srfi1:filter-map (lambda (result index) (if result #f index))
results indices)])
(if (null? errors)
#t
(with-assertion-info
(['error-indices errors])
(fail-assertion)))))
(define (make-program-test program-file)
(make-test-case program-file (assert-test-file program-file)))
(define program-tests
(apply make-test-suite
"Honu"
(map make-program-test program-files)))
)

View File

@ -1,38 +0,0 @@
(module typechecker-tests mzscheme
(require (lib "contract.ss")
(planet "test.ss" ("schematics" "schemeunit.plt" 1 1))
(prefix srfi13: (lib "13.ss" "srfi"))
"../typechecker/typecheck-expression.ss"
"../../tenv.ss"
"../../ast.ss"
)
(provide/contract [typechecker-tests test-suite?])
(define non-void-in-sequence-test
(make-test-case "Non-void expression in a sequence"
(assert-exn
(lambda (exn)
(srfi13:string-contains (exn-message exn) "void"))
(lambda ()
(typecheck-expression
(wrap-lenv) #f
(make-ast:expr:sequence
#'()
(list (make-ast:expr:literal #'() (make-ast:type:primitive #'() 'int) #'5))
(make-ast:expr:literal #'() (make-ast:type:primitive #'() 'int) #'4)))))))
(define error-message-tests
(make-test-suite
"Error messages"
non-void-in-sequence-test
))
(define typechecker-tests
(make-test-suite
"Typechecker"
error-message-tests
))
)

View File

@ -1,100 +0,0 @@
(module general mzscheme
(require (prefix srfi1: (lib "list.ss" "srfi" "1"))
(lib "list.ss"))
(provide fold-with-rest
get-first-non-unique-name
map-and-fold
map-two-values
map-values
partition-first
unique?
curry
false?)
(define (map-values-rev-accs f lists accs)
(cond [(andmap empty? lists) (apply values (map reverse accs))]
[(ormap empty? lists) (error 'map-values "expects lists of equal length")]
[else (call-with-values (lambda () (apply f (map first lists)))
(lambda vs (map-values-rev-accs f (map rest lists) (map cons vs accs))))]))
(define (map-values f . lists)
(cond [(empty? lists) (error 'map-values "expects 1 or more input lists")]
[(ormap empty? lists) (error 'map-values "expects non-empty lists")]
[else
(call-with-values (lambda () (apply f (map first lists)))
(lambda vs (map-values-rev-accs f (map rest lists) (map list vs))))]))
(define (identifier<? a b)
(string<? (symbol->string (syntax-e a))
(symbol->string (syntax-e b))))
(define (get-first-non-unique-name lst)
(let loop ([lst (quicksort lst identifier<?)])
(cond
[(null? lst) #f]
[(null? (cdr lst)) #f]
[(bound-identifier=? (car lst) (cadr lst))
;; since quicksort isn't stable, just return the first
(car lst)]
[else #f])))
(define (fold-with-rest f init l)
(if (null? l)
init
(fold-with-rest f (f (car l) (cdr l) init) (cdr l))))
(define (unique? cs)
(fold-with-rest (lambda (c cs acc)
(and acc
(not (member c cs))))
#t cs))
(define (get-names ds p f)
(srfi1:filter-map (lambda (defn)
(and (p defn)
(f defn)))
ds))
(define (map-and-fold f i l)
(let loop ((l l)
(mapped '())
(folded i))
(if (null? l)
(values (reverse mapped) folded)
(let-values ([(res folded) (f (car l) folded)])
(loop (cdr l)
(cons res mapped)
folded)))))
(define (map-two-values f . lists)
(let loop ((lists lists)
(map1 '())
(map2 '()))
(if (ormap empty? lists)
(values (reverse map1) (reverse map2))
(let-values ([(m1 m2) (apply f (map car lists))])
(loop (map cdr lists)
(cons m1 map1)
(cons m2 map2))))))
(define (partition-first f lis)
(let loop ([lis lis]
[passed '()])
(cond
[(null? lis)
(values #f (reverse passed))]
[(f (car lis))
(values (car lis) (append (reverse passed) (cdr lis)))]
[else
(loop (cdr lis) (cons (car lis) passed))])))
(define (curry f . args)
(lambda rest
(apply f (append args rest))))
(define (false? v)
(eq? v #f))
)

View File

@ -1,112 +0,0 @@
(module test mzscheme
(require (lib "list.ss"))
#|
Test case and test suite macros:
Expressions:
(test-case NAME EXPR PREDICATE)
(test-suite NAME CASE ...)
Definitions:
(define-test-case NAME EXPR PREDICATE)
(define-test-suite NAME CASES ...)
|#
(define (report? obj) (or (void? obj) (list? obj)))
(define (exn-sexp exn)
`(error ,(exn-message exn)))
(define-for-syntax (syntax-rest stx)
(syntax-case stx () [(_ . REST) #'REST]))
(define-for-syntax (translate-predicate stx)
(syntax-case stx (equal: error: pred:)
[(equal: VALUE)
#`(lambda (name expr thunk)
(lambda ()
(with-handlers ([(lambda (exn) #t)
(lambda (exn) `(,name : ,expr raised ,(exn-sexp exn)))])
(let* ([result (thunk)])
(with-handlers ([(lambda (exn) #t)
(lambda (exn)
`(,name : expected value VALUE raised ,(exn-sexp exn)))])
(let* ([expected VALUE])
(if (equal? result expected)
(void)
`(,name : ,expr = ,result != ,expected))))))))]
[error:
#`(lambda (name expr thunk)
(lambda ()
(with-handlers ([(lambda (exn) #t) (lambda (exn) (void))])
(let* ([result (thunk)])
`(,name : ,expr = ,result but expected error)))))]
[(error: PRED)
#`(lambda (name expr thunk)
(lambda ()
(with-handlers
([(lambda (exn) #t)
(lambda (exn)
(with-handlers
([(lambda (exn) #t)
(lambda (exn)
`(,name : predicate PRED raised ,(exn-sexp exn)))])
(if (PRED exn)
(void)
`(,name : ,expr raised ,(exn-sexp exn) which failed PRED))))])
(let* ([result (thunk)])
`(,name : ,expr = ,result but expected error)))))]
[(pred: PRED)
#`(lambda (name expr thunk)
(lambda ()
(with-handlers ([(lambda (exn) #t)
(lambda (exn) `(,name : ,expr raised ,(exn-sexp exn)))])
(let* ([result (thunk)])
(with-handlers ([(lambda (exn) #t)
(lambda (exn)
`(,name : predicate PRED raised ,(exn-sexp exn)))])
(if (PRED result)
(void)
`(,name : ,expr = ,result failed PRED)))))))]
))
(define-for-syntax (translate-test-case stx)
(syntax-case stx ()
[(NAME EXPR PREDICATE)
#`(#,(translate-predicate #'PREDICATE) 'NAME 'EXPR (lambda () EXPR))]))
(define-for-syntax (translate-test-suite stx)
(syntax-case stx ()
[(NAME CASE ...)
#`(let* ([cases (list CASE ...)])
(lambda ()
(let* ([reports (map (lambda (case) (case)) cases)]
[errors (filter (lambda (report) (not (void? report))) reports)])
(cond [(null? errors) (void)]
[(= (length errors) 1) (cons 'NAME (first errors))]
[else (cons 'NAME (cons ': errors))]))))]))
(define-for-syntax (translate-define-test-case stx)
(syntax-case stx ()
[(NAME . _) #`(define NAME #,(translate-test-case stx))]))
(define-for-syntax (translate-define-test-suite stx)
(syntax-case stx ()
[(NAME . _) #`(define NAME #,(translate-test-suite stx))]))
(define-syntax (test-case stx)
(translate-test-case (syntax-rest stx)))
(define-syntax (test-suite stx)
(translate-test-suite (syntax-rest stx)))
(define-syntax (define-test-case stx)
(translate-define-test-case (syntax-rest stx)))
(define-syntax (define-test-suite stx)
(translate-define-test-suite (syntax-rest stx)))
(provide report? test-case test-suite define-test-case define-test-suite)
)

View File

@ -1,279 +0,0 @@
(module type-utils mzscheme
(require (prefix srfi1: (lib "list.ss" "srfi" "1"))
(lib "contract.ss")
(lib "plt-match.ss")
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss")
(provide make-null-type make-any-type make-void-type make-error-type make-top-type make-bottom-type
make-int-type make-string-type make-char-type make-bool-type make-float-type
make-tuple-type make-func-type make-method-type make-iface-type)
(define (make-null-type stx)
(make-ast:type:object:null stx))
(define (make-any-type stx)
(make-ast:type:object:any stx))
;; if you want non-strict void context method bodies, change this to
;; (make-ast:type:top stx)
;; if you want to make sure that a value of "void" type is returned, do
;; (make-ast:type:tuple stx '())
(define (make-void-type stx)
(make-ast:type:tuple stx (list)))
(define (make-error-type stx)
(make-ast:type:bot stx))
(define (make-top-type stx)
(make-ast:type:top stx))
(define (make-bottom-type stx)
(make-ast:type:bot stx))
(define (make-tuple-type stx args)
(if (and (not (null? args))
(null? (cdr args)))
(car args) ;; just return the type if there's only one.
(make-ast:type:tuple stx args)))
(define (make-func-type stx arg ret)
(make-ast:type:function stx arg ret))
(define (make-method-type stx disp arg ret)
(make-ast:type:method stx disp arg ret))
(define (make-iface-type stx name)
(make-ast:type:object:iface stx name))
(define (make-int-type stx)
(make-ast:type:primitive stx 'int))
(define (make-string-type stx)
(make-ast:type:primitive stx 'string))
(define (make-char-type stx)
(make-ast:type:primitive stx 'char))
(define (make-bool-type stx)
(make-ast:type:primitive stx 'bool))
(define (make-float-type stx)
(make-ast:type:primitive stx 'float))
(provide printable-type)
(define (printable-type t)
(match t
[(struct ast:type:top (_))
"(no info)"]
[(struct ast:type:bot (_))
"'a"]
[(struct ast:type:primitive (_ name))
(symbol->string name)]
[(struct ast:type:tuple (_ args))
(if (null? args)
"void"
(string-append "<"
(srfi1:fold (lambda (t i)
(string-append i ", " (printable-type t)))
(printable-type (car args))
(cdr args))
">"))]
[(struct ast:type:partial/tuple (_ slot type))
(format "tuple of size >= ~a where the type in slot ~a is ~a"
slot slot (printable-type type))]
[(struct ast:type:function (_ arg ret))
(if (ast:type:function? arg)
(string-append "<" (printable-type arg) "> -> " (printable-type ret))
(string-append (printable-type arg) " -> " (printable-type ret)))]
[(struct ast:type:method (_ disp arg ret))
(string-append "[" (printable-type disp) "] "
(printable-type arg) " -> " (printable-type ret))]
[(struct ast:type:object:iface (_ name))
(symbol->string (syntax-e name))]
[(struct ast:type:object:any (_))
"Any"]
[(struct ast:type:object:null (_))
"null"]))
(provide type-valid?)
(define (type-valid? t)
(match t
[(struct ast:type:object:any (_)) #t]
[(struct ast:type:primitive (stx name))
(case name
[(int float char string bool) #t]
[else (raise-read-error-with-stx
(format "Unexpected primitive type ~a" name)
stx)])]
[(struct ast:type:object:iface (stx name))
(let ([tentry (get-tenv-entry name)])
(and tentry (tenv:type? tentry)))]
[(struct ast:type:tuple (_ args))
(andmap (lambda (t)
(type-valid? t))
args)]
[(struct ast:type:function (_ arg ret))
(and (type-valid? arg)
(type-valid? ret))]
[(struct ast:type:method (_ disp arg ret))
(and (type-valid? disp)
(type-valid? arg)
(type-valid? ret))]))
(provide type-equal?)
(define (type-equal? t1 t2)
(cond
;; first all the easy ones
[(and (ast:type:top? t1)
(ast:type:top? t2))
#t]
[(and (ast:type:bot? t1)
(ast:type:bot? t2))
#t]
[(and (ast:type:object:any? t1)
(ast:type:object:any? t2))
#t]
[(and (ast:type:object:null? t1)
(ast:type:object:null? t2))
#t]
;; primitive types are equal if their names are equal.
[(and (ast:type:primitive? t1)
(ast:type:primitive? t2))
(eqv? (ast:type:primitive-name t1)
(ast:type:primitive-name t2))]
;; same for ifaces
[(and (ast:type:object:iface? t1)
(ast:type:object:iface? t2))
(tenv-key=? (ast:type:object:iface-name t1)
(ast:type:object:iface-name t2))]
;; function, dispatch types are equal if their component types are.
[(and (ast:type:function? t1)
(ast:type:function? t2))
(and (type-equal? (ast:type:function-input t1) (ast:type:function-input t2))
(type-equal? (ast:type:function-output t1) (ast:type:function-output t2)))]
[(and (ast:type:method? t1)
(ast:type:method? t2))
(and (type-equal? (ast:type:method-receiver t1) (ast:type:method-receiver t2))
(type-equal? (ast:type:method-input t1) (ast:type:method-input t2))
(type-equal? (ast:type:method-output t1) (ast:type:method-output t2)))]
;; tuple types are equal if they have the same number of components and
;; their components are pairwise equal
[(and (ast:type:tuple? t1)
(ast:type:tuple? t2))
(let ([t1-args (ast:type:tuple-elems t1)]
[t2-args (ast:type:tuple-elems t2)])
(and (= (length t1-args) (length t2-args))
(andmap (lambda (t1 t2)
(type-equal? t1 t2))
t1-args t2-args)))]
;; for select types, they must be the same type on the same slot
;; (should we even get here?)
[(and (ast:type:partial/tuple? t1)
(ast:type:partial/tuple? t2))
(and (= (ast:type:partial/tuple-position t1) (ast:type:partial/tuple-position t2))
(type-equal? (ast:type:partial/tuple-elem t1) (ast:type:partial/tuple-elem t2)))]
[else #f]))
;; assumes either Any or some type identifier
(define (get-type-name t)
(cond
[(ast:type:object:iface? t)
(ast:type:object:iface-name t)]
[(ast:type:object:any? t)
#'Any]))
;; is t1 a _direct_ subtype of t2?
(define (Subtype_P t1 t2)
(let ([type-entry (get-type-entry t1)])
(match type-entry
[(struct tenv:type (_ supers _ _))
(let ([super-names (map get-type-name supers)])
(srfi1:s:member (get-type-name t2) super-names tenv-key=?))])))
;; is t1 a (ref-trans-closed) subtype of t2?
(provide <:_P)
(define (<:_P t1 t2)
(cond
;; if t1 = t2, t1 <:_P t2
[(type-equal? t1 t2)
#t]
;; if t1 is the bottom of the type lattice, then it trivially holds
[(ast:type:bot? t1)
#t]
;; if t2 is the top of the type lattice, then it trivially holds
[(ast:type:top? t2)
#t]
;; if t1 =/= t2 and they're both primitives, then they cannot be equal.
[(and (ast:type:primitive? t1)
(ast:type:primitive? t2))
#f]
;; for function types...
[(and (ast:type:function? t1)
(ast:type:function? t2))
;; the arg is contravariant and the ret is covariant
(and (<:_P (ast:type:function-input t2) (ast:type:function-input t1))
(<:_P (ast:type:function-output t1) (ast:type:function-output t2)))]
;; for dispatch types...
[(and (ast:type:method? t1)
(ast:type:method? t2))
;; dispatch args must be co-, regular args contra-, and ret co-
(and (<:_P (ast:type:method-receiver t1) (ast:type:method-receiver t2))
(<:_P (ast:type:method-input t2) (ast:type:method-input t1))
(<:_P (ast:type:method-output t1) (ast:type:method-output t2)))]
;; for tuple types...
[(and (ast:type:tuple? t1)
(ast:type:tuple? t2))
(let ([t1-args (ast:type:tuple-elems t1)]
[t2-args (ast:type:tuple-elems t2)])
;; the lengths must be equal...
(and (= (length t1-args) (length t2-args))
;; and each component must be a subtype (covariantly)
(andmap (lambda (t1 t2)
(<:_P t1 t2))
t1-args t2-args)))]
;; for a select statement (s, t), we have that a tuple type (t_1 ... t_n) is <:_P t if
;; if t_s <:_P t.
[(and (ast:type:tuple? t1)
(ast:type:partial/tuple? t2))
(let ([t2-slot (ast:type:partial/tuple-position t2)]
[t1-args (ast:type:tuple-elems t1)])
(and (<= t2-slot (length t1-args))
;; we have to subtract one from t2-slot because list-ref is zero-based
(<:_P (list-ref t1-args (- t2-slot 1)) (ast:type:partial/tuple-elem t2))))]
;; not sure if this is necessary. Hmm.
[(and (ast:type:partial/tuple? t1)
(ast:type:partial/tuple? t2))
(and (= (ast:type:partial/tuple-position t1) (ast:type:partial/tuple-position t2))
(<:_P (ast:type:partial/tuple-elem t1) (ast:type:partial/tuple-elem t2)))]
;; the bottom of the iface lattice is <:_P either the iface-top or
;; any iface
[(and (ast:type:object:null? t1)
(or (ast:type:object:iface? t2)
(ast:type:object:any? t2)))
#t]
;; any iface type is <:_P the iface-top (iface-bot already caught above)
[(and (ast:type:object:iface? t1)
(ast:type:object:any? t2))
#t]
;; if two (non-equal) iface types...
[(and (ast:type:object:iface? t1)
(ast:type:object:iface? t2))
(if (Subtype_P t1 t2)
;; return true if it's a direct subtype relation
#t
(let ([type-entry (get-type-entry t1)])
;; if any of the direct supertypes of t1 is a subtype of t2,
;; then t1 is also
(ormap (lambda (t)
(<:_P t t2))
(tenv:type-supers type-entry))))]
[else #f]))
(provide/contract [type-member-names (ast:type? . -> . (listof identifier?))])
(define (type-member-names type)
(let* ([entry (get-type-entry type)])
(map tenv:member-name
(append (tenv:type-members entry)
(tenv:type-inherited entry)))))
(provide iface-name)
(define (iface-name type)
(match type
[(struct ast:type:object:any (_)) #'Any]
[(struct ast:type:object:iface (_ name)) name]))
(provide raise-honu-type-error)
(define (raise-honu-type-error stx expected received)
(raise-read-error-with-stx
(format "Expected type ~a, got type ~a"
(printable-type expected)
(printable-type received))
stx))
)

View File

@ -1,273 +0,0 @@
(module typecheck-class-utils mzscheme
(require (lib "list.ss" "srfi" "1")
(lib "plt-match.ss")
(lib "struct.ss")
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss"
"../tools/general.ss"
"typecheck-expression.ss"
"typecheck-parameters.ss"
"type-utils.ss")
(provide extend-lenv-with-type-members typecheck-members typecheck-supernew typecheck-exports)
(define (typecheck-exports lenv selftype init-impls exports)
(let loop ([impls init-impls]
[exports exports])
(cond
[(and (null? exports)
(null? impls))
(if (not (s:member selftype init-impls (lambda (t1 t2) (type-equal? t1 t2))))
(raise-read-error-with-stx
(format "No export statement for self type ~a"
(printable-type selftype))
(ast-syntax selftype))
;; the selftype was already covered by one of the implemented types, so
;; we can just stop.
(void))]
[(null? exports)
(raise-read-error-with-stx
(format "No export statement for implemented type ~a"
(printable-type (car impls)))
(ast-syntax (car impls)))]
[(null? impls)
(if (s:member selftype init-impls (lambda (t1 t2) (type-equal? t1 t2)))
(raise-read-error-with-stx
(format "Extra export statement for unimplemented type ~a"
(printable-type (ast:export-type (car exports))))
(ast-syntax (car exports)))
(let-values ([(matched non-matches) (partition-first (lambda (e)
(type-equal? (ast:export-type e) selftype))
exports)])
(if (not matched)
(raise-read-error-with-stx
(format "No export statement for self type ~a"
(printable-type selftype))
(ast-syntax selftype))
(let ([type-entry (get-type-entry selftype)])
(typecheck-export lenv type-entry matched)
(if (not (null? non-matches))
(raise-read-error-with-stx
(format "Extra export statement for unimplemented type ~a"
(printable-type (ast:export-type (car exports))))
(ast-syntax (car exports)))
(void))))))]
[else
(let-values ([(matched non-matches) (partition-first (lambda (t)
(type-equal? (ast:export-type (car exports)) t))
impls)])
(if (not matched)
(raise-read-error-with-stx
(format "Extra export statement for unimplemented type ~a"
(ast:export-type (car exports)))
(ast-syntax (car exports)))
(let* ([type-entry (get-type-entry matched)]
[export (car exports)])
(typecheck-export lenv type-entry export)
(loop non-matches (cdr exports)))))])))
(define (typecheck-export lenv type-entry export)
;; make sure to use both defined members and inherited members here
(let loop ([type-members (append (tenv:type-members type-entry) (tenv:type-inherited type-entry))]
[export-binds (ast:export-members export)])
(cond
[(and (null? type-members)
(null? export-binds))
(void)]
[(null? type-members)
(raise-read-error-with-stx
(format "No member named ~a in type ~a"
(printable-key (ast:export/member-external (car export-binds)))
(printable-type (ast:export-type export)))
(ast:export/member-external (car export-binds)))]
[(null? export-binds)
(raise-read-error-with-stx
(format "Member ~a of type ~a was not exported"
(printable-key (tenv:member-name (car type-members)))
(printable-type (ast:export-type export)))
(ast-syntax export))]
[else
(let-values ([(matched non-matches) (partition-first (lambda (m)
(tenv-key=? (tenv:member-name m)
(ast:export/member-external (car export-binds))))
type-members)]
[(lenv-entry) (lenv (ast:export/member-internal (car export-binds)))])
(cond
[(not lenv-entry)
(raise-read-error-with-stx
(format "No static member named ~a"
(printable-key (ast:export/member-internal (car export-binds))))
(ast:export/member-internal (car export-binds)))]
[(not matched)
(raise-read-error-with-stx
(format "No member named ~a in type ~a"
(printable-key (ast:export/member-external (car export-binds)))
(printable-type (ast:export-type export)))
(ast:export/member-external (car export-binds)))]
;; if it's a method, then allow exporting a subtype
[(ast:type:method? (tenv:member-type matched))
(if (<:_P lenv-entry (tenv:member-type matched))
(loop non-matches (cdr export-binds))
(raise-read-error-with-stx
(format "Exported static member ~a has type ~a which is not a subtype of ~a's type ~a"
(printable-key (ast:export/member-internal (car export-binds)))
(printable-type lenv-entry)
(printable-key (tenv:member-name matched))
(printable-type (tenv:member-type matched)))
(ast:export/member-internal (car export-binds))))]
;; for fields, we just do invariance until we get read-only fields
[else
(if (type-equal? lenv-entry (tenv:member-type matched))
(loop non-matches (cdr export-binds))
(raise-read-error-with-stx
(format "Exported static member ~a has type ~a which is not the same type as ~a's type ~a"
(printable-key (ast:export/member-internal (car export-binds)))
(printable-type lenv-entry)
(printable-key (tenv:member-name matched))
(printable-type (tenv:member-type matched)))
(ast:export/member-internal (car export-binds))))]))])))
(define (extend-lenv-with-type-members lenv type)
(let ([type-entry (get-type-entry type)])
(fold (lambda (m e)
(extend-fenv (tenv:member-name m)
(tenv:member-type m)
e))
lenv
(tenv:type-members type-entry))))
(define (typecheck-supernew lenv withs supernew)
(let loop ([withs withs]
[args (ast:super-new-args supernew)]
[checked-args '()])
(cond
[(and (null? withs)
(null? args))
(copy-struct ast:super-new supernew
[ast:super-new-args (reverse checked-args)])]
[(null? withs)
(raise-read-error-with-stx
(format "No expected init slot declaration for super arg ~a"
(printable-key (ast:named/arg-name (car args))))
(ast:named/arg-name (car args)))]
[(null? args)
(raise-read-error-with-stx
(format "Expected init slot ~a not used as super arg"
(printable-key (ast:formal-name (car withs))))
(ast:formal-name (car withs)))]
[else
(let-values ([(matched non-matches) (partition-first (lambda (w)
(tenv-key=? (ast:formal-name w)
(ast:named/arg-name (car args))))
withs)])
(if (not matched)
(raise-read-error-with-stx
(format "No expected init slot declaration for super arg ~a"
(printable-key (ast:named/arg-name (car args))))
(ast:named/arg-name (car args)))
(let ([first-arg (car args)])
(let-values ([(e1 t1) (typecheck-expression lenv
(ast:formal-type matched)
(ast:named/arg-actual first-arg))])
(loop non-matches
(cdr args)
(cons (copy-struct ast:named/arg first-arg
[ast:named/arg-actual e1])
checked-args))))))])))
(define (typecheck-members lenv selftype members)
(let loop ([members members]
[lenv lenv]
[ret '()])
(cond
[(null? members)
(values (reverse ret) lenv)]
[(or (ast:class/member:field/formal? (car members))
(ast:class/member:field? (car members)))
(let ([member (typecheck-member lenv selftype (car members))])
(loop (cdr members)
(extend-fenv (get-class-member-name (car members))
(get-class-member-type selftype (car members))
lenv)
(cons member ret)))]
[(ast:class/member:method? (car members))
(let-values ([(methods remainder) (span ast:class/member:method? members)])
(let ([lenv (fold (lambda (m lenv)
(extend-fenv (get-class-member-name m)
(get-class-member-type selftype m)
lenv))
lenv
methods)])
(loop remainder
lenv
;; I only through the reverse in to keep the order the same.
;; it doesn't really matter.
(append (reverse (map (lambda (m)
(typecheck-member lenv selftype m))
methods))
ret))))])))
(define (typecheck-member lenv selftype member)
(match member
[(struct ast:class/member:field/formal (stx name type value))
(if (not (type-valid? type))
(raise-read-error-with-stx
"Type of init field is undefined"
(ast-syntax type)))
(if value
(let-values ([(e1 t1) (typecheck-expression lenv type value)])
(copy-struct ast:class/member:field/formal member
[ast:class/member:field/formal-default e1]))
member)]
[(struct ast:class/member:field (stx name type value))
(if (not (type-valid? type))
(raise-read-error-with-stx
"Type of field is undefined"
(ast-syntax type)))
(let-values ([(e1 t1) (typecheck-expression lenv type value)])
(copy-struct ast:class/member:field member
[ast:class/member:field-default e1]))]
[(struct ast:class/member:method (stx name type args body))
(if (not (type-valid? type))
(raise-read-error-with-stx
"Return type of method is undefined"
(ast-syntax type)))
(for-each (lambda (t)
(if (not (type-valid? t))
(raise-read-error-with-stx
"Type of method argument is undefined"
(ast-syntax t))))
(map ast:formal-type args))
(let-values ([(e1 t1) (parameterize ([current-return-type type])
(typecheck-expression (fold (lambda (arg fenv)
(extend-fenv (ast:formal-name arg)
(ast:formal-type arg)
fenv))
lenv args)
type body))])
(copy-struct ast:class/member:method member
[ast:class/member:method-body e1]))]))
(define (get-class-member-name member)
(match member
[(struct ast:class/member:field/formal (stx name type value)) name]
[(struct ast:class/member:field (stx name type value)) name]
[(struct ast:class/member:method (stx name type args body)) name]))
(define (get-class-member-type exptype member)
(match member
[(struct ast:class/member:field/formal (stx name type value))
type]
[(struct ast:class/member:field (stx name type value))
type]
[(struct ast:class/member:method (stx name type args body))
(make-method-type stx exptype
(make-tuple-type stx (map ast:formal-type args))
type)]))
)

View File

@ -1,677 +0,0 @@
(module typecheck-expression mzscheme
(require (all-except (lib "list.ss" "srfi" "1") any)
(lib "contract.ss")
(lib "plt-match.ss")
(lib "struct.ss")
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss"
"../tools/general.ss"
"typecheck-parameters.ss"
"type-utils.ss")
(provide/contract [typecheck-expression ((((syntax/c symbol?) . -> . (union ast:type? false/c))
(union ast:type? false/c)
ast:expr?)
. ->* .
(ast:expr?
ast:type?))])
;; lenv : ((syntax/c symbol?) . -> . (union ast:type false/c))
;; lexical environment (includes top-level bindings and
;; binding for #'this if inside class or mixin)
;; ctype : (union ast:type? false/c)
;; type of context for expression
;; expr : ast:expr?
;; expression to typecheck
(define (typecheck-expression lenv ctype expr)
(match expr
[(struct ast:expr:self (stx))
(cond
[(lenv #'this) => (lambda (t)
(if (<:_P t ctype)
(values expr t)
(raise-honu-type-error stx ctype t)))]
[else (raise-read-error-with-stx
"Found use of 'this' outside of class or mixin"
stx)])]
[(struct ast:expr:tuple/select (stx slot arg))
;; changed to have a special "select" type that does the following:
;; (type-select n t) <:_P (type-tuple args) if
;; a) (>= (length args) n)
;; b) (type-equal? (list-ref args (- n 1)) t)
;; c) (list-ref args m) <:_P (type-top) for all m =/= n (vacuously true)
(let-values ([(e1 t1) (typecheck-expression lenv (make-ast:type:partial/tuple stx slot ctype) arg)])
(if (not (ast:type:tuple? t1))
(raise-read-error-with-stx "Tried to use select with non-tuple expression" stx))
(let ([etype (list-ref (ast:type:tuple-elems t1) (- slot 1))])
(values (copy-struct ast:expr:tuple/select expr
[ast:expr:tuple/select-arg e1])
etype)))]
[(struct ast:expr:var (stx name))
(cond
[(lenv name) => (lambda (t)
(if (<:_P t ctype)
(values expr t)
(raise-honu-type-error stx ctype t)))]
[else (raise-read-error-with-stx
(format "Unbound variable ~a" (syntax-e name))
stx)])]
[(struct ast:expr:assign (stx lhs rhs))
;; the context type for the lhs is a vacuous one.
(let*-values ([(e1 t1) (typecheck-expression lenv (make-top-type (ast-syntax lhs)) lhs)]
[(e2 t2) (typecheck-expression lenv t1 rhs)])
(let ([void-type (make-void-type stx)])
(if (<:_P void-type ctype)
(values (copy-struct ast:expr:assign expr
[ast:expr:assign-lhs e1]
[ast:expr:assign-rhs e2])
void-type)
(raise-honu-type-error stx ctype void-type))))]
[(struct ast:expr:apply (stx func arg))
(let*-values ([(e1 t1) (typecheck-expression lenv (make-func-type (ast-syntax func)
(make-bottom-type (ast-syntax func))
ctype) func)]
[(e2 t2) (typecheck-expression lenv (ast:type:function-input t1) arg)])
(let ([ret-type (ast:type:function-output t1)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:apply expr
[ast:expr:apply-func e1]
[ast:expr:apply-arg e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(struct ast:expr:literal (stx type value))
(if (<:_P type ctype)
(values expr type)
(raise-honu-type-error stx ctype type))]
[(struct ast:expr:unary/op (stx op op-stx _ arg))
(case op
[(not)
(let-values ([(e1 t1) (typecheck-expression lenv (make-bool-type (ast-syntax arg)) arg)])
(let ([ret-type (make-bool-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:unary/op expr
[ast:expr:unary/op-rator-type t1]
[ast:expr:unary/op-arg e1])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(minus)
(let-values ([(e1 t1) (typecheck-expression lenv (make-top-type (ast-syntax arg)) arg)])
(if (not (ast:type:primitive? t1))
(raise-read-error-with-stx
"Invalid type for argument to unary minus"
(ast-syntax arg))
(let ([ret-type (case (ast:type:primitive-name t1)
[(int) (make-int-type (ast-syntax arg))]
[(float) (make-float-type (ast-syntax arg))]
[else (raise-read-error-with-stx
(format "Argument to unary minus must be int or float type, got ~a"
(printable-type t1))
(ast-syntax arg))])])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:unary/op expr
[ast:expr:unary/op-rator-type t1]
[ast:expr:unary/op-arg e1])
ret-type)
(raise-honu-type-error stx ctype ret-type)))))]
[else
(raise-read-error-with-stx
"Unknown operator"
op-stx)])]
[(struct ast:expr:binary/op (stx op op-stx _ larg rarg))
(case op
;; binary boolean operators
[(or and)
(let-values ([(e1 t1) (typecheck-expression lenv (make-bool-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-bool-type (ast-syntax rarg)) rarg)])
(let ([ret-type (make-bool-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type (make-bool-type (ast-syntax larg))]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(clseq)
(let-values ([(e1 t1) (typecheck-expression lenv (make-any-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-any-type (ast-syntax rarg)) rarg)])
(let ([ret-type (make-bool-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type (make-any-type (ast-syntax larg))]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(equal neq)
(let-values ([(e1 t1) (typecheck-expression lenv (make-top-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-top-type (ast-syntax rarg)) rarg)])
(let ([ret-type (make-bool-type stx)]
[arg-type (cond
[(and (<:_P t1 (make-any-type (ast-syntax larg)))
(<:_P t2 (make-any-type (ast-syntax rarg))))
(make-any-type (ast-syntax larg))]
[(check-prim-types-for-binop stx t1 t2) => (lambda (t) t)])])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type arg-type]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(le lt ge gt)
(let-values ([(e1 t1) (typecheck-expression lenv (make-top-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-top-type (ast-syntax rarg)) rarg)])
(let ([ret-type (make-bool-type stx)]
[arg-type (check-prim-types-for-binop stx t1 t2)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type arg-type]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(plus)
(let-values ([(e1 t1) (typecheck-expression lenv (make-top-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-top-type (ast-syntax rarg)) rarg)])
(let ([arg-type (check-prim-types-for-binop stx t1 t2)])
(case (ast:type:primitive-name arg-type)
[(int float string)
(if (<:_P arg-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type arg-type]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
arg-type)
(raise-honu-type-error stx ctype arg-type))]
[else (raise-read-error-with-stx
"The plus operator requires both arguments to be of type int, type float, or type string"
stx)])))]
[(minus times div)
(let-values ([(e1 t1) (typecheck-expression lenv (make-top-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-top-type (ast-syntax rarg)) rarg)])
(let ([arg-type (check-prim-types-for-binop stx t1 t2)])
(case (ast:type:primitive-name arg-type)
[(int float)
(if (<:_P arg-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type arg-type]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
arg-type)
(raise-honu-type-error stx ctype arg-type))]
[else (raise-read-error-with-stx
"Arithmetic operator requires both arguments to be of type int or type float"
stx)])))]
[(mod)
(let-values ([(e1 t1) (typecheck-expression lenv (make-int-type (ast-syntax larg)) larg)]
[(e2 t2) (typecheck-expression lenv (make-int-type (ast-syntax rarg)) rarg)])
(let ([ret-type (make-int-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:binary/op expr
[ast:expr:binary/op-rator-type (make-int-type (ast-syntax larg))]
[ast:expr:binary/op-left e1]
[ast:expr:binary/op-right e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[else
(raise-read-error-with-stx
"Unknown operator"
op-stx)])]
[(struct ast:expr:function (stx ret-type args body))
(if (not (type-valid? ret-type))
(raise-read-error-with-stx
"Return type of anonymous function is invalid"
(ast-syntax ret-type)))
(let ([conflicting-name (get-first-non-unique-name (map ast:formal-name args))])
(if conflicting-name
(raise-read-error-with-stx
(format "Variable name ~a used more than once in function arguments"
(printable-key conflicting-name))
conflicting-name)))
(for-each (lambda (t)
(if (not (type-valid? t))
(raise-read-error-with-stx
"Type of argument of anonymous function is invalid"
(ast-syntax t))))
(map ast:formal-type args))
;; since we have explicit return type annotations now, we use them for the body's ctype and rtype.
(let ([body-lenv (fold (lambda (f e)
(extend-fenv (ast:formal-name f)
(ast:formal-type f)
e))
lenv args)])
(let-values ([(body _) (parameterize ([current-return-type ret-type])
(typecheck-expression body-lenv ret-type body))])
;; we also have the lambda's return type be what was explicitly annotated instead of what we got back
(let ([lam-type (make-func-type stx (make-tuple-type stx (map ast:formal-type args)) ret-type)])
(if (<:_P lam-type ctype)
(values (copy-struct ast:expr:function expr
[ast:expr:function-body body])
lam-type)
(raise-honu-type-error stx ctype lam-type)))))]
[(struct ast:expr:if (stx test then else))
(if else
(let-values ([(e1 t1) (typecheck-expression lenv (make-bool-type (ast-syntax test)) test)]
[(e2 t2) (typecheck-expression lenv ctype then)]
[(e3 t3) (typecheck-expression lenv ctype else)])
;; this should work, but I get the following:
;; -- context expected 1 value, received 2 values: #<struct:ast:expr:if> #<struct:ast:type:primitive>
;; with the arrow going from values -> cond, so I'm going to rewrite as a nested-if for now.
(cond
;; if we had a context type and got to this point, then both t2 and t3 must be related to it (either equal
;; or subtypes), so use it as the type of the entire if expression.
;;
;; No, we can't do this. Think about the fact where we use an if expression on the left-hand side of a
;; member access -- we need to get the most specific type back as the result, not the (vacuous) context
;; type. If the branches are of unrelated types, then having a context type doesn't help us all the time.
;; [ctype
;; (values (copy-struct ast:expr:if expr
;; [ast:expr:if-test e1]
;; [ast:expr:if-then e2]
;; [ast:expr:if-else e3])
;; ctype)]
;; if there was no ctype, then we require either t2 <: t3 or t3 <: t2, and we'll pick the supertype.
[(<:_P t2 t3)
(values (copy-struct ast:expr:if expr
[ast:expr:if-test e1]
[ast:expr:if-then e2]
[ast:expr:if-else e3])
t3)]
[(<:_P t3 t2)
(values (copy-struct ast:expr:if expr
[ast:expr:if-test e1]
[ast:expr:if-then e2]
[ast:expr:if-else e3])
t2)]
;; if we got to here, then there's no good type to use as the type of the entire if expression, so
;; raise an error.
[else (raise-read-error-with-stx
"Branches of if statement are of unrelated types"
stx)]))
;; if else is #f, there was no else branch, so the then branch must be of void type.
(let-values ([(e1 t1) (typecheck-expression lenv (make-bool-type (ast-syntax test)) test)]
[(e2 t2) (typecheck-expression lenv (make-void-type (ast-syntax then)) then)])
(let ([ret-type (make-void-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:if expr
[ast:expr:if-test e1]
[ast:expr:if-then e2])
ret-type)
(raise-read-error-with-stx
"Found if expression without else branch in non-void context"
stx)))))]
[(struct ast:expr:cast (stx obj type))
(if (not (type-valid? type))
(raise-read-error-with-stx
"Type argument of cast is not a valid type"
(ast-syntax type)))
(let-values ([(e1 t1) (typecheck-expression lenv (make-any-type (ast-syntax obj)) obj)])
(if (<:_P type ctype)
(values (copy-struct ast:expr:cast expr
[ast:expr:cast-object e1])
type)
(raise-honu-type-error stx ctype type)))]
[(struct ast:expr:isa (stx obj type))
(if (not (type-valid? type))
(raise-read-error-with-stx
"Type argument of isa is not a valid type"
(ast-syntax type)))
(let-values ([(e1 t1) (typecheck-expression lenv (make-any-type (ast-syntax obj)) obj)])
(let ([ret-type (make-bool-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:isa expr
[ast:expr:isa-object e1])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(struct ast:expr:member (stx 'my _ name _))
(cond
[(lenv name)
=>
(lambda (t)
(if (ast:type:method? t)
(let ([fun-type (make-func-type (ast-syntax t) (ast:type:method-input t) (ast:type:method-output t))])
(if (<:_P fun-type ctype)
(values (copy-struct ast:expr:member expr
[ast:expr:member-method? #t])
fun-type)
(raise-honu-type-error stx ctype fun-type)))
(if (<:_P t ctype)
(values expr t)
(raise-honu-type-error stx ctype t))))]
[else (raise-read-error-with-stx
(format "Static member ~a not found" (syntax-e name))
stx)])]
[(struct ast:expr:member (stx obj _ name _))
(let-values ([(e1 t1) (typecheck-expression lenv (make-any-type (ast-syntax obj)) obj)])
;; if obj was something like error or return, which do not give us a valid type for
;; getting the appropriate member...
(if (ast:type:bot? t1)
(raise-read-error-with-stx
"Attempt to access member of an expression which does not return"
stx))
;; if obj was null...
(if (ast:type:object:null? t1)
(raise-read-error-with-stx
"Null has no fields or methods"
stx))
(let ([t (get-member-type t1 name)])
(cond
[(ast:type:method? t)
(let ([fun-type (make-func-type (ast-syntax t) (ast:type:method-input t) (ast:type:method-output t))])
(if (<:_P fun-type ctype)
(values (copy-struct ast:expr:member expr
[ast:expr:member-object e1]
[ast:expr:member-object-type t1]
[ast:expr:member-method? #t])
fun-type)
(raise-honu-type-error stx ctype fun-type)))]
[t
(if (<:_P t ctype)
(values (copy-struct ast:expr:member expr
[ast:expr:member-object e1]
[ast:expr:member-object-type t1])
t)
(raise-honu-type-error stx ctype t))]
[else (raise-read-error-with-stx
(format "Member ~a not found in type ~a" (syntax-e name) (printable-type t1))
stx)])))]
[(struct ast:expr:new (stx class type args))
(let ([class-entry (get-class-entry class)]
[new-type (if type type ctype)])
;; the following can only be triggered if the type annontation isn't a type
(if (and type (not (type-valid? type)))
(raise-read-error-with-stx
(format "Type annotation ~a on new statement is not a valid type" (printable-type new-type))
(ast-syntax new-type)))
;; the following two checks can only be triggered if there is no type annotation
(if (ast:type:top? new-type)
(raise-read-error-with-stx
"type of instantiation must be explicitly annotated"
stx))
(if (not (<:_P new-type (make-any-type stx)))
(raise-read-error-with-stx
(format "new statement appears in context of non-interface type ~a"
(printable-type new-type))
stx))
;; the class must implement a subtype of the type we're instantiating it at
(if (not (ormap (lambda (t)
(<:_P t new-type))
(tenv:class-impls class-entry)))
(raise-read-error-with-stx
(format "class ~a does not implement a subtype of type ~a"
(printable-key class)
(printable-type new-type))
stx))
(let ([args (check-inits stx (lambda (e t)
(typecheck-expression lenv t e))
(tenv:class-inits class-entry) args)])
(if (<:_P new-type ctype)
(values (copy-struct ast:expr:new expr
[ast:expr:new-type new-type]
[ast:expr:new-args args])
new-type)
(raise-honu-type-error stx ctype new-type))))]
[(struct ast:expr:while (stx cond body))
(let-values ([(e1 t1) (typecheck-expression lenv (make-bool-type (ast-syntax cond)) cond)]
[(e2 t2) (typecheck-expression lenv (make-void-type (ast-syntax body)) body)])
(let ([ret-type (make-void-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:while expr
[ast:expr:while-test e1]
[ast:expr:while-body e2])
ret-type)
(raise-honu-type-error stx ctype ret-type))))]
[(struct ast:expr:cond (stx clauses else))
(if else
(let-values ([(clauses types) (map-two-values (lambda (c)
(typecheck-cond-clause lenv ctype c))
clauses)]
[(else etype) (typecheck-expression lenv ctype else)])
(cond
;; if ctype exists, just use it
;;
;; can't do this, see if for reasoning
;; [ctype
;; (values (copy-struct ast:expr:cond expr
;; [ast:expr:cond-clauses clauses])
;; ctype)]
;; otherwise find the most super type of all the branches
[(pick-super-type-from-list (cons etype types))
=>
(lambda (t)
(values (copy-struct ast:expr:cond expr
[ast:expr:cond-clauses clauses]
[ast:expr:cond-else else])
t))]
;; otherwise we're hosed for determining a type -- throw an error
[else
(raise-read-error-with-stx
"At least two branches of the cond statement have unrelated types"
stx)]))
;; if else is #f, there was no else branch, so the cond clauses must be of void type.
(let-values ([(clauses types) (map-two-values (lambda (c)
(typecheck-cond-clause lenv
(make-void-type (ast-syntax c)) c))
clauses)])
(let ([ret-type (make-void-type stx)])
(if (<:_P ret-type ctype)
(values (copy-struct ast:expr:cond expr
[ast:expr:cond-clauses clauses])
ret-type)
(raise-read-error-with-stx
"Cond expression without an else branch found in non-void context"
stx)))))]
[(struct ast:expr:return (stx body))
;; returns don't return to their context, but to the context of the method or function call in which
;; they were invoked. Because of this a) rtype must not be #f (else we're not in a method or function
;; body) and b) the type of a return statement is the bottom type (same as error).
(if (current-return-type)
;; we use rtype as the context type here, since that's the type that needs to be returned.
(let-values ([(e1 _) (typecheck-expression lenv (current-return-type) body)])
;; we don't need to check (bottom-type) <:_P ctype, because that's vacuously true.
(values (copy-struct ast:expr:return expr
[ast:expr:return-result e1])
(make-bottom-type stx)))
(raise-read-error-with-stx
"Return statement found outside body of method or function"
stx))]
[(struct ast:expr:tuple (stx vals))
(cond
[(ast:type:tuple? ctype)
;; we have a tuple context type, so use its contents, but make
;; sure it's the right length.
(if (not (= (length vals) (length (ast:type:tuple-elems ctype))))
(raise-read-error-with-stx
(format "Expected tuple of length ~a, got tuple of length ~a"
(length vals)
(length (ast:type:tuple-elems ctype)))
stx))
(let-values ([(vals types) (map-two-values (lambda (e t)
(typecheck-expression lenv t e))
vals (ast:type:tuple-elems ctype))])
(values (copy-struct ast:expr:tuple expr
[ast:expr:tuple-elems vals])
(make-tuple-type stx types)))]
;; we must be in hte context of a select expression, so
[(ast:type:partial/tuple? ctype)
(if (not (<= (ast:type:partial/tuple-position ctype) (length vals)))
(raise-read-error-with-stx
(format "Expected tuple of length at least ~a, got tuple of length ~a"
(ast:type:partial/tuple-position ctype)
(length vals))
stx))
(let-values ([(vals types) (map-two-values (lambda (e t)
(typecheck-expression lenv t e))
vals (gen-top-except-for (length vals)
(ast:type:partial/tuple-position ctype)
(ast:type:partial/tuple-elem ctype)))])
(values (copy-struct ast:expr:tuple expr
[ast:expr:tuple-elems vals])
(make-tuple-type stx types)))]
;; if we have the top type here, then we either a) don't care about the type or
;; b) are going to check it after we return, so just do the simple thing -- since
;; we have no knowledge about what's wanted, we just check each component with ctype.
[(ast:type:top? ctype)
(let-values ([(vals types) (map-two-values (lambda (e)
(typecheck-expression lenv
(make-top-type (ast-syntax e)) e))
vals)])
(values (copy-struct ast:expr:tuple expr
[ast:expr:tuple-elems vals])
(make-tuple-type stx types)))]
[else (raise-read-error-with-stx
"Expected non-tuple expression (or tuple of length 1) here"
stx)])]
[(struct ast:expr:let (_ bindings body))
(let*-values ([(bindings lenv) (map-and-fold (lambda (bind lenv)
(typecheck-binding lenv bind))
lenv
bindings)]
[(e1 t1) (typecheck-expression lenv ctype body)])
(values (copy-struct ast:expr:let expr
[ast:expr:let-bindings bindings]
[ast:expr:let-body e1])
t1))]
[(struct ast:expr:sequence (_ effects value))
(let-values ([(effects _)
(map-two-values
(lambda (e)
(typecheck-expression lenv (make-void-type (ast-syntax e)) e))
effects)]
[(e1 t1) (typecheck-expression lenv ctype value)])
(values (copy-struct ast:expr:sequence expr
[ast:expr:sequence-statements effects]
[ast:expr:sequence-result e1])
t1))]))
;; bindings have no ctype because they're always in the void type context
;; they return the elaborated binding and a new environment extended with the
;; type of the bound variable.
(define (typecheck-binding lenv binding)
(match binding
[(struct ast:defn:binding (stx names types value))
;; make sure to remove all the #f for don't care arguments.
(let ([conflicting-name (get-first-non-unique-name (filter (lambda (n) n) names))])
(if conflicting-name
(raise-read-error-with-stx
(format "Variable name ~a used more than once in binding form"
(printable-key conflicting-name))
conflicting-name)))
(for-each (lambda (n t)
(if (and (not (and (not n)
(ast:type:top? t)))
(not (type-valid? t)))
(raise-read-error-with-stx
"Type of locally bound variable is undefined"
(ast-syntax t))))
names types)
(let-values ([(e1 t1) (typecheck-expression lenv (make-tuple-type (ast-syntax value) types) value)])
(values (copy-struct ast:defn:binding binding
[ast:defn:binding-init e1])
(fold (lambda (name type lenv)
(if name
(extend-fenv name type lenv)
lenv))
lenv names types)))]))
(define (typecheck-cond-clause lenv ctype clause)
(match clause
[(struct ast:cond/clause (stx pred rhs))
(let-values ([(e1 t1) (typecheck-expression lenv (make-bool-type (ast-syntax pred)) pred)]
[(e2 t2) (typecheck-expression lenv ctype rhs)])
(values (copy-struct ast:cond/clause clause
[ast:cond/clause-test e1]
[ast:cond/clause-result e2])
t2))]))
(define (check-prim-types-for-binop stx t1 t2)
(cond
[(and (ast:type:bot? t1)
(ast:type:primitive? t2))
t2]
[(and (ast:type:primitive? t1)
(ast:type:bot? t2))
t1]
[(and (ast:type:primitive? t1)
(ast:type:primitive? t2)
(type-equal? t1 t2))
t1]
[else
(raise-read-error-with-stx
(format "Expected primitive types for binary operator, got ~a and ~a"
(printable-type t1)
(printable-type t2))
stx)]))
(define (check-inits stx type-fun inits new-args)
(let-values ([(new-args remaining-inits)
(map-and-fold (lambda (arg inits)
(let*-values ([(init remaining-inits)
(find-init inits (ast:named/arg-name arg))]
[(e1 t1)
(type-fun (ast:named/arg-actual arg) (tenv:init-type init))])
(values (copy-struct ast:named/arg arg
[ast:named/arg-actual e1])
remaining-inits)))
inits new-args)])
(if (andmap tenv:init-optional? remaining-inits)
new-args
(raise-read-error-with-stx
(format "No value assigned for init arg ~a"
(printable-key (tenv:init-name (car remaining-inits))))
stx))))
;; find-inits takes the name of an init arg to find in a list of inits and
;; returns both the init (if found) and the list minus that init
(define (find-init inits name)
(let loop ([inits inits]
[passed '()])
(cond
[(null? inits)
(raise-read-error-with-stx
(format "class does not have an init arg with name ~a"
(printable-key name))
name)]
[(tenv-key=? name (tenv:init-name (car inits)))
(values (car inits)
(append (reverse passed) (cdr inits)))]
[else
(loop (cdr inits)
(cons (car inits) passed))])))
;; assumes a non-empty list
(define (pick-super-type-from-list ts)
(define (pick-super-type-with-acc ts t)
(cond
;; t is a super-type of all the other branches
[(andmap (lambda (t2)
(<:_P t2 t))
ts)
t]
;; if there's a type t2 in ts that is not equal to t
;; but t <:_P t2, then recur with t2 instead.
[(find (lambda (t2)
(and (not (type-equal? t t2))
(<:_P t t2)))
ts)
=>
(lambda (t)
(pick-super-type-with-acc ts t))]
;; there are no types in ts that are a super-type of t,
;; but t is not equal to or a super-type of all the types
;; in ts, we know that not all the types in the list are
;; related and thus we fail.
[else #f]))
(pick-super-type-with-acc ts (car ts)))
(define (gen-top-except-for n k t)
(cond
[(= n 0) (list)]
[(= k 1) (cons t (gen-top-except-for (- n 1) (- k 1) t))]
[else (cons (make-top-type #f) (gen-top-except-for (- n 1) (- k 1) t))]))
)

View File

@ -1,13 +0,0 @@
(module typecheck-parameters mzscheme
(provide (all-defined))
;; since the return type only changes when we go into a lambda in typecheck-expression, we
;; make it a parameter also.
;;
;; rtype : (union ast:type? false/c)
;; return type for method/function
(define current-return-type (make-parameter #f))
)

View File

@ -1,28 +0,0 @@
(module typecheck-utils mzscheme
(require (lib "contract.ss")
"../../ast.ss"
"../tools/general.ss"
"../../readerr.ss"
"type-utils.ss"
)
(provide/contract
[check-valid-type! (string? ast:type? . -> . void?)]
[check-valid-types! (string? (listof ast:type?) . -> . void?)]
)
;; check-valid-type! : Name Type -> Void
;; Raises an error if named type is not valid.
(define (check-valid-type! name type)
(if (not (type-valid? type))
(raise-read-error-with-stx
(format "~s is undefined" name)
(ast-syntax type))))
;; check-valid-types! : Name [Listof Type] -> Void
;; Raises an error if any of the named types are not valid.
(define (check-valid-types! name types)
(for-each (curry check-valid-type! name) types))
)

View File

@ -1,251 +0,0 @@
(module typechecker mzscheme
(require (lib "contract.ss")
(lib "plt-match.ss")
(lib "struct.ss")
(prefix srfi1: (lib "list.ss" "srfi" "1"))
"../../ast.ss"
"../../readerr.ss"
"../../tenv.ss"
"../tools/general.ss"
"typecheck-utils.ss"
"typecheck-class-utils.ss"
"typecheck-expression.ss"
"typecheck-parameters.ss"
"type-utils.ss")
(provide/contract [typecheck ((listof ast:defn?)
. -> .
(listof ast:defn?))]
[typecheck-defn (ast:defn?
. -> .
ast:defn?)])
(define (typecheck defns)
(let loop ([defns defns]
[results '()])
(cond
[(null? defns) (reverse results)]
;; we allow functions to be mutually recursive in Algol-like fashion
;; (i.e. if they are no intervening non-function definitions)
[(ast:defn:function? (car defns))
(let-values ([(funcs remaining) (srfi1:span ast:defn:function? defns)])
(loop remaining (append (typecheck-functions funcs) results)))]
[else (loop (cdr defns) (cons (typecheck-defn (car defns)) results))])))
(define (typecheck-functions funcs)
(define (check-function-type func)
(match func
[(struct ast:defn:function (stx name type args body))
(check-valid-type! "function return type" type)
(let ([conflicting-name (get-first-non-unique-name (map ast:formal-name args))])
(if conflicting-name
(raise-read-error-with-stx
(format "Argument name ~a used more than once"
(printable-key conflicting-name))
conflicting-name)))
(check-valid-types! "function argument type" (map ast:formal-type args))
(make-func-type stx (make-tuple-type stx (map ast:formal-type args)) type)]))
;; first we add the functions to the lexical environment so that when we typecheck
;; the bodies, they'll be in scope.
(for-each (lambda (f)
(extend-lenv (ast:defn:function-name f)
(make-tenv:value (ast-syntax f) (check-function-type f))))
funcs)
(let loop ([funcs funcs]
[new-funcs '()])
(if (null? funcs)
;; don't reverse it, because we want to keep these in the same order in typecheck,
;; which will eventually reverse everything
new-funcs
(match (car funcs)
[(struct ast:defn:function (stx name type args body))
(let-values
([(e1 t1)
(parameterize ([current-return-type type])
(typecheck-expression (srfi1:fold (lambda (a e)
(extend-fenv (ast:formal-name a)
(ast:formal-type a)
e))
(wrap-lenv)
args)
type body))])
(loop (cdr funcs)
(cons (copy-struct ast:defn:function (car funcs)
[ast:defn:function-body e1])
new-funcs)))]))))
;; typecheck-bind-top : BindTop -> BindTop
;; Typechecks a top-level binding and produces the annotated version.
(define (typecheck-bind-top bind-top)
(match bind-top
[(struct ast:defn:binding (stx names types value))
(for-each (lambda (n t)
(if (not (and (not n)
(ast:type:top? t)))
(check-valid-type! "top-level bound variable type" t)))
names types)
(let-values ([(e1 t1) (typecheck-expression (wrap-lenv) (make-tuple-type stx types) value)])
(for-each (lambda (n t)
(if n (extend-lenv n (make-tenv:value stx t))))
names types)
(copy-struct ast:defn:binding bind-top
[ast:defn:binding-init e1]))]))
;; typecheck-iface : IFace -> IFace
;; Typechecks an interface definition and produces the annotated version.
(define (typecheck-iface iface)
(match iface
[(struct ast:defn:iface (stx name supers members))
(check-valid-types! "interface supertype" supers)
(let ([conflicting-name (get-first-non-unique-name (map ast:iface/member-name members))])
(if conflicting-name
(raise-read-error-with-stx
(format "Field/method name ~a used more than once"
(printable-key conflicting-name))
conflicting-name)))
(for-each (lambda (m)
(typecheck-member-decl m))
members)
iface]))
;; typecheck-class : Class -> Class
;; Typechecks a class definition and produces the annotated version.
(define (typecheck-class class)
(match class
[(struct ast:defn:class (stx name type final? impls inits members exports))
(check-valid-type! "class self-type" type)
(check-valid-types! "implemented type of class" impls)
(let ([conflicting-name (get-first-non-unique-name (append (map ast:formal-name inits)
(map ast:class/member-name members)))])
(if conflicting-name
(raise-read-error-with-stx
(format "Init/field/method name ~a used more than once"
(printable-key conflicting-name))
conflicting-name)))
(check-valid-types! "init slot type" (map ast:formal-type inits))
(let ([lenv (srfi1:fold (lambda (a e)
(extend-fenv (ast:formal-name a)
(ast:formal-type a)
e))
(lambda (n) #f)
inits)])
(let*-values ([(lenv) (extend-fenv #'this type (wrap-lenv))]
[(members lenv) (typecheck-members lenv type members)])
(typecheck-exports lenv type impls exports)
(copy-struct ast:defn:class class
[ast:defn:class-members members])))]))
;; check-mixin-internal-names! : Mixin -> Void
;; Raises an error if defined names in a mixin conflict with each other.
(define (check-mixin-internal-names! mixin)
(match mixin
[(struct ast:defn:mixin (stx name type arg-type final? impls inits withs
supernew members-before members-after exports))
(let* ([arg-tentry (get-type-entry arg-type)]
[conflicting-name (get-first-non-unique-name (append (map tenv:member-name
(append (tenv:type-members arg-tentry)
(tenv:type-inherited arg-tentry)))
(map ast:formal-name inits)
(map ast:class/member-name
(append members-before
members-after))))])
(if conflicting-name
(raise-read-error-with-stx
(format "Init/field/method name ~a used more than once in mixin or conflicts with members of argument type"
(printable-key conflicting-name))
(ast-syntax mixin))))]))
;; check-mixin-expected-init-names! : Mixin -> Void
;; Raises an error if init arguments expected of mixin's argument contain conflicts
(define (check-mixin-expected-init-names! mixin)
(match mixin
[(struct ast:defn:mixin (stx name type arg-type final? impls inits withs
supernew members-before members-after exports))
(let ([conflicting-name (get-first-non-unique-name (map ast:formal-name withs))])
(if conflicting-name
(raise-read-error-with-stx
(format "Init name ~a used more than once in expected init slots"
(printable-key conflicting-name))
conflicting-name)))]))
;; check-distinct-names! : String [Listof Identifier] -> Void
;; Raises an error if any of the names are the same.
(define (check-distinct-names! desc names)
(cond
[(check-duplicate-identifier names) =>
(lambda (name)
(raise-read-error-with-stx (format "Duplicate name ~s found in ~s." name desc) name))]
[else (void)]))
;; check-distinct-types! : String [Listof Honu:Type] -> Void
;; Raises an error if any of the types are the same.
(define (check-distinct-types! desc types)
(check-distinct-names! desc (map ast:type:object:iface-name types)))
;; typecheck-mixin : Mixin -> Mixin
;; Typechecks a mixin definition and produces the annotated version.
(define (typecheck-mixin mixin)
(match mixin
[(struct ast:defn:mixin (stx name type arg-type final? impls inits withs
supernew members-before members-after exports))
(define members (append members-before members-after))
(define member-names (map ast:class/member-name members))
(define init-names (map ast:formal-name inits))
(define super-member-names (type-member-names arg-type))
(check-valid-type! "mixin argument type" arg-type)
(check-valid-type! "mixin result type" type)
(check-valid-types! "mixin implemented type" impls)
(check-valid-types! "init slot type" (map ast:formal-type inits))
(check-valid-types! "superclass init slot type" (map ast:formal-type withs))
(check-distinct-types! "mixin implemented types" impls)
(check-distinct-names! "internally visible member/init names"
(append super-member-names init-names member-names))
(check-distinct-names! "superclass init slot names"
(map ast:formal-name withs))
(let*-values ([(lenv) (wrap-lenv)]
[(lenv) (extend-fenv #'this type lenv)]
[(lenv) (srfi1:fold extend-fenv-ast:formal lenv inits)]
[(members-before lenv) (typecheck-members lenv type members-before)]
[(supernew) (typecheck-supernew lenv withs supernew)]
[(lenv) (extend-lenv-with-type-members lenv arg-type)]
[(members-after lenv) (typecheck-members lenv type members-after)])
(typecheck-exports lenv type impls exports)
(copy-struct ast:defn:mixin mixin
[ast:defn:mixin-pre-members members-before]
[ast:defn:mixin-super-new supernew]
[ast:defn:mixin-post-members members-after]))]))
;; typecheck-subclass : Subclass -> Subclass
;; Typechecks a subclass definition and produces the annotated version.
(define (typecheck-subclass subclass)
(match subclass
;; we basically do all the checks when we create the tenv entry for the subclass (plus typechecking the base
;; class and mixin), so no need to check again.
[(struct ast:defn:subclass (_ _ _ _))
subclass]))
;; typecheck-defn : Defn -> Defn
;; Typechecks a top-level definition and produces the annotated version.
(define (typecheck-defn defn)
(cond
[(ast:defn:binding? defn) (typecheck-bind-top defn)]
[(ast:defn:iface? defn) (typecheck-iface defn)]
[(ast:defn:class? defn) (typecheck-class defn)]
[(ast:defn:mixin? defn) (typecheck-mixin defn)]
[(ast:defn:subclass? defn) (typecheck-subclass defn)]
[else (raise-read-error-with-stx
"Haven't implemented typechecking for that type of definition yet."
(ast-syntax defn))]))
(define (typecheck-member-decl member)
(match member
[(struct ast:iface/member:field (stx name type))
(check-valid-type! "field type" type)]
[(struct ast:iface/member:method (stx name type args))
(check-valid-type! "method return type" type)
(check-valid-types! "method argument type" args)]))
)

View File

@ -1,20 +0,0 @@
(module readerr mzscheme
(require (lib "readerr.ss" "syntax"))
(provide raise-read-error-with-stx)
;; Yes, this is misleading for now. I'll rename it later.
;; (define (raise-read-error-with-stx str stx)
;; (raise-syntax-error #f str stx))
;; Forget it, this gives you less extra crap with your error message.
;; I'd need to decide what to put in those places instead, so at the
;; moment we'll keep it a read error.
(define (raise-read-error-with-stx str stx)
(raise-read-error str
(syntax-source stx)
(syntax-line stx)
(syntax-column stx)
(syntax-position stx)
(syntax-span stx)))
)

View File

@ -1,21 +0,0 @@
(module run-tests mzscheme
(require "honu-tests.ss"
)
(provide test/text test/graphical)
(define (test/text)
((dynamic-require '(planet "text-ui.ss" ("schematics" "schemeunit.plt" 1 1)) 'test/text-ui)
honu-tests))
(define (test/graphical)
((dynamic-require '(planet "graphical-ui.ss" ("schematics" "schemeunit.plt" 1 1)) 'test/graphical-ui)
honu-tests))
)

View File

@ -1,561 +0,0 @@
(module tenv-utils mzscheme
(require "readerr.ss"
"ast.ss"
"parameters.ss"
"tenv.ss"
"private/tools/general.ss"
"private/typechecker/type-utils.ss"
(lib "plt-match.ss")
(lib "struct.ss")
(lib "list.ss" "srfi" "1"))
(define (make-struct-type-decls inits mfidefns)
(define (convert-to-decl d)
(cond
;; can come from inits
[(ast:formal? d)
(make-ast:iface/member:field (ast-syntax d)
(ast:formal-name d)
(ast:formal-type d))]
;; can come from mdidefns
[(ast:class/member:field/formal? d)
(make-ast:iface/member:field (ast-syntax d)
(ast:class/member-name d)
(ast:class/member:field/formal-type d))]
[(ast:class/member:field? d)
(make-ast:iface/member:field (ast-syntax d)
(ast:class/member-name d)
(ast:class/member:field-type d))]
[(ast:class/member:method? d)
(make-ast:iface/member:method (ast-syntax d)
(ast:class/member-name d)
(ast:class/member:method-return-type d)
(map ast:formal-type (ast:class/member:method-formals d)))]))
(map convert-to-decl (append inits mfidefns)))
(define (make-struct-export typ inits mdidefns members)
(define (grab-name d)
(cond
;; can come from members
[(tenv:member? d) (tenv:member-name d)]
;; can come from inits
[(ast:formal? d) (ast:formal-name d)]
;; can come from mdidefns
[(ast:class/member? d) (ast:class/member-name d)]))
(let ([binds (map (lambda (m)
(let ([name (grab-name m)])
(make-ast:export/member #f name name))) (append inits mdidefns members))])
(make-ast:export #f typ binds)))
(define (tenv-create-error skipped)
;; only subclasses and substructs can be skipped, so if the base of one of them
;; is in the skipped list as well, then we have a cycle. If not, then there's
;; some missing definition.
;;
;; well, this isn't true anymore, so check to see if it's an iface first, which
;; is the other possibility for skipping. We need to check a similar kind of
;; thing to see if the type hierarchy is a cycle or there's just something missing.
;;
;; FIXME: This function almost certainly does not always give the correct error message
;; (for example, it may give a cycle error when it turns out that the first thing
;; in the skipped list just depends on something else which just had stuff missing,
;; so there should have been a definitions needed missing error. Will revisit later.
(if (ast:defn:iface? (car skipped))
(let ([supers (ast:defn:iface-supers (car skipped))])
(if (find (lambda (d)
(cond
[(ast:defn:iface? d) (s:member (ast:defn:iface-name d) supers tenv-key=?)]
[else #f]))
(cdr skipped))
(raise-read-error-with-stx
(format "Type ~a is involved in a type hierarchy cycle"
(printable-key (ast:defn:iface-name (car skipped))))
(ast:defn:iface-name (car skipped)))
(raise-read-error-with-stx
(format "At least one supertype of type ~a is missing"
(printable-key (ast:defn:iface-name (car skipped))))
(ast:defn:iface-name (car skipped)))))
(let ([class-name (cond
[(ast:defn:subclass? (car skipped)) (ast:defn:subclass-name (car skipped))]
[(ast:defn:substructure? (car skipped)) (ast:defn:substructure-name (car skipped))])]
[base-name (cond
[(ast:defn:subclass? (car skipped)) (ast:defn:subclass-base (car skipped))]
[(ast:defn:substructure? (car skipped)) (ast:defn:substructure-super-class (car skipped))])])
(if (find (lambda (d)
(cond
[(ast:defn:subclass? d) (tenv-key=? base-name (ast:defn:subclass-name d))]
[(ast:defn:substructure? d) (tenv-key=? base-name (ast:defn:substructure-name d))]
[else #f]))
(cdr skipped))
(raise-read-error-with-stx
(format "Class ~a is involved in a class hierarchy cycle" (printable-key class-name))
class-name)
(raise-read-error-with-stx
(format "Definitions needed for definition of class ~a are missing" (printable-key class-name))
class-name)))))
(provide add-defns-to-tenv add-defn-to-tenv)
(define (add-defns-to-tenv defns)
(let loop ([defns defns]
[skipped '()]
[changed? #f]
[new-defns '()])
(cond
;; we're done, so return the new defns
[(and (null? defns) (null? skipped))
(reverse new-defns)]
;; we skipped some, so go back and check those.
[(null? defns)
(if changed?
(loop skipped '() #f new-defns)
;; we didn't change anything on the last run,
;; so we must either have a cycle in the class graph
;; or there are missing definitions. Raise an
;; appropriate error for the first definition.
(tenv-create-error skipped))]
;; for functions and top level bindings, we
;; don't add them here, so just skip them.
[(or (ast:defn:function? (car defns))
(ast:defn:binding? (car defns)))
(loop (cdr defns) skipped #t (cons (car defns) new-defns))]
[(ast:defn:iface? (car defns))
(let loop2 ([supers (map ast:type:object:iface-name (ast:defn:iface-supers (car defns)))])
(cond
;; if we went through all the supers with them being defined,
;; then we can add this type as well.
[(null? supers)
(loop (cdr defns) skipped #t (cons (add-defn-to-tenv (car defns)) new-defns))]
;; if there is an entry, we check to make sure it's a type, and
;; if it is, then we continue looping in the inner loop
[(get-tenv-entry (car supers))
=>
(lambda (e)
(if (not (tenv:type? e))
(raise-read-error-with-stx
(format "~a is not a type" (printable-key (car supers)))
(car supers))
(loop2 (cdr supers))))]
;; if there is no entry, then we can't add this type yet, so
;; recur on the outer loop with this type being skipped.
[else
(loop (cdr defns) (cons (car defns) skipped) changed? new-defns)]))]
;; for classes and mixins, we don't use the tenv to create
;; their entries, so we just run them through as we hit them.
[(or (ast:defn:class? (car defns))
(ast:defn:mixin? (car defns)))
(loop (cdr defns) skipped #t (cons (add-defn-to-tenv (car defns)) new-defns))]
;; for structs, we will get back a list of two things: the new type
;; and the new class definition, so append those onto new-defns
[(ast:defn:structure? (car defns))
(match (car defns)
[(struct ast:defn:structure (stx name type final? impls inits members exports))
(let ([new-iface (make-ast:defn:iface stx (ast:type:object:iface-name type) (list)
(make-struct-type-decls inits members))]
[new-class (make-ast:defn:class stx name type final? (cons type impls) inits members
(cons (make-struct-export type inits members (list)) exports))])
(loop (cdr defns) skipped #t (cons (add-defn-to-tenv new-class)
(cons (add-defn-to-tenv new-iface) new-defns))))])]
;; for subclasses, we check to make sure the base (and its self-type) and
;; the mixin (and its arg-type) are in the tenv. If not, skip it.
;; Give appropriate errors for each thing that can go wrong.
[(ast:defn:subclass? (car defns))
(let* ([base (get-tenv-entry (ast:defn:subclass-base (car defns)))]
[selftype (if (and base (tenv:class? base))
(get-tenv-entry (ast:type:object:iface-name (tenv:class-sub-type base)))
#f)]
[mixin (get-tenv-entry (ast:defn:subclass-mixin (car defns)))]
[argtype (if (and mixin (tenv:mixin? mixin))
(get-tenv-entry (ast:type:object:iface-name (tenv:mixin-arg-type mixin)))
#f)])
(cond
[(and base (not (tenv:class? base)))
(raise-read-error-with-stx
"Base class for subclass definition is not a class"
(ast:defn:subclass-base (car defns)))]
[(and selftype (not (tenv:type? selftype)))
(raise-read-error-with-stx
"Selftype for class is not a type"
(ast-syntax (tenv:class-sub-type base)))]
[(and mixin (not (tenv:mixin? mixin)))
(raise-read-error-with-stx
"Mixin for subclass definition is not a mixin"
(ast:defn:subclass-mixin (car defns)))]
[(and argtype (not (tenv:type? argtype)))
(raise-read-error-with-stx
"Argument type for mixin is not a type"
(ast-syntax (tenv:mixin-arg-type mixin)))]
[(and base selftype mixin argtype)
;; if the base is final, then we can't extend it.
(if (tenv:class-final? base)
(raise-read-error-with-stx
(format "Cannot apply mixin to final class ~a"
(printable-key base))
base))
;; if the base's selftype does not match the mixin's argtype,
;; we cannot apply the mixin to the base.
(if (not (<:_P (tenv:class-sub-type base) (tenv:mixin-arg-type mixin)))
(raise-read-error-with-stx
(format "Class ~a (~a) is not of an appropriate type (~a) for mixin ~a"
(printable-key (ast:defn:subclass-base (car defns)))
(printable-type (tenv:class-sub-type base))
(printable-type (tenv:mixin-arg-type mixin))
(printable-key (ast:defn:subclass-mixin (car defns))))
(ast:defn:subclass-base (car defns))))
(loop (cdr defns) skipped #t (cons (add-defn-to-tenv (car defns)) new-defns))]
;; if we get here, we cannot yet make the entry for this subclass,
;; so skip it.
[else
(loop (cdr defns) (cons (car defns) skipped) changed? new-defns)]))]
;; for substructs, we just deconstruct it and then let the subclass logic catch any problems.
;; we do a couple of checks, because getting the type right for the substruct requires having
;; the argtype of the substruct.
[(ast:defn:substructure? (car defns))
(match (car defns)
[(struct ast:defn:substructure (stx name type base arg-type final? impls inits withs super-new
members-before members-after exports))
(let ([argtype (get-tenv-entry (ast:type:object:iface-name arg-type))])
(cond
[(and argtype (not (tenv:type? argtype)))
(raise-read-error-with-stx
"Type at which we are extending is not a type"
(ast-syntax arg-type))]
[argtype
(let* ([new-iface (make-ast:defn:iface stx (ast:type:object:iface-name type) (list arg-type)
(make-struct-type-decls inits
(append members-before members-after)))]
[mixin-name (datum->syntax-object name (string->symbol
(string-append "$" (symbol->string (printable-key name))))
name)]
[new-mixin (make-ast:defn:mixin stx mixin-name type arg-type final? (cons type impls) inits withs
super-new members-before members-after
(cons (make-struct-export type
inits
(append members-before members-after)
(tenv:type-members argtype))
exports))]
[new-sclass (make-ast:defn:subclass stx name base mixin-name)])
(loop (cons new-sclass (cdr defns)) skipped #t (cons (add-defn-to-tenv new-mixin)
(cons (add-defn-to-tenv new-iface) new-defns))))]
[else
(loop (cdr defns) (cons (car defns) skipped) changed? new-defns)]))])])))
(define (check-super-for-members name members super-name)
(match (get-tenv-entry super-name)
[(struct tenv:type (_ _ super-members super-inherited))
;; here we make sure to use both defined members and inherited members
(let loop ([super-members (append super-members super-inherited)]
[inherited '()])
(cond
;; we've checked all the super members
[(null? super-members)
(reverse inherited)]
;; if we find a member of the subtype that matches the currently inspected member of
;; the supertype...
[(find (lambda (m)
(tenv-key=? (tenv:member-name m)
(tenv:member-name (car super-members))))
members)
=>
(lambda (m)
;; if we eventually allow co-/contra-variance here, this is where
;; we'd do it.
(if (ast:type:method? (tenv:member-type (car super-members)))
(if (<:_P (tenv:member-type m) (tenv:member-type (car super-members)))
(loop (cdr super-members) inherited)
(raise-read-error-with-stx
(format "Type ~a defines member ~a with type ~a, is not a subtype of type ~a as defined in supertype ~a"
(printable-key name)
(printable-key (tenv:member-name m))
(printable-type (tenv:member-type m))
(printable-type (tenv:member-type (car super-members)))
(printable-key super-name))
(tenv:member-stx m)))
;; this handles mutable fields -- we don't have immutable fields yet
(if (type-equal? (tenv:member-type m) (tenv:member-type (car super-members)))
(loop (cdr super-members) inherited)
(raise-read-error-with-stx
(format "Type ~a defines member ~a with type ~a, was defined with type ~a in supertype ~a"
(printable-key name)
(printable-key (tenv:member-name m))
(printable-type (tenv:member-type m))
(printable-type (tenv:member-type (car super-members)))
(printable-key super-name))
(tenv:member-stx m)))))]
;; if there was no match, then this is one we inherited and for which we did not give
;; an explicit declaration.
[else
(loop (cdr super-members) (cons (cons super-name (car super-members)) inherited))]))]))
(define (mangle-disp-type iface member)
(let ([member-type (tenv:member-type member)])
(if (ast:type:method? member-type)
(copy-struct tenv:member member
[tenv:member-type (make-method-type (ast-syntax member-type)
iface
(ast:type:method-input member-type)
(ast:type:method-output member-type))])
member)))
(define (type-equal-modulo-disp? t1 t2)
(let ([t1 (if (ast:type:method? t1)
(make-func-type (ast-syntax t1)
(ast:type:method-input t1)
(ast:type:method-output t1))
t1)]
[t2 (if (ast:type:method? t2)
(make-func-type (ast-syntax t2)
(ast:type:method-input t2)
(ast:type:method-output t2))
t2)])
(type-equal? t1 t2)))
(define (check-and-remove-duplicate-members subtype inherited-members)
(let loop ([inherited-members inherited-members]
[unique-members '()])
(if (null? inherited-members)
(reverse unique-members)
(let ([current-member (cdr (car inherited-members))])
(let-values ([(matching-members rest-members)
(partition (lambda (p)
(tenv-key=? (tenv:member-name current-member)
(tenv:member-name (cdr p))))
(cdr inherited-members))])
(let loop2 ([matching-members matching-members])
(cond
[(null? matching-members)
(loop rest-members (cons (mangle-disp-type (make-iface-type subtype subtype)
current-member)
unique-members))]
;; members coming from supers that are _not_ redefined must be exactly equal
;; (modulo the dispatch arguments of methods)
;;
;; doesn't matter which we keep, so we'll just keep the first one that matched.
[(type-equal-modulo-disp? (tenv:member-type current-member)
(tenv:member-type (cdr (car matching-members))))
(loop2 (cdr matching-members))]
[else
(raise-read-error-with-stx
(format "For type ~a, supertype ~a has type ~a for member ~a, whereas supertype ~a has type ~a"
(printable-key subtype)
(printable-key (car (car inherited-members)))
(printable-type (tenv:member-type current-member))
(printable-key (tenv:member-name current-member))
(printable-key (car (car matching-members)))
(printable-type (tenv:member-type (cdr (car matching-members)))))
subtype)])))))))
(define (add-defn-to-tenv defn)
(match defn
;; for types, we need to recur over our supertypes, make sure that we don't have any definitions that countermand
;; those in our super classes (which will also make sure that our superclass definitions are consistent), and
;; then we will add any member definitions in them that are _not_ declared in this type.
;;
;; If we get here, we know that all the supers are in the tenv and are type entries, so we can use
;; get-type-entry safely.
[(struct ast:defn:iface (src-stx name supers members))
;; we have to do this because members of the type can refer to the type itself.
;; this is only for <:_P checks.
(extend-tenv name
(make-tenv:type src-stx supers '() '()))
(let* ([tenv-members (convert-members (make-iface-type name name) members)]
[inherited-decls
(apply append (map (lambda (n) (check-super-for-members name tenv-members n))
(map ast:type:object:iface-name supers)))]
[unique-inherited
;; remove duplicate entries for the same member name, making sure they match.
(check-and-remove-duplicate-members name inherited-decls)])
(extend-tenv-without-checking name
(make-tenv:type src-stx supers tenv-members unique-inherited))
defn)]
;; for classes and mixins, just add a new appropriate entry.
[(struct ast:defn:class (src-stx name t f? impls inits defns _))
(extend-tenv name (make-tenv:class src-stx t impls
(get-inits inits defns)
f? #f))
defn]
[(struct ast:defn:mixin (src-stx name type arg-type final? impls inits
withs _ defns-before defns-after _))
(extend-tenv name (make-tenv:mixin src-stx arg-type type impls
(get-inits inits
(append defns-before
defns-after))
withs final?))
defn]
;; all the heavy lifting of subclasses is in generate-subclass-tenv,
;; which does things like make sure that the withs of the mixin are satisfied
;; by the base, collects all the inits needed for the resulting class, etc.
[(struct ast:defn:subclass (src-stx name base mixin))
(extend-tenv name (generate-subclass-tenv defn))
defn]))
(define (convert-members iface members)
(let loop ([members members]
[converted '()])
(if (null? members)
(reverse converted)
(match (car members)
[(struct ast:iface/member:field (stx name type))
(loop (cdr members)
(cons (make-tenv:member stx name type) converted))]
[(struct ast:iface/member:method (stx name type arg-types))
(loop (cdr members)
(cons (make-tenv:member stx name (make-method-type stx
iface
(make-tuple-type stx arg-types)
type))
converted))]))))
(define (get-inits inits defns)
(let ([init-fields (filter (lambda (d)
(ast:class/member:field/formal? d))
defns)])
(append (map (lambda (i)
(make-tenv:init (ast:formal-name i)
(ast:formal-type i)
#f))
inits)
(map (lambda (d)
(make-tenv:init (ast:class/member-name d)
(ast:class/member:field/formal-type d)
(not (false? (ast:class/member:field/formal-default d)))))
init-fields))))
(define (generate-subclass-tenv defn)
(let ([base (get-class-entry (ast:defn:subclass-base defn))]
[mixin (get-mixin-entry (ast:defn:subclass-mixin defn))])
(let ([new-inits (remove-used-inits defn
(tenv:class-inits base)
(tenv:mixin-withs mixin))])
(make-tenv:class (ast-syntax defn)
(tenv:mixin-sub-type mixin)
(tenv:mixin-impls mixin)
(append (tenv:mixin-inits mixin)
new-inits)
(tenv:mixin-final? mixin)
(ast:defn:subclass-base defn)))))
(define (remove-used-inits defn old-inits withs)
(let loop ([old-inits old-inits]
[withs withs]
[new-inits '()])
(if (null? old-inits)
(if (not (null? withs))
(raise-read-error-with-stx
(format "Class ~a does not have an init arg ~a with the correct type"
(printable-key (ast:defn:subclass-base defn))
(printable-key (ast:formal-name (car withs))))
(ast:defn:subclass-base defn))
(reverse new-inits))
(let* ([curr (car old-inits)]
[index (list-index (lambda (w)
(tenv-key=? (ast:formal-name w) (tenv:init-name curr)))
withs)])
(if index
(if (<:_P (ast:formal-type (list-ref withs index)) (tenv:init-type curr))
(loop (cdr old-inits)
(append (take withs index)
(drop withs (+ index 1)))
new-inits)
(raise-read-error-with-stx
(format "Mixin ~a needs an incompatible type for init arg ~a"
(printable-key (ast:defn:subclass-mixin defn))
(printable-key (ast:formal-name (car withs))))
(ast:defn:subclass-mixin defn)))
(loop (cdr old-inits)
withs
(cons curr new-inits)))))))
(provide display-lenv display-current-lenv display-tenv display-current-tenv)
(define (display-current-lenv)
(display-lenv (current-lexical-environment)))
(define (display-lenv lenv)
(tenv-for-each lenv
(lambda (k v)
(display (format "~a = ~a~%"
(printable-key k)
(printable-type (tenv:value-type v)))))))
(define (display-current-tenv)
(display-lenv (current-type-environment)))
(define (display-tenv tenv)
(tenv-for-each tenv
(lambda (k v)
(display (format "~a = " (printable-key k)))
(display-tenv-entry v))))
(define (display-tenv-entry entry)
(match entry
[(struct tenv:type (_ supers members inherited))
(display (format "type {~%"))
(display (format " supers = "))
(if (null? supers) (display "(none)"))
(for-each (lambda (s) (display (format "~a " (printable-type s)))) supers)
(newline)
(display (format " members = "))
(if (null? members) (display "(none)"))
(newline)
(for-each (lambda (m)
(match m
[(struct tenv:member (_ name type))
(display (format " ~a : ~a~%"
(printable-key name)
(printable-type type)))]))
members)
(display (format " inherited members = "))
(if (null? inherited) (display "(none)"))
(newline)
(for-each (lambda (m)
(match m
[(struct tenv:member (_ name type))
(display (format " ~a : ~a~%"
(printable-key name)
(printable-type type)))]))
inherited)
(display (format "}~%"))]
[(struct tenv:class (_ sub-type impls inits final? super))
(display (format "class {~%"))
(display (format " final? = ~a~%" (if final? "yes" "no")))
(display (format " super = ~a~%" (if super (printable-key super) "(none)")))
(display (format " sub-type = ~a~%" (printable-type sub-type)))
(display (format " impls = "))
(for-each (lambda (s) (display (format "~a " (printable-type s)))) impls)
(if (null? impls) (display "(none)"))
(newline)
(display (format " inits = "))
(if (null? inits) (display "(none)"))
(newline)
(for-each (lambda (i) (display (format " ~a : ~a ~a~%"
(printable-key (tenv:init-name i))
(printable-type (tenv:init-type i))
(if (tenv:init-optional? i) "(opt)" ""))))
inits)
(display (format "}~%"))]
[(struct tenv:mixin (_ arg-type sub-type impls inits withs final?))
(display (format "mixin {~%"))
(display (format " final? = ~a~%" (if final? "yes" "no")))
(display (format " arg-type = ~a~%" (printable-type arg-type)))
(display (format " sub-type = ~a~%" (printable-type sub-type)))
(display (format " impls = "))
(for-each (lambda (s) (display (format "~a " (printable-type s)))) impls)
(if (null? impls) (display "(none)"))
(newline)
(display (format " inits = "))
(if (null? inits) (display "(none)"))
(newline)
(for-each (lambda (i) (display (format " ~a : ~a ~a~%"
(printable-key (tenv:init-name i))
(printable-type (tenv:init-type i))
(if (tenv:init-optional? i) "(opt)" ""))))
inits)
(display (format " withs = "))
(if (null? withs) (display "(none)"))
(newline)
(for-each (lambda (i) (display (format " ~a : ~a ~a~%"
(printable-key (tenv:init-name i))
(printable-type (tenv:init-type i))
(if (tenv:init-optional? i) "(opt)" ""))))
withs)
(display (format "}~%"))]))
)

Some files were not shown because too many files have changed in this diff Show More