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 <<<
> 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
Java are roughly contract positions in dynamic Honu.
and run it like a `(module ...)' program.
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
obj - anything
string - character string
The following grammar is a lie, because Honu is extensible in a way
that doesn't fit BNFs. But it's (intended as) an accurate picture of
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
like...]
Definitions:
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) {
return x + 1;
}
Expressions:
(int -> int) g() {
return f;
}
<expr> := <literal>
| <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
tail position.
<binop> := + | - | * | / | %
| == | < | > | >= | <= | =
| && | ||
| ? | : // see note below
Assignment: =
Operators: + - * / %
Functions: stringToNumber numberToString
Operators have the same precedence as in Java
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,9 +1,9 @@
(module contexts mzscheme
(define-struct block-context ())
(define-struct block-context (return?))
(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 (function-definition-context definition-context) ())
(define-struct (value-definition-context definition-context) ())
@ -12,30 +12,40 @@
(define-struct expression-context ())
(define-struct type-context ())
(define-struct type-or-expression-context ())
(define-struct prototype-context ())
(define the-block-context (make-block-context))
(define the-top-block-context (make-top-block-context))
(define the-return-block-context (make-return-block-context))
(define the-block-context (make-block-context #f))
(define the-top-block-context (make-top-block-context #f))
(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-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-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)
(cond
[(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"]
[(variable-definition-context? ctx) "a variable-definition"]
[(constant-definition-context? ctx) "a constant-definition"]
[(function-definition-context? ctx) "a function-definition"]
[(prototype-context? ctx) "a function-definition"]
[else "an expression"]))
(provide block-context?
top-block-context?
return-block-context?
expression-block-context?
top-block-context?
definition-context?
function-definition-context?
@ -45,16 +55,25 @@
expression-context?
type-context?
type-or-expression-context?
prototype-context?
block-context-return?
the-block-context
the-top-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-constant-definition-context
the-function-definition-context
the-expression-context
the-type-context
the-type-or-expression-context
the-prototype-context
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
(provide unary-prefix-ops
unary-postfix-ops
(struct op (id))
(struct prefix ())
(struct cast-prefix (type))
(struct infix ())
(struct postfix ())
(struct postfix ())
prec-key
precedence-table
op-table)
(define unary-prefix-ops (list #'++
#'--
#'+
#'-
#'!
#'~))
(define unary-prefix-ops '(++
--
+
-
!
~))
(define unary-postfix-ops '(++
--))
(define-struct op (id))
(define-struct (prefix op) ())
(define-struct (cast-prefix prefix) (type))
(define-struct (infix op) ())
(define-struct (postfix op) ())
@ -33,6 +39,7 @@
'(((in . |.|) . 100)
((in . #%parens) . 100)
((in . #%brackets) . 100)
((in . #%angles) . 100)
((post . ++) . 100)
((post . --) . 100)
((pre . ++) . 95)
@ -41,6 +48,7 @@
((pre . -) . 95)
((pre . ~) . 95)
((pre . !) . 95)
((pre . #%parens) . 95)
((in . *) . 90)
((in . %) . 90)
((in . /) . 90)
@ -71,7 +79,10 @@
((in . \|=) . 10)
((in . <<=) . 10)
((in . >>=) . 10)
((in . >>>=) . 10))
((in . >>>=) . 10)
((in . \,) . 6)
((in . :) . 5)
((in . ?) . 4))
'equal))
(define op-table (make-hash-table))

View File

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