gradually typed functional honu

svn: r5616
This commit is contained in:
Matthew Flatt 2007-02-15 08:14:18 +00:00
parent a5df6154c1
commit 41f7592c11
7 changed files with 2264 additions and 1233 deletions

View File

@ -2,48 +2,156 @@
>>> FOR NOW, THIS IS AN EXPERIMENTAL TOY <<< >>> FOR NOW, THIS IS AN EXPERIMENTAL TOY <<<
> Everything is subject to change. < > Everything is subject to change. <
Write a dynamically typed Honu program as Honu is a "gradual-ly typed" language. That is, it's statically typed,
but any expression can have type `obj', and an expresion of type `obj'
is implicitly coreced to any other type by inserting run-time checks
(with delayed checks for higher-order values, as in a contract
system).
#honu dynamic Every identifier binding has a declared type --- it's `obj' if an
optional <type> is omitted --- and every function has a declared
return type. Types for expressions are inferred in the obvious
way. [TODO: explain "obvious".]
<defn-or-provide> The syntax is much like Java, but also slightly influenced by
Javascript, since functions are first-class values. Honu support
higher-order parametric polymorphism, for which it uses the Java
"generic" terminology.
There no no classes/records, yet. That's the next step.
Write a Honu program as
#honu
<stmt|defn|impexp>
... ...
The syntax of a definition is much like Java, and type positions in and run it like a `(module ...)' program.
Java are roughly contract positions in dynamic Honu.
The only supported base "types" right now are Each <stmt> as a top-level <stmt|defn> is implicitly wrapped to print
the result of the <stmt> (if the result is not void).
int - exact integer The following grammar is a lie, because Honu is extensible in a way
obj - anything that doesn't fit BNFs. But it's (intended as) an accurate picture of
string - character string the initial grammar before any extensions.
and the only "type constructor" is Types:
(_ -> _) <type> := obj // anything
| bool
| int // exact integer
| string // character string
| (<type>* -> <type>) // procedure
| (<id>* >-> <type>) // generic
| <id> // if bound as generic argument
where "_" is to be replaced with a "type". [Ok, "->" is not very Java Definitions:
like...]
Every declaration must have a value, like this: <defn> := var [<type>] <id> = <expr>; // <type> defaults to `obj'
| const [<type>] <id> = <expr>; // prohibits assignment
| <type> <id> = <expr>;
| <type> id(<arg>,*) { <stmt|defn>* }
| < <id>,* > <type> id(<arg>,*) { <stmt|defn>* }
#honu dynamic <arg> := <id> // same as `obj <id>'
| <type> <id>
int v = 10; The <defn> form is a generic-procedure definition.
int f(int x) { Expressions:
return x + 1;
}
(int -> int) g() { <expr> := <literal>
return f; | <expr> <binop> <expr>
} | <unpreop> <expr>
| <expr> <unpostop>
| (<expr>)
| { <stmt|defn>* }
| (type)<expr> // cast
| <expr>(<expr>,*) // procedure call
| <expr> [ <expr> ] // array access (eventually)
| <expr> < <type>,* > // generic instantiation
| [type] function(<arg>,*) { <stmt|defn>* } // anon function
| < <id>,* > [type] function(<arg>,*) { <stmt|defn>* }
provide f, g; <literal> := <number>
| <string>
| true | false
The "return" keyword is optional, but allowed only for expressions in <binop> := + | - | * | / | %
tail position. | == | < | > | >= | <= | =
| && | ||
| ? | : // see note below
Assignment: = Operators have the same precedence as in Java
Operators: + - * / %
Functions: stringToNumber numberToString Note: `<expr> ? <expr> : <expr>' is currently parsed as
`(<expr> ? (<expr> : <expr>))', where `?' looks for
`:' in its second argument.
Statements:
<stmt|defn> := <stmt>
| <defn> // in non-tail positions, only
<stmt> := <expr> ;
| if (<expr>) <branch>
| if (<expr>) <branch> else <branch>
| return <stmt> // in tail positions, only
| time <expr> ;
<branch> := { <stmt>* }
| <stmt>
Imports and exports:
<stmt|defn|impexp> := <stmt|defn>
| provide <id>,* ;
------------------------------------------------------------------------
About Honu Parsing and Typechecking
-----------------------------------
A Honu program is first parsed by using the MzScheme reader, which
goes into H-expression mode due to the leading #honu. This read phase
tokenizes and groups based on parens, braces, brackets, and (under
certain circumstances) angle brackets. See the MzScheme manual for
details.
The program is then parsed, expanded (including translation to
Scheme), and type-checked all at once. Thus, the parsing of a term can
depend on the type assigned by the context.
Parsing proceeds by taking the first thing in the reader's output and
checking whether it has a binding as a Honu transformer. For example
`int' will have a binding to a transformer that expands the next bit
of the stream to a variable or function definition. This transformer
check is performed when the stream starts with an identifier or a
parenthesized group (<h-expr> ...) includes only one operator
identifier; in the latter case, the operator is used for looking up a
transformer. For example, `(int -> int)' starts a definition because
`->' is bound to a transformer.
A transformer takes the current stream and a context object; it
returns a Scheme expression and the unconsumed part of the stream. The
Scheme expression is likely to contain unparsed H-expression
representations in a `honu-unparsed-block' form, which is bound to a
Scheme macro in the usual way to continue parsing later.
A context object can be anything. The base Honu grammar implies
several kinds of contexts, each with its own record type (described
later). A transformer should expand only in contexts that it
recognizes, and it should raise a syntax error when given any context
that it doesn't recognize. A transformer might expand differently in
different contexts. For example, `int' expands to a definition in a
block context (e.g., at the top level), but to a type description in a
type context (e.g., in a procedure's formal argument list).
When the start of the stream offers no other guidance, it is parsed as
an expression. The expression-parsing rules are essentially hardwired
to the Java grammar rules. (In the future, programmers will likely
have control over precedence, at least.)
[to be continued]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
(module contexts mzscheme (module contexts mzscheme
(define-struct block-context ()) (define-struct block-context (return?))
(define-struct (top-block-context block-context) ()) (define-struct (top-block-context block-context) ())
(define-struct (return-block-context block-context) ()) (define-struct (expression-block-context block-context) ())
(define-struct definition-context ()) (define-struct definition-context ())
(define-struct (function-definition-context definition-context) ()) (define-struct (function-definition-context definition-context) ())
@ -12,30 +12,40 @@
(define-struct expression-context ()) (define-struct expression-context ())
(define-struct type-context ()) (define-struct type-context ())
(define-struct type-or-expression-context ())
(define-struct prototype-context ())
(define the-block-context (make-block-context)) (define the-block-context (make-block-context #f))
(define the-top-block-context (make-top-block-context)) (define the-top-block-context (make-top-block-context #f))
(define the-return-block-context (make-return-block-context)) (define the-expression-block-context (make-expression-block-context #f))
(define the-return-block-context (make-block-context #t))
(define the-expression-return-block-context (make-expression-block-context #t))
(define the-function-definition-context (make-function-definition-context))
(define the-variable-definition-context (make-variable-definition-context)) (define the-variable-definition-context (make-variable-definition-context))
(define the-constant-definition-context (make-constant-definition-context)) (define the-constant-definition-context (make-constant-definition-context))
(define the-function-definition-context (make-function-definition-context))
(define the-expression-context (make-expression-context)) (define the-expression-context (make-expression-context))
(define the-type-context (make-type-context)) (define the-type-context (make-type-context))
(define the-type-or-expression-context (make-type-or-expression-context))
(define the-prototype-context (make-prototype-context))
(define (context->name ctx) (define (context->name ctx)
(cond (cond
[(type-context? ctx) "a type"] [(type-context? ctx) "a type"]
[(type-or-expression-context? ctx) "a type or expression"]
[(expression-context? ctx) "an expression"]
[(expression-block-context? ctx) "a statement"]
[(block-context? ctx) "a block"] [(block-context? ctx) "a block"]
[(variable-definition-context? ctx) "a variable-definition"] [(variable-definition-context? ctx) "a variable-definition"]
[(constant-definition-context? ctx) "a constant-definition"] [(constant-definition-context? ctx) "a constant-definition"]
[(function-definition-context? ctx) "a function-definition"] [(function-definition-context? ctx) "a function-definition"]
[(prototype-context? ctx) "a function-definition"]
[else "an expression"])) [else "an expression"]))
(provide block-context? (provide block-context?
expression-block-context?
top-block-context? top-block-context?
return-block-context?
definition-context? definition-context?
function-definition-context? function-definition-context?
@ -45,16 +55,25 @@
expression-context? expression-context?
type-context? type-context?
type-or-expression-context?
prototype-context?
block-context-return?
the-block-context the-block-context
the-top-block-context the-top-block-context
the-return-block-context the-return-block-context
the-expression-block-context
the-expression-return-block-context
the-function-definition-context make-function-definition-context
the-variable-definition-context the-variable-definition-context
the-constant-definition-context the-constant-definition-context
the-function-definition-context
the-expression-context the-expression-context
the-type-context the-type-context
the-type-or-expression-context
the-prototype-context
context->name)) context->name))

View File

@ -0,0 +1,3 @@
(module mzscheme mzscheme
(provide (all-from-except mzscheme
string)))

View File

@ -1,23 +1,29 @@
(module ops mzscheme (module ops mzscheme
(provide unary-prefix-ops (provide unary-prefix-ops
unary-postfix-ops
(struct op (id)) (struct op (id))
(struct prefix ()) (struct prefix ())
(struct cast-prefix (type))
(struct infix ()) (struct infix ())
(struct postfix ()) (struct postfix ())
prec-key prec-key
precedence-table precedence-table
op-table) op-table)
(define unary-prefix-ops (list #'++ (define unary-prefix-ops '(++
#'-- --
#'+ +
#'- -
#'! !
#'~)) ~))
(define unary-postfix-ops '(++
--))
(define-struct op (id)) (define-struct op (id))
(define-struct (prefix op) ()) (define-struct (prefix op) ())
(define-struct (cast-prefix prefix) (type))
(define-struct (infix op) ()) (define-struct (infix op) ())
(define-struct (postfix op) ()) (define-struct (postfix op) ())
@ -33,6 +39,7 @@
'(((in . |.|) . 100) '(((in . |.|) . 100)
((in . #%parens) . 100) ((in . #%parens) . 100)
((in . #%brackets) . 100) ((in . #%brackets) . 100)
((in . #%angles) . 100)
((post . ++) . 100) ((post . ++) . 100)
((post . --) . 100) ((post . --) . 100)
((pre . ++) . 95) ((pre . ++) . 95)
@ -41,6 +48,7 @@
((pre . -) . 95) ((pre . -) . 95)
((pre . ~) . 95) ((pre . ~) . 95)
((pre . !) . 95) ((pre . !) . 95)
((pre . #%parens) . 95)
((in . *) . 90) ((in . *) . 90)
((in . %) . 90) ((in . %) . 90)
((in . /) . 90) ((in . /) . 90)
@ -71,7 +79,10 @@
((in . \|=) . 10) ((in . \|=) . 10)
((in . <<=) . 10) ((in . <<=) . 10)
((in . >>=) . 10) ((in . >>=) . 10)
((in . >>>=) . 10)) ((in . >>>=) . 10)
((in . \,) . 6)
((in . :) . 5)
((in . ?) . 4))
'equal)) 'equal))
(define op-table (make-hash-table)) (define op-table (make-hash-table))

View File

@ -1,9 +1,13 @@
(module util mzscheme (module util mzscheme
(provide extract-until) (provide delim-identifier=?
extract-until)
(require (lib "stx.ss" "syntax")) (require (lib "stx.ss" "syntax"))
(define (delim-identifier=? a b)
(eq? (syntax-e a) (syntax-e b)))
(define extract-until (define extract-until
(case-lambda (case-lambda
[(r ids keep?) [(r ids keep?)
@ -13,7 +17,7 @@
(values #f #f #f)] (values #f #f #f)]
[(and (identifier? (stx-car r)) [(and (identifier? (stx-car r))
(ormap (lambda (id) (ormap (lambda (id)
(module-identifier=? id (stx-car r))) (delim-identifier=? id (stx-car r)))
ids)) ids))
(values (reverse (if keep? (values (reverse (if keep?
(cons (stx-car r) val-stxs) (cons (stx-car r) val-stxs)