spec/ebnf: macroexpand order, set!, letfn primitive, numeric tower
Bring the formal definition in line with this session's language work: - grammar.ebnf: numbers are a real tower (exact integer / Ratio / double); the M suffix reads a real BigDecimal, N an exact integer (drop the stale Janet note). - 02-reader S5: M is a real java.math.BigDecimal with scale-insensitive equality. - 03-special-forms: document the read -> macroexpand -> analyze order (macros expand before special-form dispatch); special-form heads are not shadowable but macros are and value-position locals may be named like a special; set! on a var sets the innermost binding (else root); letfn is a primitive with letrec* semantics.
This commit is contained in:
parent
212cd0399a
commit
b9ab750983
3 changed files with 25 additions and 10 deletions
|
|
@ -50,11 +50,12 @@ collection = list | vector | map ;
|
|||
nil = "nil" ;
|
||||
boolean = "true" | "false" ;
|
||||
|
||||
(* Numbers. Jolt accepts Clojure's numeric literal syntaxes, but — since Jolt
|
||||
numbers are Janet ints/doubles — it has no distinct bignum, ratio or
|
||||
BigDecimal types: the BigInt suffix N and BigDecimal suffix M are read as the
|
||||
plain number, a ratio a/b is read as its double quotient, and radixed
|
||||
integers are computed by base. The symbolic floats ##Inf/##-Inf/##NaN are
|
||||
(* Numbers. Jolt carries a real numeric tower (JVM parity): an integer literal
|
||||
reads as an exact integer (arbitrary precision), a ratio a/b as an exact
|
||||
Ratio, a decimal/exponent literal as a double. The BigDecimal suffix M reads
|
||||
as a real BigDecimal (unscaled x 10^-scale) — 1.5M, 0.0M, 3M; class is
|
||||
java.math.BigDecimal. The BigInt suffix N reads as an exact integer. Radixed
|
||||
integers are computed by base; the symbolic floats ##Inf/##-Inf/##NaN are
|
||||
also read. (No octal-with-leading-0 literal.) *)
|
||||
number = symbolic-value
|
||||
| [ sign ] , ( radix-int | ratio | hex-int | decimal ) ;
|
||||
|
|
@ -62,10 +63,10 @@ sign = "+" | "-" ;
|
|||
integer = digit , { digit } ;
|
||||
hex-int = "0" , ( "x" | "X" ) , hex-digit , { hex-digit } , [ "N" ] ;
|
||||
radix-int = integer , ( "r" | "R" ) , alnum , { alnum } ; (* base 2..36: 2r1010, 16rFF, 36rZ *)
|
||||
ratio = integer , "/" , integer ; (* read as a double quotient *)
|
||||
ratio = integer , "/" , integer ; (* exact Ratio *)
|
||||
decimal = integer , [ "." , digit , { digit } ] , [ exponent ] , [ num-suffix ] ;
|
||||
exponent = ( "e" | "E" ) , [ sign ] , digit , { digit } ;
|
||||
num-suffix = "N" | "M" ; (* BigInt / BigDecimal in Clojure; plain number in Jolt *)
|
||||
num-suffix = "N" | "M" ; (* N = exact integer (BigInt); M = BigDecimal *)
|
||||
symbolic-value = "##Inf" | "##-Inf" | "##NaN" ;
|
||||
digit = "0".."9" ;
|
||||
hex-digit = digit | "a".."f" | "A".."F" ;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,10 @@ exponent := [eE] ['+'|'-'] digits
|
|||
- S5. Trailing `N` (BigInt) and `M` (BigDecimal) suffixes are part of the
|
||||
grammar; their value semantics are the §4 numeric-tower question.
|
||||
Implementations without those towers SHOULD read them as the nearest
|
||||
numeric type and MUST document the choice.
|
||||
numeric type and MUST document the choice. The Chez host carries the full
|
||||
tower: `N` reads as an exact integer (arbitrary precision) and `M` as a real
|
||||
BigDecimal — `1.5M`, `0.0M`, `3M` — with value equality ignoring scale
|
||||
(`1.0M = 1.00M`), `(class 1.5M)` ⇒ `java.math.BigDecimal`, and `decimal?` true.
|
||||
|
||||
### Symbols and keywords
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,17 @@ syntax is specified here, their behavior is host-defined.
|
|||
|
||||
Special-form head symbols are not shadowable: a binding named `if` does not
|
||||
change the meaning of `(if ...)` in operator position. ⚠ This matches the
|
||||
reference; it differs from Scheme.
|
||||
reference; it differs from Scheme. A local *may* legally be named like a special
|
||||
form and used in value position (`(let [if 5] if)` ⇒ `5`); only operator
|
||||
position is reserved. **Macros, unlike special forms, ARE shadowable** by a local
|
||||
(`(let [when (fn ...)] (when 1 2))` calls the local).
|
||||
|
||||
A list form in operator position is resolved in this order (the canonical
|
||||
read → **macroexpand** → analyze pipeline): a local binding shadows everything;
|
||||
otherwise a macro head is expanded and the result re-analyzed; otherwise a
|
||||
special-form head is parsed by rule; otherwise the form is a function
|
||||
application. Macroexpansion therefore happens *before* special-form dispatch, so
|
||||
a macro is never mistaken for a special form (and vice versa).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -135,10 +145,11 @@ S1–S3, E1 → jolt `forms-spec` let group; clojure-test-suite
|
|||
| `do` | empty `(do)` → nil; top-level `do` splices for compilation units (important and under-documented) |
|
||||
| `fn*` | arities, variadic `&`, closure capture, self-name, simple-symbol params only, recur target |
|
||||
| `loop*` | recur arity must match bindings; recur rebinds in place |
|
||||
| `letfn` | mutually-recursive local fns (`letrec*` semantics — a fn body sees every binding, not only earlier ones). jolt treats `letfn` as a primitive special, not the reference's `letfn` macro → `letfn*` indirection; behavior is identical |
|
||||
| `recur` | tail-position rule (normative definition of tail position needed), across `if`/`do`/`let*`/`try` interactions |
|
||||
| `quote` | self-evaluation table: which literals are self-evaluating unquoted |
|
||||
| `var` | `#'` reader sugar; resolution at compile time |
|
||||
| `throw` | any value vs Throwable — host question; jolt/cljs allow data, reference requires Throwable → classification needed |
|
||||
| `try/catch/finally` | catch dispatch order, `:default`-style catch-all is a dialect extension (⚠ divergence note), finally evaluation guarantees, value of try |
|
||||
| `set!` | host-dependent (dynamic vars + host fields) |
|
||||
| `set!` | `(set! *var* val)` sets the var's innermost thread binding, else its root, and returns val (implemented); a local (deftype mutable field) or host `(.-field obj)` target is host-dependent |
|
||||
| `.` / `new` | syntax only; behavior host-defined |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue