158 lines
5.6 KiB
Plaintext
158 lines
5.6 KiB
Plaintext
|
|
>>> FOR NOW, THIS IS AN EXPERIMENTAL TOY <<<
|
|
> Everything is subject to change. <
|
|
|
|
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).
|
|
|
|
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".]
|
|
|
|
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>
|
|
...
|
|
|
|
and run it like a `(module ...)' program.
|
|
|
|
Each <stmt> as a top-level <stmt|defn> is implicitly wrapped to print
|
|
the result of the <stmt> (if the result is not void).
|
|
|
|
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.
|
|
|
|
Types:
|
|
|
|
<type> := obj // anything
|
|
| bool
|
|
| int // exact integer
|
|
| string // character string
|
|
| (<type>* -> <type>) // procedure
|
|
| (<id>* >-> <type>) // generic
|
|
| <id> // if bound as generic argument
|
|
|
|
Definitions:
|
|
|
|
<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>* }
|
|
|
|
<arg> := <id> // same as `obj <id>'
|
|
| <type> <id>
|
|
|
|
The <defn> form is a generic-procedure definition.
|
|
|
|
Expressions:
|
|
|
|
<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>* }
|
|
|
|
<literal> := <number>
|
|
| <string>
|
|
| true | false
|
|
|
|
<binop> := + | - | * | / | %
|
|
| == | < | > | >= | <= | =
|
|
| && | ||
|
|
| ? | : // see note below
|
|
|
|
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]
|