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 <<<
|
||||
> 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
|
@ -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))
|
||||
|
|
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
|
||||
(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))
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user