@@ -49,6 +49,7 @@ sealed abstract class Block extends Product with AutoLocated:
4949 case Begin (sub, rst) => sub.size + rst.size
5050 case Assign (_, _, rst) => 1 + rst.size
5151 case AssignField (_, _, _, rst) => 1 + rst.size
52+ case AssignDynField (_, _, _, _, rst) => 1 + rst.size
5253 case Match (_, arms, dflt, rst) =>
5354 1 + arms.map(_._2.size).sum + dflt.map(_.size).getOrElse(0 ) + rst.size
5455 case Define (_, rst) => 1 + rst.size
@@ -132,6 +133,45 @@ sealed abstract class Block extends Product with AutoLocated:
132133 case _ => super .applyBlock(b)
133134
134135 (transformer.applyBlock(this ), defns)
136+
137+ lazy val flatten : Block =
138+ // traverses a Block like a list, flatten `Begin`s using an accumulator
139+ // returns the flattend but reversed Block (with the dummy tail `End("for flatten only")`) and the actual tail of the Block
140+ def getReversedFlattenAndTrueTail (b : Block , acc : Block ): (Block , BlockTail ) = b match
141+ case Match (scrut, arms, dflt, rest) => getReversedFlattenAndTrueTail(rest, Match (scrut, arms, dflt, acc))
142+ case Label (label, body, rest) => getReversedFlattenAndTrueTail(rest, Label (label, body, acc))
143+ case Begin (sub, rest) =>
144+ val (firstBlockRev, firstTail) = getReversedFlattenAndTrueTail(sub, acc)
145+ firstTail match
146+ case _ : End => getReversedFlattenAndTrueTail(rest, firstBlockRev)
147+ // if the tail of `sub` is not `End`, ignore the `rest` of this `Begin`
148+ case _ => firstBlockRev -> firstTail
149+ case TryBlock (sub, finallyDo, rest) => getReversedFlattenAndTrueTail(rest, TryBlock (sub, finallyDo, acc))
150+ case Assign (lhs, rhs, rest) => getReversedFlattenAndTrueTail(rest, Assign (lhs, rhs, acc))
151+ case a@ AssignField (lhs, nme, rhs, rest) => getReversedFlattenAndTrueTail(rest, AssignField (lhs, nme, rhs, acc)(a.symbol))
152+ case AssignDynField (lhs, fld, arrayIdx, rhs, rest) => getReversedFlattenAndTrueTail(rest, AssignDynField (lhs, fld, arrayIdx, rhs, acc))
153+ case Define (defn, rest) => getReversedFlattenAndTrueTail(rest, Define (defn, acc))
154+ case HandleBlock (lhs, res, par, args, cls, handlers, body, rest) => getReversedFlattenAndTrueTail(rest, HandleBlock (lhs, res, par, args, cls, handlers, body, acc))
155+ case t : BlockTail => acc -> t
156+
157+ // reverse the Block returnned from the previous function,
158+ // which does not contain `Begin` (except for the nested ones),
159+ // and whose tail must be the dummy `End("for flatten only")`
160+ def rev (b : Block , t : Block ): Block = b match
161+ case Match (scrut, arms, dflt, rest) => rev(rest, Match (scrut, arms, dflt, t))
162+ case Label (label, body, rest) => rev(rest, Label (label, body, t))
163+ case TryBlock (sub, finallyDo, rest) => rev(rest, TryBlock (sub, finallyDo, t))
164+ case Assign (lhs, rhs, rest) => rev(rest, Assign (lhs, rhs, t))
165+ case a@ AssignField (lhs, nme, rhs, rest) => rev(rest, AssignField (lhs, nme, rhs, t)(a.symbol))
166+ case AssignDynField (lhs, fld, arrayIdx, rhs, rest) => rev(rest, AssignDynField (lhs, fld, arrayIdx, rhs, t))
167+ case Define (defn, rest) => rev(rest, Define (defn, t))
168+ case HandleBlock (lhs, res, par, args, cls, handlers, body, rest) => rev(rest, HandleBlock (lhs, res, par, args, cls, handlers, body, t))
169+ case End (msg) => t
170+ case _ : BlockTail => ??? // unreachable
171+ case Begin (sub, rest) => ??? // unreachable
172+
173+ val (flattenRev, actualTail) = getReversedFlattenAndTrueTail(this , End (" for flatten only" ))
174+ rev(flattenRev, actualTail)
135175
136176end Block
137177
0 commit comments