parser-fixes #7
Loading…
Reference in a new issue
No description provided.
Delete branch "parser-fixes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parser fixes based on review.
parse_type_group read each member with parse_type_atom, so a `|` inside parens was never consumed and the group failed with "expected ')' after type". That rejected the grammar's own disambiguation example (language-grammar.md: "(int| float)" is union), the spec's `type b = (int | float);` under Tuples, and two fixtures the manifest binds to the parse phase - union-propagation.cat's `*(x | y)` and interfaces.cat's `impl<T> ICollection<T> for ([]T | [..]T)`. Group and tuple members now parse as full union-types, which is what the grammar says: type-atom admits "(" union-type ")", and a tuple member is a type. Union Propagation makes `*(x|y)` and `*x|*y` equivalent, but that is a semantic rule - the parser preserves what was written and leaves distribution to a later phase. Known gap: `([]T | [..]T)` now parses, but both legs still dump as `([] T)` because TypeRef::ArrayDyn does not record the `..` (backlog #6), so interfaces.cat's head is not yet correct. Phase: parse. Backlog #1.>when closing generic arguments bd859af6ed`(int) -> a|b` parsed as `(| (fun int -> a) b)` - a union of a function and a `b`. The grammar says `function-type = "(" [ type … ] ")" "->" type`, and `type` is a union-type, so the arrow takes the whole return: `(fun int -> (| a b))`. unions.cat returns `bool | int` for exactly this reason. All three arrow arms in parse_type_group read the return with parse_type_atom; they now read it with parse_type_union. A union outside the arrow still parses that way when written that way: `((int) -> a) | b`. Phase: parse. Backlog #3.typeandvolatilef625b7e1ee?.from a ternary by adjacency fab7ea04aaResolves the overlap recorded during the grammar pass. Three `declaration` arms were derivable twice, and the AST carried the same duplication. - `var-decl` is a statement, and only a statement. A top-level `let` reaches `top-level-item` by way of `statement`. - `lambda-const` is deleted. `const f = (x: int) -> int { ... }` is a var-decl whose initializer is a func-value - a primary, hence an expr - so it never needed a production. It also gets the spec's overloading rule for free: only `function` overloads, and two `const f` bindings are a redeclaration rather than two candidates. - `static-member` stays a declaration, because it is one. The spec gives `Vector3::dot = (a, b) -> {...}` as the functional-style spelling of `function Vector3::dot(a, b) -> {...}` (Derived > Functions > Static and Instance), and `Vector3::dot` is not an lvalue an assignment could target. It is told from an expr-stmt by shape - qualified-name, `=`, func-value - and builds the same FunctionDecl the C-style spelling does, which is why FunctionDecl no longer needs an `is_lambda` flag and there is no static-member node. On the AST side that removes Decl::VarDecl, Decl::Attribute, Stmt::Attribute, and the is_lambda bool, and adds an `Item` enum mirroring `top-level-item` (attribute / declaration / statement) as what a Program holds. An impl body becomes Vec<Item> rather than Box<Stmt>: `impl-member` admits function declarations, which a Vec<Stmt> block could never have held - the function declarations are the point of an impl. That also makes an empty body contribute nothing to the dump, so ImplDecl now produces `(impl <T> I for (| ([] T) ([..] T)))` - the string 60-user-types.md asserted all along, and which I had "corrected" to include a `(block)` last pass. Backlog #37, #43; adds #44 (attributes still float rather than attaching to the declaration they bind to).Literal::Int was a u64, so no s128 or u128 value could be written - and after the overflow check landed those literals went from silently wrapping to being refused outright, which made the gap real rather than latent. token.rs called the width "a semantics concern, not a lexer one"; that was defensible while overflow wrapped and is not now. The spec's smallest-type rule ("numbers are assumed to be the smallest type that can store the literal") also needs the literal's real value to classify it, so the payload has to hold the widest thing anyone can write either way. Costs nothing in practice: Str(String) is already the widest Literal variant, so the 16-byte payload grows neither Literal nor Token. An array size stays u64 - an array indexed beyond u64 is not a thing - so the narrowing is a checked conversion rather than a cast, reported against the literal token rather than the cursor, which by then has moved past it and would have named the `]`. Phase: lex. Backlog #41.