commit 031ebf5c6b52a47d3b98184b2a82c5c955d5b5ea
Author: keyle <keyle@capsule.org>
Date: Sat, 16 May 2026 12:03:23 +1000
init
Diffstat:
| A | language2.bnf | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | language2.mty | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
| A | notes.md | | | 90 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 203 insertions(+), 0 deletions(-)
diff --git a/language2.bnf b/language2.bnf
@@ -0,0 +1,68 @@
+# 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
+
+# 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
+
+# `.` semantics:
+# In methods, `.` is the receiver. In free functions, `.` is the first argument.
+# In selectors and @(...), `.` is the current element.
diff --git a/language2.mty b/language2.mty
@@ -0,0 +1,45 @@
+ns app
+
+use io
+use math
+
+struct Vec2 ::
+ float x
+ float y
+
+ float len() where result >= 0.0 =
+ math.sqrt(.x ^ 2 + .y ^ 2)
+
+ int clamp(int x, int lo, int hi)
+ where lo <= hi
+ where result >= lo and result <= hi
+ =
+ min(max(x, lo), hi)
+
+struct Reading ::
+ int sensor
+ float value
+ bool valid
+
+ bool usable() =
+ .valid and .value >= 0.0;
+
+ str label() =
+ "high" if .value > 100.0 else "normal"
+
+pre #xs > 0
+float mean(float[] xs) = +/xs / #xs
+
+
+float[] values(Reading[] rows) =
+ rows[.usable()]
+ | @(.value)
+
+
+int main() ::
+ Reading[] rows = load_readings("readings.csv")
+ float[] xs = values(rows)
+
+ io.put("mean = " + str(mean(xs)))
+ ret 0
+
diff --git a/notes.md b/notes.md
@@ -0,0 +1,90 @@
+
+@(expr)
+-------
+
+Evaluate `expr` once per element, with . bound to the current element.
+
+```
+Examples:
+
+int[] doubled(int[] xs) =
+ xs | @(. * 2)
+
+str[] labels(Reading[] rows) =
+ rows | @("high" if .value > 100.0 else "normal")
+```
+
+Masking or filtering
+---------------------
+
+Masking/filtering works as you would expect at first, then evolves into something more like APL.
+
+It's best to call `[]` the Selector.
+
+```
+xs[i] // scalar index
+xs[is] // gather by int[] indices
+xs[mask] // compress by bool[] mask
+```
+
+`xs[3]` returns the 4th element
+`xs[[0 2]]` returns the first and 3rd element
+`xs[0..-1]` returns the range from the 1st, to the one before last
+`xs[[true, false, true]]` returns the mask against the collection, in this case 1st and 3rd.
+
+
+Selectors can also be using expression to filter collections
+
+`integer_list[. > 0]` returns values higher than 0
+`rows[.valid]` within a struct, invoke valid(element) on each element
+
+Implied self
+------------
+
+`.` is `self` within the context, it's the current subject.
+
+Inside a free function it's implied the first argument.
+
+`float len(Vec2) = math.sqrt(.x ^ 2 + .y ^ 2)`
+
+is equivalent to
+
+`float len(Vec2 v) = math.sqrt(v.x ^ 2 + v.y ^2)`
+
+inside a method of a struct, it's implied to this struct subject
+
+```
+struct Vec2 ::
+ float x, y
+ float len() = math.sqrt(.x ^ 2 + .y ^2)
+```
+
+Inside a selector, map, or other collection expr, `.` refers to the current element.
+
+`rows[valid]`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+