@@ -33,9 +33,10 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
33
33
var fromBooleanSym : Symbol = uninitialized
34
34
var customWhileSym : Symbol = uninitialized
35
35
var dfcStack : List [Tree ] = Nil
36
+ val processDefs = mutable.Set .empty[Symbol ]
36
37
37
38
override val runsAfter = Set (transform.Pickler .name)
38
- override val runsBefore = Set (" MetaContextGen " )
39
+ override val runsBefore = Set (" CustomControl " )
39
40
40
41
override def prepareForDefDef (tree : DefDef )(using Context ): Context =
41
42
ContextArg .at(tree).foreach { t =>
@@ -61,6 +62,64 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
61
62
}
62
63
tree
63
64
65
+ def allDefsErrMsg (srcPos : util.SrcPos )(using Context ): Unit =
66
+ report.error(" Process blocks must only declare `def`s or no `def`s at all." , srcPos)
67
+
68
+ def fsmStatCheck (tree : Tree , returnCheck : Boolean )(using Context ): Unit =
69
+ tree match
70
+ case Block (stats, expr) =>
71
+ fsmStatCheck(stats, tree.srcPos)
72
+ expr match
73
+ case Literal (Constant (_ : Unit )) =>
74
+ case _ =>
75
+ stats.headOption match
76
+ case Some (dd : DefDef ) =>
77
+ allDefsErrMsg(expr.srcPos)
78
+ case _ =>
79
+ fsmStatCheck(expr, returnCheck)
80
+ case If (cond, thenp, elsep) =>
81
+ fsmStatCheck(thenp, returnCheck)
82
+ fsmStatCheck(elsep, returnCheck)
83
+ case Match (scrut, cases) =>
84
+ cases.foreach { case CaseDef (pat, guard, body) =>
85
+ fsmStatCheck(body, returnCheck)
86
+ }
87
+ case _ if returnCheck =>
88
+ tree match
89
+ case x @ Ident (stepName) if processDefs.contains(x.symbol) =>
90
+ case Apply (x @ Ident (stepName), _) if processDefs.contains(x.symbol) =>
91
+ case _ =>
92
+ report.error(
93
+ " Process `def`s must end with a call to a process `def` (it could be the same `def`)." ,
94
+ tree.srcPos
95
+ )
96
+ case Foreach (_, _, _, body, _) =>
97
+ fsmStatCheck(body, returnCheck = false )
98
+ case WhileDo (_, body) =>
99
+ fsmStatCheck(body, returnCheck = false )
100
+ case _ =>
101
+
102
+ def fsmStatCheck (trees : List [Tree ], srcPos : util.SrcPos )(using Context ): Unit =
103
+ val (allDefs : List [DefDef ] @ unchecked, allSteps : List [Tree ]) = (trees.partition {
104
+ case _ : DefDef => true
105
+ case _ => false
106
+ }): @ unchecked
107
+ if (allDefs.nonEmpty && allSteps.nonEmpty) allDefsErrMsg(srcPos)
108
+
109
+ var errFound = false
110
+ // checking process defs syntax and caching the process def symbols
111
+ allDefs.foreach {
112
+ case dd @ DefDef (_, Nil , retTypeTree, _) if retTypeTree.tpe =:= defn.UnitType =>
113
+ processDefs += dd.symbol
114
+ case dd =>
115
+ report.error(" Unexpected process `def` syntax. Must be `def xyz: Unit = ...`" , dd.srcPos)
116
+ errFound = true
117
+ }
118
+ if (! errFound)
119
+ allDefs.foreach { dd => fsmStatCheck(dd.rhs, returnCheck = true ) }
120
+ allSteps.foreach { step => fsmStatCheck(step, returnCheck = false ) }
121
+ end fsmStatCheck
122
+
64
123
object Step :
65
124
def unapply (tree : Tree )(using Context ): Option [Tree ] =
66
125
if (tree.tpe <:< stepRef && ! (tree.tpe =:= defn.NothingType ))
@@ -144,6 +203,29 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
144
203
ref(customWhileSym).appliedTo(guard).appliedTo(tree.body).appliedTo(dfc)
145
204
}.getOrElse(tree)
146
205
206
+ case class ProcessForever (scopeCtx : ValDef , block : Tree )
207
+ object ProcessForever :
208
+ def unapply (tree : Tree )(using Context ): Option [ProcessForever ] =
209
+ tree match
210
+ case Apply (
211
+ Apply (
212
+ Select (Ident (process), forever),
213
+ List (
214
+ Block (
215
+ List (dd @ DefDef (anonfun, List (List (scopeCtx : ValDef )), _, _)),
216
+ _ : Closure
217
+ )
218
+ )
219
+ ),
220
+ _
221
+ )
222
+ if anonfun.toString.startsWith(" $anonfun" ) && process.toString == " process" && forever
223
+ .toString == " forever" =>
224
+ Some (ProcessForever (scopeCtx, dd.rhs))
225
+ case _ =>
226
+ None
227
+ end ProcessForever
228
+
147
229
override def transformApply (tree : Apply )(using Context ): Tree =
148
230
tree match
149
231
case fe @ Foreach (iter, range, filters, body, dfc) =>
@@ -163,6 +245,10 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
163
245
.appliedTo(iter.genMeta, range, ifGuards)
164
246
.appliedTo(updatedBody)
165
247
.appliedTo(dfc)
248
+ case ProcessForever (scopeCtx, block) =>
249
+ fsmStatCheck(block, returnCheck = false )
250
+ processDefs.clear()
251
+ tree
166
252
case _ =>
167
253
tree
168
254
@@ -201,6 +287,7 @@ class LoopFSMPhase(setting: Setting) extends CommonPhase:
201
287
toFunc1Sym = requiredMethod(" dfhdl.core.r__For_Plugin.toFunc1" )
202
288
fromBooleanSym = requiredMethod(" dfhdl.core.r__For_Plugin.fromBoolean" )
203
289
customWhileSym = requiredMethod(" dfhdl.core.DFWhile.plugin" )
290
+ processDefs.clear()
204
291
ctx
205
292
end prepareForUnit
206
293
end LoopFSMPhase
0 commit comments