gradually typed functional honu
svn: r5616
This commit is contained in:
parent
a5df6154c1
commit
41f7592c11
|
@ -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
|
@ -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))
|
||||||
|
|
3
collects/honu-module/private/mzscheme.ss
Normal file
3
collects/honu-module/private/mzscheme.ss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
(module mzscheme mzscheme
|
||||||
|
(provide (all-from-except mzscheme
|
||||||
|
string)))
|
|
@ -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))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user