commit 2bbd72bef870cf1eb1e211cf566dab8309711d43
parent 791321af39c8203340815bd2747ddc10163b3f2b
Author: keyle <keyle@capsule.org>
Date: Sat, 16 May 2026 16:40:14 +1000
bnf stuff
Diffstat:
| M | language2.bnf | | | 160 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
1 file changed, 99 insertions(+), 61 deletions(-)
diff --git a/language2.bnf b/language2.bnf
@@ -1,67 +1,105 @@
# Mighty language2 sketch grammar
-# Layout produces INDENT/DEDENT after `::`.
-
-program ::= { top }
-top ::= namespace | use | struct | function
-
-namespace ::= "ns" path
-use ::= "use" path
-
-struct ::= "struct" Type "::" block(member)
-member ::= field | function
-field ::= type names
-names ::= name { "," name }
-
-function ::= { pre } signature { where } body
-pre ::= "pre" expr
-where ::= "where" expr # may mention contextual `result`
-signature ::= type name "(" [ params ] ")"
-params ::= param { "," param }
-param ::= type [ name ]
-body ::= "=" expr | "::" block(stmt)
-
-stmt ::= binding | ret | expr
-binding ::= type name "=" expr
-ret ::= "ret" expr
-
-type ::= path { "[]" }
-path ::= name { "." name }
-
-expr ::= conditional
-conditional ::= pipe [ "if" expr "else" expr ]
-pipe ::= reduce { "|" ( map | expr ) }
-map ::= "@" "(" expr ")" # each: `.` is the current element
-reduce ::= [ op "/" ] logic # +/xs, */xs, max/xs
-
-logic ::= compare { ( "and" | "or" ) compare }
-compare ::= range { cmp range }
-range ::= add [ ".." add ]
-add ::= mul { ( "+" | "-" ) mul }
-mul ::= pow { ( "*" | "/" ) pow }
-pow ::= unary { "^" unary }
-unary ::= [ "-" | "#" ] postfix # #xs is length/count
-
-postfix ::= atom { call | selector | "." name }
-call ::= "(" [ args ] ")"
-args ::= expr { "," expr }
-selector ::= "[" [ selectors ] "]" # index, gather, mask, or filter expr
-selectors ::= expr { [ "," ] expr }
-
-atom ::= literal | path | subject | array | "(" expr ")"
-subject ::= "." [ name ] # current subject/self/element
-array ::= "[" [ selectors ] "]"
-
-literal ::= int | float | string | "true" | "false"
-op ::= "+" | "*" | "&" | "|" | "min" | "max" | name
-cmp ::= "==" | "!=" | "<" | "<=" | ">" | ">="
-
-block(x) ::= INDENT { x } DEDENT
+
+program ::= { nl | top nl }
+nl ::= NEWLINE { NEWLINE }
+
+top ::= namespace | use | decl
+namespace ::= "ns" path
+use ::= "use" path
+decl ::= [ "pub" ] ( struct | function | operator )
+
+struct ::= "struct" Type [ generics ] "::" block(member)
+member ::= field | decl
+field ::= type names
+names ::= name { "," name }
+
+function ::= { pre nl } signature { where_part } body
+pre ::= "pre" expr
+where_part ::= [ nl ] where
+where ::= "where" constraint # may mention contextual `result`
+signature ::= type name [ generics ] "(" [ params ] ")"
+params ::= param { "," param }
+param ::= type [ name ]
+body ::= [ nl ] "=" ( expr | nl expr ) | "::" block(stmt)
+
+operator ::= "op" op [ generics ] "(" params ")" "->" type body
+
+stmt ::= binding | ret | expr
+binding ::= type name "=" expr
+ret ::= "ret" expr
+
+generics ::= "[" typevar { "," typevar } "]"
+typevar ::= Type
+constraint ::= expr | type_constraint
+type_constraint ::= Type ":" trait { "+" trait }
+trait ::= Type
+
+type ::= primary_type { type_suffix }
+primary_type ::= path [ type_args ] | "(" types ")"
+type_args ::= "[" type { "," type } "]"
+types ::= type { "," type }
+type_suffix ::= "[]" # slice/dynamic array
+ | "[" int_lit "]" # fixed array
+ | "?" # option: T?
+ | "!" type # result: T!E
+
+path ::= name { "." name }
+
+expr ::= conditional
+conditional ::= pipe [ "if" expr "else" expr ]
+pipe ::= scan { "|" ( map | expr ) }
+map ::= "@" "(" expr ")" # each: `.` is the current element
+scan ::= [ op "\\" ] reduce # +\xs, *\xs
+reduce ::= [ op "/" ] logic # +/xs, */xs, max/xs
+
+logic ::= compare { ( "and" | "or" ) compare }
+compare ::= range { cmp range }
+range ::= add [ ".." [ add ] ]
+add ::= mul { ( "+" | "-" ) mul }
+mul ::= pow { ( "*" | "/" ) pow }
+pow ::= unary { "^" unary }
+unary ::= [ "-" | "#" ] postfix # #xs is length/count
+
+postfix ::= atom { call | selector | "." name }
+call ::= "(" [ args ] ")"
+args ::= expr { "," expr }
+selector ::= "[" [ items ] "]" # index, gather, mask, or filter expr
+
+atom ::= literal | path | subject | array | record | "(" expr ")"
+subject ::= "." [ name ] # current subject/self/element
+array ::= "[" [ items ] "]"
+items ::= expr { "," expr }
+record ::= path "(" [ fields ] ")"
+fields ::= field_value { "," field_value }
+field_value ::= name ":" expr
+
+literal ::= int_lit | float_lit | string | "true" | "false" | "nil"
+op ::= "+" | "*" | "&" | "|" | "min" | "max" | name
+cmp ::= "==" | "!=" | "<" | "<=" | ">" | ">="
+
+block(x) ::= INDENT { nl | x nl } DEDENT
+
+# Lexical sketch: name is an identifier, Type is a capitalized identifier.
+# Comments run from // to end of line.
# Selector semantics:
-# xs[i] scalar index
-# xs[is] gather by int[] indices
-# xs[mask] compress by bool[] mask
-# xs[.valid] filter by expression evaluated per element
+# xs[i] scalar index
+# xs[[0, 2]] gather by int[] indices
+# xs[mask] compress by bool[] mask
+# xs[.valid] filter by expression evaluated per element
+
+# Array literals use commas: [1, 2, 3], [true, false, true].
+
+# Named record literals use Type(field: value): Vec2(x: 1.0, y: 2.0).
+
+# Ranges are half-open. Negative indices are relative to the end.
+# xs[0..-1] selects from the first element up to, not including, the last.
+
+# Reductions over empty collections are invalid unless the operator has a
+# defined identity. max/ and min/ require non-empty collections.
+
+# Values are passed by copy semantically. An implementation may pass by
+# read-only reference when that is observationally identical.
# `.` semantics:
# In methods, `.` is the receiver. In free functions, `.` is the first argument.