@@ -15,96 +15,90 @@ import scala.annotation.targetName
1515import effekt .core .Type .TString
1616import effekt .source .FeatureFlag
1717import effekt .generator .llvm .Transformer .llvmFeatureFlags
18+ import effekt .core .ExternBody .StringExternBody
19+ import effekt .core .ExternBody .Unsupported
1820
1921object Show extends Phase [CoreTransformed , CoreTransformed ] {
2022
2123 override val phaseName : String = " show"
2224
23- case class ShowContext (showDefnsMap : Map [List [ValueType ], Block .BlockVar ], groundTypes : List [ValueType ], var defnsToGenerate : collection.mutable.Map [ValueType , Id ], infixConcatFn : Block .BlockVar )
25+ case class ShowContext (showDefns : collection.mutable.Map [ValueType , Id ], backend : String , externFns : Map [String , Extern .Def ]) {
26+ def getShowBlockVar (vt : ValueType ): Block .BlockVar =
27+ val showId = showDefns(vt)
28+ Block .BlockVar (showId, BlockType .Function (List .empty, List .empty, List (vt), List .empty, TString ), Set .empty)
29+
30+ def externBlockVar (name : String ): Block .BlockVar =
31+ val fn = externFns(name)
32+ Block .BlockVar (fn.id, BlockType .Function (fn.tparams, fn.cparams, fn.vparams map (_.tpe), fn.bparams map (_.tpe), fn.ret), fn.annotatedCapture)
33+ }
2434
2535 override def run (input : CoreTransformed )(using Context ): Option [CoreTransformed ] = input match {
2636 case CoreTransformed (source, tree, mod, core) => {
27-
28- // Collect all extern definitions that are named "show"
29- // Record what type of values these functions take as arguments
30- // Store these in a Map so we know our ground types
31- // Map[Int -> show#1, Char -> show#2, ...]
32- val extShowDefns : List [Extern .Def ] = core.externs.flatMap(ext => ext match
33- case e : Extern .Def => List (e)
34- case _ => List ()
37+ // 1. Find ids of relevant extern functions by name
38+ val externFnNames = List (
39+ " myshow" ,
40+ " infixConcat" ,
41+ " c_bytearray_show_Int" ,
42+ " c_bytearray_show_Byte" ,
43+ " c_bytearray_show_Double" ,
3544 )
36- // TODO: Could be more specific in filtering here
37- // for example only allow functions with one argument
38- // which return Strings
39- .filter(defn => defn.id.name.name == " show" )
40-
41- val myshow = core.externs.flatMap(ext => ext match
42- case e : Extern .Def => List (e)
43- case _ => List ()
45+ val externFns = findRelevantExterns(core.externs, externFnNames)
46+
47+ // 2. Define list of base types to synthesize definitions for
48+ // 2.1 actual base types (Int, Char, ...)
49+ var builtinTypes = Type .Builtins
50+ // 2.2 data types without tparams
51+ val declarationTypes = core.declarations.flatMap(decl => decl match
52+ case Data (id, List (), constructors) => Some (decl)
53+ case _ => None
4454 )
45- .filter(defn => defn.id.name.name == " myshow" )
46-
47- val blockVars : List [Block .BlockVar ] = extShowDefns.map(defn =>
48- Block .BlockVar (defn.id, BlockType .Function (defn.tparams, defn.cparams, defn.vparams map (_.tpe), defn.bparams map (_.tpe), defn.ret), Set .empty))
49- val showDefnsMap : Map [List [ValueType ], Block .BlockVar ] = extShowDefns.zip(blockVars).map((defn, bv) =>
50- (defn.vparams.map(_.tpe), bv)).toMap
51-
52-
53- // TODO: This already assumes there is only one vparam
54- val extGroundTypes = extShowDefns.map(defn => defn.vparams.map(_.tpe)(0 ))
55-
56- // TODO: We also want to include declarations with targs
57- // if those are called with ground types or types we already have generated a show instance for
58- val declGroundTypes = core.declarations.flatMap(decl => decl match {
59- case Data (id, List (), constructors) =>
60- List (ValueType .Data (id, List .empty))
61- case _ => List ()
62- })
63- val groundTypes = extGroundTypes ++ declGroundTypes
64-
65- // TODO: There has to be a better way... right?
66- val infixConcatDef = core.externs.find(ext => ext match {
67- case Extern .Def (id, tparams, cparams, vparams, bparams, ret, annotatedCapture, body) if id.name.name == " infixConcat" =>
68- true
69- case _ => false
70- }).get
71- var infixConcatFn : Block .BlockVar = infixConcatDef match {
72- case Extern .Def (id, tparams, cparams, vparams, bparams, ret, annotatedCapture, body) =>
73- BlockVar (id, BlockType .Function (tparams, cparams, vparams map (_.tpe), bparams map (_.tpe), ret), Set ())
74- case _ => sys error " Does not happen"
55+ // 2.3 data types with targs (later fixed by Mono)
56+ // 2.4 externs (hard, if not impossible)
57+ // 2.5 Types with user defined show definitions (skip for now, unclear if we even want this)
58+
59+ // 3. Synthesize `show` definitions, create (ValueType -> (show) Id) map for context
60+ // 3.1 figure out which backend we are generating for
61+ val backend : String = externFns(" myshow" ).body match {
62+ case StringExternBody (featureFlag : FeatureFlag .NamedFeatureFlag , contents) => featureFlag.id
63+ case _ => sys error " Should never happen"
7564 }
65+ implicit val ctx : ShowContext = ShowContext (collection.mutable.Map .empty, backend, externFns)
7666
77- implicit val ctx : ShowContext = ShowContext (showDefnsMap, groundTypes, collection.mutable.Map .empty, infixConcatFn)
67+ // 3.2 generate show instances for base types in that backend
68+ val baseShowInstances = generateShowInstancesBases(builtinTypes)
69+ // 3.3 generate show instances for declarations
70+ val declShowInstances = generateShowInstancesDecls(declarationTypes)
7871
79- var transformed = transform(core)
72+ // var transformed = transform(core)
73+ // println(util.show(transformed))
74+ // Some(CoreTransformed(source, tree, mod, transformed))
8075
81- println(util.show(transformed))
82-
83- Some (CoreTransformed (source, tree, mod, transformed))
76+ None
8477 }
8578 }
8679
80+ def findRelevantExterns (externs : List [Extern ], names : List [String ]): Map [String , Extern .Def ] =
81+ var retMap = Map [String , Extern .Def ]()
82+ externs.foreach({
83+ case defn@ Extern .Def (id, tparams, cparams, vparams, bparams, ret, annotatedCapture, body) if names.contains(id.name.name) =>
84+ retMap += (id.name.name -> defn)
85+ case _ => ()
86+ })
87+ retMap
88+
8789 def transform (decl : ModuleDecl )(using ctx : ShowContext ): ModuleDecl = decl match {
8890 case ModuleDecl (path, includes, declarations, externs, definitions, exports) =>
8991 val transformedDefns = definitions map transform
90- val additionalDefns = generateShowInstances(declarations)
9192 // Remove myshow extern
9293 // because it only has a dummy implementation which will fail when run
9394 val filteredExterns = decl.externs.flatMap(ext => ext match
9495 case e : Extern .Def => List (e)
9596 case _ => List ()
9697 )
9798 .filter(defn => defn.id.name.name != " myshow" )
98- ModuleDecl (path, includes, declarations, filteredExterns, transformedDefns ++ additionalDefns , exports)
99+ ModuleDecl (path, includes, declarations, filteredExterns, transformedDefns, exports)
99100 }
100101
101- // Q: May externs have show instances on any type
102- // Ignoring these for now
103- // def transform(extern: Extern)(using ShowContext): Extern = extern match {
104- // case Extern.Def(id, tparams, cparams, vparams, bparams, ret, annotatedCapture, body) => ???
105- // case Extern.Include(featureFlag, contents) => Extern.Include(featureFlag, contents)
106- // }
107-
108102 def transform (toplevel : Toplevel )(using ShowContext ): Toplevel = toplevel match {
109103 case Toplevel .Def (id, block) => Toplevel .Def (id, transform(block))
110104 case Toplevel .Val (id, tpe, binding) => ???
@@ -117,15 +111,11 @@ object Show extends Phase[CoreTransformed, CoreTransformed] {
117111 case Unbox (pure) => ???
118112 }
119113
120- def transform (stmt : Stmt )(using ShowContext ): Stmt =
114+ def transform (stmt : Stmt )(using ctx : ShowContext ): Stmt =
121115 stmt match {
122116 case Let (id, annotatedTpe, PureApp (BlockVar (bid, bannotatedTpe, bannotatedCapt), targs, vargs), body) if bid.name.name == " myshow" =>
123117 if (targs.length != 1 ) sys error " expected targs to only have one argument"
124- val targ = targs(0 )
125- if (isGroundType(targ))
126- val bvar = getOrAddShow(targ)
127- return Stmt .Val (id, annotatedTpe, Stmt .App (bvar, List .empty, vargs, List .empty), transform(body))
128- sys error " targ was not ground type in PureApp"
118+ Stmt .Val (id, annotatedTpe, Stmt .App (ctx.getShowBlockVar(targs(0 )), List .empty, vargs, List .empty), transform(body))
129119 case Let (id, annotatedTpe, binding, body) => Let (id, annotatedTpe, transform(binding), transform(body))
130120 case Return (expr) => Return (transform(expr))
131121 // TODO: We might need to do the same thing as in PureApp if we want to allow show(something) instead of something.show
@@ -137,19 +127,100 @@ object Show extends Phase[CoreTransformed, CoreTransformed] {
137127 case Make (data, tag, targs, vargs) => Make (data, tag, targs, vargs)
138128 case PureApp (BlockVar (id, annotatedTpe, annotatedCapt), targs, vargs) if id.name.name == " myshow" =>
139129 if (targs.length != 1 ) sys error " expected targs to only have one argument"
140- val targ = targs(0 )
141- if (isGroundType(targ))
142- val bvar = getOrAddShow(targ)
143- return Expr .PureApp (bvar, List .empty, vargs)
144- sys error " targ was not ground type in PureApp"
130+ Expr .PureApp (ctx.getShowBlockVar(targs(0 )), List .empty, vargs)
145131 case PureApp (b, targs, vargs) => PureApp (b, targs, vargs)
146132 case o => println(o); ???
147133 }
148134
149- def generateShowInstances ( declarations : List [Declaration ])(using ctx : ShowContext ): List [Toplevel ] =
150- ctx.defnsToGenerate.map((vt, id) => generateShowInstance(declarations, vt, id)).toList
135+ def generateShowInstancesBases ( baseTypes : List [ValueType ])(using ShowContext ): List [Toplevel . Def ] =
136+ baseTypes flatMap generateShowInstance
151137
152- def generateShowInstance (declarations : List [Declaration ], vt : ValueType , id : Id )(using ctx : ShowContext ): Toplevel =
138+ // The cases here should match the list effekt.core.Type.Builtins
139+ def generateShowInstance (vt : ValueType )(using ctx : ShowContext ): Option [Toplevel .Def ] =
140+ ctx.backend match {
141+ case " llvm" => generateShowInstanceLLVM(vt)
142+ }
143+
144+ def generateShowInstanceLLVM (vt : ValueType )(using ctx : ShowContext ): Option [Toplevel .Def ] =
145+ val showId = freshShowId
146+ val paramId = Id (" value" )
147+ val vparam = ValueParam (paramId, vt)
148+ val valueVar = Expr .ValueVar (paramId, vt)
149+
150+ def generateBlockLit (stmt : Stmt ) = BlockLit (List .empty, List .empty, List (vparam), List .empty, stmt)
151+ def generateDef (stmt : Stmt ): Toplevel .Def =
152+ ctx.showDefns += (vt -> showId)
153+ val block = generateBlockLit(stmt)
154+ Toplevel .Def (showId, block)
155+
156+ vt match {
157+ case Type .TString =>
158+ // (value: String) { return value }
159+ val stmt = Stmt .Return (valueVar)
160+ Some (generateDef(stmt))
161+ case Type .TUnit =>
162+ /*
163+ (value: Unit) {
164+ "()"
165+ }
166+ */
167+ val stmt = Stmt .Return (Expr .Literal (" ()" , TString ))
168+ Some (generateDef(stmt))
169+ case Type .TInt | Type .TChar =>
170+ /*
171+ (value: Int) {
172+ %z = call %Pos @c_bytearray_show_Int(%Int ${value})
173+ ret %Pos %z
174+ }
175+ */
176+ val blockVar = ctx.externBlockVar(" c_bytearray_show_Int" )
177+ val call = Expr .PureApp (blockVar, List .empty, List (valueVar))
178+ val stmt = Stmt .Return (call)
179+ Some (generateDef(stmt))
180+ case Type .TByte =>
181+ /*
182+ (value: Byte) {
183+ %z = call %Pos @c_bytearray_show_Byte(%Byte ${value})
184+ ret %Pos %z
185+ }
186+ */
187+ val blockVar = ctx.externBlockVar(" c_bytearray_show_Byte" )
188+ val call = Expr .PureApp (blockVar, List .empty, List (valueVar))
189+ val stmt = Stmt .Return (call)
190+ Some (generateDef(stmt))
191+ case Type .TDouble =>
192+ /*
193+ (value: Double) {
194+ %z = call %Pos @c_bytearray_show_Double(%Double ${value})
195+ ret %Pos %z
196+ }
197+ */
198+ val blockVar = ctx.externBlockVar(" c_bytearray_show_Double" )
199+ val call = Expr .PureApp (blockVar, List .empty, List (valueVar))
200+ val stmt = Stmt .Return (call)
201+ Some (generateDef(stmt))
202+ case Type .TBoolean =>
203+ // if (value) "true" else "false"
204+ val stmt = Stmt .If (valueVar, Stmt .Return (Expr .Literal (" true" , TString )), Stmt .Return (Expr .Literal (" false" , TString )))
205+ Some (generateDef(stmt))
206+
207+ case _ => println(s " Missing case for vt: ${vt}" ); None
208+
209+ }
210+
211+ def generateShowInstancesDecls (declarations : List [Declaration ])(using ShowContext ): List [Toplevel .Def ] =
212+ declarations flatMap generateShowInstance
213+
214+ def generateShowInstance (decl : Declaration )(using ctx : ShowContext ): Option [Toplevel .Def ] = decl match {
215+ case dataDecl : Declaration .Data =>
216+ val freshId = freshShowId
217+ val toplevel = generateShowInstance(dataDecl, freshId)
218+ ctx.showDefns += (ValueType .Data (dataDecl.id, List .empty) -> freshId)
219+ Some (toplevel)
220+ case _ => None
221+ }
222+
223+ def generateShowInstance (declarations : List [Declaration ], vt : ValueType , id : Id )(using ctx : ShowContext ): Toplevel .Def =
153224 vt match {
154225 case ValueType .Data (name, targs) =>
155226 declarations.find(decl => decl.id == name).get match {
@@ -160,7 +231,7 @@ object Show extends Phase[CoreTransformed, CoreTransformed] {
160231 }
161232 ???
162233
163- def generateShowInstance (decl : Declaration .Data , id : Id )(using ShowContext ): Toplevel =
234+ def generateShowInstance (decl : Declaration .Data , id : Id )(using ShowContext ): Toplevel . Def =
164235 val defnId = id
165236 val valueId = Id (" value" )
166237 val valueTpe = ValueType .Data (decl.id, List .empty)
@@ -187,8 +258,7 @@ object Show extends Phase[CoreTransformed, CoreTransformed] {
187258 val defns = constructorStmts.zip(constructorIdVparams)
188259 val stmt = nestDefns(defns, returnVal)
189260
190- val finalDefn = Toplevel .Def (defnId, Block .BlockLit (List .empty, List .empty, List (vparam), List .empty, stmt))
191- finalDefn
261+ Toplevel .Def (defnId, Block .BlockLit (List .empty, List .empty, List (vparam), List .empty, stmt))
192262
193263 def nestDefns (defns : List [(Stmt , (Id , List [ValueParam ]))], default : Stmt ): Stmt = defns match
194264 case (head, (id, vparams)) :: rest =>
@@ -207,37 +277,29 @@ object Show extends Phase[CoreTransformed, CoreTransformed] {
207277 def constructorStmt (constr : Constructor )(using ctx : ShowContext ): Stmt = constr match
208278 case Constructor (id, tparams, List ()) => Return (Literal (id.name.name, TString ))
209279 case Constructor (id, tparams, fields) =>
210- val infixConcatBlockVar : Block .BlockVar = ctx.infixConcatFn
280+ val infixConcatBlockVar : Block .BlockVar = ctx.externBlockVar( " infixConcat " )
211281 val pureFields = fields map fieldPure
212- val concatenated = PureApp (ctx.infixConcatFn , List .empty, List (Literal (id.name.name ++ " (" , TString ), concatPure(pureFields)))
282+ val concatenated = PureApp (infixConcatBlockVar , List .empty, List (Literal (id.name.name ++ " (" , TString ), concatPure(pureFields)))
213283 Return (concatenated)
214284
215285 // Convert a list of pure statements to comma-separated concatenated version
216286 // Literal("Just("), PureApp(show, x), Literal(", "), PureApp(show, y), Literal(")")
217287 // =>
218288 // PureApp(concat, List(Literal("Just("), PureApp(concat, List(PureApp(show, x), PureApp(concat, List(Literal(", "), ...))))
219289 def concatPure (pures : List [Expr ])(using ctx : ShowContext ): Expr = pures match
220- case head :: next :: rest => PureApp (ctx.infixConcatFn , List .empty, List (head, PureApp (ctx.infixConcatFn , List .empty, List (Literal (" , " , TString ), concatPure(next :: rest)))))
221- case head :: Nil => PureApp (ctx.infixConcatFn , List .empty, List (head, Literal (" )" , TString )))
290+ case head :: next :: rest => PureApp (ctx.externBlockVar( " infixConcat " ) , List .empty, List (head, PureApp (ctx.externBlockVar( " infixConcat " ) , List .empty, List (Literal (" , " , TString ), concatPure(next :: rest)))))
291+ case head :: Nil => PureApp (ctx.externBlockVar( " infixConcat " ) , List .empty, List (head, Literal (" )" , TString )))
222292 case Nil => Literal (" )" , TString )
223293
224294 def fieldValueVar (field : Field ): Expr = field match
225295 case Field (id, tpe) => ValueVar (id, tpe)
226296
227297 def fieldPure (field : Field )(using ctx : ShowContext ): Expr .PureApp = field match
228- case Field (id, tpe) => PureApp (ctx.showDefnsMap(List (tpe)), List .empty, List (ValueVar (id, tpe)))
229-
230- def getOrAddShow (vt : ValueType )(using ctx : ShowContext ): BlockVar = vt match
231- case ValueType .Boxed (tpe, capt) => ???
232- case ValueType .Data (name, targs) =>
233- val id = ctx.defnsToGenerate.getOrElse(vt, {
234- val freshShowId = Id (" myshow" )
235- ctx.defnsToGenerate += (vt -> freshShowId)
236- freshShowId
237- })
238- val freshBlockType = BlockType .Function (List .empty, List .empty, List (vt), List .empty, TString )
239- BlockVar (id, freshBlockType, Set .empty)
240- case ValueType .Var (name) => ???
241-
242- def isGroundType (vt : ValueType )(using ctx : ShowContext ): Boolean = ctx.groundTypes.contains(vt)
298+ case Field (id, tpe) => PureApp (ctx.getShowBlockVar(tpe), List .empty, List (ValueVar (id, tpe)))
299+
300+ var freshShowCounter = 0
301+ def freshShowId : Id =
302+ val freshId = Id (" show" ++ freshShowCounter.toString())
303+ freshShowCounter += 1
304+ freshId
243305}
0 commit comments