Skip to content

Commit

Permalink
Merge pull request #1657 from DanielXMoore/more-for
Browse files Browse the repository at this point in the history
`for concat` reduction for concatenating arrays, `for first` reduction for finding elements
  • Loading branch information
edemaine authored Dec 24, 2024
2 parents fd1aaa4 + 00a2d44 commit aa4fcf9
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 4 deletions.
26 changes: 24 additions & 2 deletions civet.dev/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1982,6 +1982,19 @@ numEven := for count item of array
numKeys := for count key in object
</Playground>
`for first` returns the first body value.
If there is no body, it uses the item being looped over.
Combined with a `when` condition, this can act like
[`Array.prototype.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
<Playground>
firstEven :=
for first item of array when item % 2 === 0
firstEvenSquare :=
for first item of array when item % 2 === 0
item * item
</Playground>
`for sum` adds up the body values with `+`, starting from `0`.
If there is no body, it adds the item being looped over.
Expand Down Expand Up @@ -2013,10 +2026,19 @@ It's like `for sum` but starting from `""` instead of `0`.
<Playground>
all := for join item of array
`[${item.type}] ${item.title}`
`[${item.type}] ${item.title}\n`
</Playground>
`for concat` concatenates the body values as arrays,
using the [concat operator `++`](#concat-operator).
If there is no body, it uses the item being looped over.
<Playground>
function flat1<T>(arrays: T[][]): T[]
for concat array of arrays
</Playground>
Implicit bodies in `for sum/product/min/max/join` reductions
Implicit bodies in `for sum/product/min/max/join/concat` reductions
can use a single destructuring:
<Playground>
Expand Down
2 changes: 1 addition & 1 deletion source/parser.hera
Original file line number Diff line number Diff line change
Expand Up @@ -4774,7 +4774,7 @@ ForStatementControlWithReduction
return { ...control, reduction }

ForReduction
( "some" / "every" / "count" / "sum" / "product" / "min" / "max" / "join" ):subtype NonIdContinue __:ws ->
( "some" / "every" / "count" / "first" / "sum" / "product" / "min" / "max" / "join" / "concat" ):subtype NonIdContinue __:ws ->
return {
type: "ForReduction",
subtype,
Expand Down
6 changes: 6 additions & 0 deletions source/parser/function.civet
Original file line number Diff line number Diff line change
Expand Up @@ -744,10 +744,12 @@ function iterationDeclaration(statement: IterationStatement | ForStatement)
switch reduction.subtype
when "some" then "false"
when "every" then "true"
when "first" then "undefined"
when "min" then "Infinity"
when "max" then "-Infinity"
when "product" then "1"
when "join" then '""'
when "concat" then "[]"
else "0"
else if statement.object
declaration.children.push "={}"
Expand Down Expand Up @@ -775,7 +777,11 @@ function iterationDeclaration(statement: IterationStatement | ForStatement)
resultsRef, " = false; break}" ]
when "count"
[ "if (", node, ") ++", resultsRef ]
when "first"
[ resultsRef, " = ", node, "; break" ]
when "sum", "join" then [ resultsRef, " += ", node ]
when "concat"
[ getHelperRef("concatAssign"), "(", resultsRef, ", ", node, ")" ]
when "product" then [ resultsRef, " *= ", node ]
when "min" then [ resultsRef, " = Math.min(", resultsRef, ", ", node, ")" ]
when "max" then [ resultsRef, " = Math.max(", resultsRef, ", ", node, ")" ]
Expand Down
2 changes: 1 addition & 1 deletion source/parser/types.civet
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ export type ForDeclaration

export type ForReduction
type: "ForReduction"
subtype: "some" | "every" | "count" | "sum" | "product" | "min" | "max" | "join"
subtype: "some" | "every" | "count" | "find" | "sum" | "product" | "min" | "max" | "first" | "concat"

export type SwitchStatement
type: "SwitchStatement"
Expand Down
31 changes: 31 additions & 0 deletions test/for.civet
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,37 @@ describe "for", ->
const h =(()=>{let results7="";for (const x of y) { results7 += x }return results7})()
"""

testCase """
for concat
---
flat := for concat x of y
numbers := for concat x of y
[x, x+1]
---
var concatAssign: <B, A extends {push: (this: A, b: B) => void} | (B extends unknown[] ? {push: (this: A, ...b: B) => void} : never)>(lhs: A, rhs: B) => A = (lhs, rhs) => (((rhs as any)?.[Symbol.isConcatSpreadable] ?? Array.isArray(rhs)) ? (lhs as any).push.apply(lhs, rhs as any) : (lhs as any).push(rhs), lhs);
let results=[];for (const x of y) {concatAssign(results, x)};const flat =results
let results1=[];for (const x of y) {
concatAssign(results1, [x, x+1])
};const numbers =results1
"""

testCase """
for first
---
first := for first x of y
positive := for first x of y when x > 0
complex := for first x of y
continue unless x > 0
x * x
---
let results=undefined;for (const x of y) {results = x; break};const first =results
let results1=undefined;for (const x of y) {if (!(x > 0)) continue;results1 = x; break};const positive =results1
let results2=undefined;for (const x of y) {
if (!(x > 0)) { continue }
results2 = x * x; break
};const complex =results2
"""

testCase """
implicit body array destructuring
---
Expand Down

0 comments on commit aa4fcf9

Please sign in to comment.