Skip to content

Commit a8eb37c

Browse files
committed
Progress...
1 parent db8df3d commit a8eb37c

8 files changed

Lines changed: 253 additions & 60 deletions

File tree

cogen/src/main/scala/org/combinators/cogen/TypeRep.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ object TypeRep {
3939
type HostType = scala.Boolean
4040
}
4141

42+
/** Represents the Scala type `Char`. */
43+
case object Char extends TypeRep {
44+
type HostType = scala.Char
45+
}
46+
4247
/** Represents the type `Seq[A]` */
4348
case class Sequence[T](elemTpe: TypeRep.OfHostType[T]) extends TypeRep {
4449
type HostType = Seq[T]

language/java/src/main/scala/org/combinators/ep/language/java/paradigm/AnyParadigm.scala

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ import org.combinators.ep.language.java.{CodeGenerator, CompilationUnitCtxt, Con
1818
import org.combinators.templating.persistable.{BundledResource, JavaPersistable}
1919

2020
import scala.util.Try
21-
import scala.jdk.CollectionConverters.*
22-
21+
import scala.jdk.CollectionConverters._
2322

2423
trait AnyParadigm extends AP {
2524
lazy val config: Config
@@ -40,8 +39,8 @@ trait AnyParadigm extends AP {
4039
context: ProjectCtxt,
4140
command: Debug
4241
): (ProjectCtxt, Unit) = {
43-
val units = context.units.toSeq.mkString(", ")
44-
System.err.println (command.tag + ": " + units)
42+
43+
context.units.foreach (u => System.err.println (command.tag + ": " + u))
4544
(context,())
4645
}
4746
}
@@ -299,7 +298,7 @@ trait AnyParadigm extends AP {
299298
val stripped = AnyParadigm.stripGenerics(command.forElem)
300299
Try { (context, context.resolver.importResolution(stripped)) } getOrElse {
301300
if (stripped.isClassOrInterfaceType) {
302-
val importName: JName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType())
301+
val importName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType())
303302
val newImport =
304303
new ImportDeclaration(
305304
importName,
@@ -332,7 +331,7 @@ trait AnyParadigm extends AP {
332331
} else {
333332
val scope =
334333
command.functional match {
335-
case n: NodeWithScope[_] => n.getScope
334+
case n: NodeWithScope[Expression] => n.getScope
336335
case _ => null
337336
}
338337
new MethodCallExpr(scope, command.functional.asInstanceOf[NodeWithSimpleName[Node]].getNameAsString, new NodeList[Expression](command.arguments*))
@@ -388,7 +387,7 @@ trait AnyParadigm extends AP {
388387
val stripped = AnyParadigm.stripGenerics(command.forElem)
389388
Try { (context, context.resolver.importResolution(stripped)) } getOrElse {
390389
if (stripped.isClassOrInterfaceType) {
391-
val importName: JName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType())
390+
val importName = ObjectOriented.typeToName(stripped.asClassOrInterfaceType())
392391
val newImport =
393392
new ImportDeclaration(
394393
importName,
@@ -529,11 +528,11 @@ trait AnyParadigm extends AP {
529528
""".stripMargin
530529
val cleanedUnits =
531530
ImportCleanup.cleaned(
532-
FreshNameCleanup.cleaned(finalContext.resolver.generatedVariables, finalContext.units*)*
531+
FreshNameCleanup.cleaned(finalContext.resolver.generatedVariables, finalContext.units: _*) : _*
533532
)
534533
val cleanedTestUnits =
535534
ImportCleanup.cleaned(
536-
FreshNameCleanup.cleaned(finalContext.resolver.generatedVariables, finalContext.testUnits*)*
535+
FreshNameCleanup.cleaned(finalContext.resolver.generatedVariables, finalContext.testUnits: _*): _*
537536
)
538537
val javaFiles = cleanedUnits.map { unit =>
539538
FileWithPath(

language/java/src/main/scala/org/combinators/ep/language/java/paradigm/Imperative.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ trait Imperative[Ctxt, AP <: AnyParadigm] extends Imp[Ctxt] {
8585
(manip.copyWithBlock(afterElseCtxt, manip.getBlock(context)), iteStmt.clone())
8686
}
8787
}
88+
89+
implicit val canTernary: Understands[Ctxt, Ternary[Expression, Expression]] =
90+
new Understands[Ctxt, Ternary[Expression, Expression]] {
91+
def perform(
92+
context: Ctxt,
93+
command: Ternary[Expression, Expression]
94+
): (Ctxt, Expression) = {
95+
val conditionalExpr: ConditionalExpr = new ConditionalExpr ()
96+
conditionalExpr.setCondition(command.condition)
97+
conditionalExpr.setThenExpr(command.trueExpression)
98+
conditionalExpr.setElseExpr(command.falseExpression)
99+
100+
(manip .copyWithBlock(context, manip.getBlock(context)), conditionalExpr.clone())
101+
}
102+
}
103+
88104
implicit val canWhile: Understands[Ctxt, While[Ctxt, Expression, Statement]] =
89105
new Understands[Ctxt, While[Ctxt, Expression, Statement]] {
90106
def perform(context: Ctxt, command: While[Ctxt, Expression, Statement]): (Ctxt, Statement) = {

language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ObjectOriented.scala

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -599,16 +599,40 @@ trait ObjectOriented[AP <: AnyParadigm] extends OO {
599599
): (MethodBodyContext, Expression) = {
600600
val (tpe, args) = context.resolver.instantiationOverride(command.tpe, command.constructorArguments)
601601
/** Expand with instantiated body (if it exists). */
602-
val result = new ObjectCreationExpr()
603-
result.setType(tpe.asClassOrInterfaceType().clone())
604-
result.setArguments(new NodeList(args*))
605-
if (command.body.isDefined) {
606-
val ci = new ClassOrInterfaceDeclaration()
607-
val (newCtxt, classDef) = Command.runGenerator(command.body.get, ClassCtxt(context.resolver, ci, context.extraImports))
608-
result.setAnonymousClassBody(newCtxt.cls.getMembers)
609-
(context.copy(resolver = newCtxt.resolver, extraImports = newCtxt.extraImports), result)
602+
if (tpe.isArrayType) {
603+
val result = new ArrayCreationExpr()
604+
result.setElementType(tpe.getElementType)
605+
val levels = new NodeList[ArrayCreationLevel] ()
606+
levels.add(new ArrayCreationLevel().setDimension(args.head))
607+
if (args.tail.nonEmpty) {
608+
levels.add(new ArrayCreationLevel().setDimension(args.tail.head))
609+
if (args.tail.tail.nonEmpty) {
610+
levels.add(new ArrayCreationLevel().setDimension(args.tail.tail.head))
611+
if (args.tail.tail.tail.nonEmpty) {
612+
levels.add(new ArrayCreationLevel().setDimension(args.tail.tail.tail.head))
613+
if (args.tail.tail.tail.nonEmpty) {
614+
levels.add(new ArrayCreationLevel().setDimension(args.tail.tail.tail.tail.head))
615+
if (args.tail.tail.tail.tail.nonEmpty) {
616+
println("Too many array levels [ObjectOriented: instantiateObject in method")
617+
}
618+
}
619+
}
620+
}
621+
}
622+
result.setLevels(levels)
623+
(context, result.removeInitializer()) // no initializers when declaring bounds
610624
} else {
611-
(context, result)
625+
val result = new ObjectCreationExpr()
626+
result.setType(tpe.asClassOrInterfaceType().clone())
627+
result.setArguments(new NodeList(args: _*))
628+
if (command.body.isDefined) {
629+
val ci = new ClassOrInterfaceDeclaration()
630+
val (newCtxt, classDef) = Command.runGenerator(command.body.get, ClassCtxt(context.resolver, ci, context.extraImports))
631+
result.setAnonymousClassBody(newCtxt.cls.getMembers)
632+
(context.copy(resolver = newCtxt.resolver, extraImports = newCtxt.extraImports), result)
633+
} else {
634+
(context, result)
635+
}
612636
}
613637
}
614638
}

language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Arrays.scala

Lines changed: 110 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ package org.combinators.ep.language.java.paradigm.ffi /*DI:LD:AI*/
33
import com.github.javaparser.ast.`type`.ArrayType
44
import com.github.javaparser.ast.expr.{ArrayAccessExpr, ArrayCreationExpr, ArrayInitializerExpr, AssignExpr, FieldAccessExpr, IntegerLiteralExpr, MethodCallExpr, NameExpr, SimpleName}
55
import com.github.javaparser.ast.{ArrayCreationLevel, NodeList}
6-
import org.combinators.cogen.InstanceRep
7-
import org.combinators.cogen.TypeRep
6+
import org.combinators.cogen.{Command, InstanceRep, TypeRep, Understands}
87
import org.combinators.cogen.paradigm.{Apply, ffi}
98
import org.combinators.cogen.Command.Generator
10-
import org.combinators.cogen.paradigm.AnyParadigm.syntax._
11-
import org.combinators.cogen.paradigm.ffi.{CreateArray, Get, Length, Arrays as Arrs}
12-
import org.combinators.cogen.Understands
9+
import org.combinators.cogen.paradigm.AnyParadigm.syntax.*
10+
import org.combinators.cogen.paradigm.ffi.{CreateArray, Get, Length, Set, Arrays as Arrs}
1311
import org.combinators.ep.language.java.CodeGenerator.Enable
14-
import org.combinators.ep.language.java.Syntax.default._
12+
import org.combinators.ep.language.java.Syntax.default.*
1513
import org.combinators.ep.language.java.paradigm.AnyParadigm
1614
import org.combinators.ep.language.java.{ContextSpecificResolver, ProjectCtxt}
1715

@@ -23,12 +21,32 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] {
2321
def perform(
2422
context: Ctxt,
2523
command: Apply[CreateArray[Type], Expression, Expression]
26-
): (Ctxt, Expression) =
27-
(context,
28-
new ArrayCreationExpr(command.functional.elementType,
29-
new NodeList(new ArrayCreationLevel(1)),
30-
new ArrayInitializerExpr(new NodeList(command.arguments*)))
31-
)
24+
): (Ctxt, Expression) = {
25+
26+
if (command.functional.dimensions.length == 1) {
27+
(context,
28+
new ArrayCreationExpr(command.functional.elementType,
29+
new NodeList(new ArrayCreationLevel()),
30+
new ArrayInitializerExpr(new NodeList(command.arguments: _ *)))
31+
)
32+
} else {
33+
val levels = command.functional.dimensions.map(level => new ArrayCreationLevel()) // inserting actual value causes problems since cannot have int[len1][len2] with initial values.
34+
val dims = command.functional.dimensions
35+
val innerFold = dims.reverse.tail.foldLeft[Seq[ArrayInitializerExpr]](
36+
command.arguments.grouped(dims.last).toSeq.map(subSeq => new ArrayInitializerExpr(new NodeList(subSeq: _*)))
37+
)
38+
{ case (inits, dim) => inits.grouped(dim).toSeq.map(subSeq => new ArrayInitializerExpr(new NodeList(subSeq: _*))) }
39+
40+
// When creating array with initial values, cannot pass in lengths. Cannot do the following for example
41+
// new int[2][3] { { 4, 5, 1 }, { 1, 2, 3 } }
42+
43+
(context,
44+
new ArrayCreationExpr(command.functional.elementType,
45+
new NodeList(levels: _*),
46+
innerFold.head) // new ArrayInitializerExpr(new NodeList(command.arguments: _ *)))
47+
)
48+
}
49+
}
3250
}
3351

3452
val arrayCapabilities: ArrayCapabilities =
@@ -42,17 +60,22 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] {
4260
context: Ctxt,
4361
command: Apply[Get, Expression, Expression]
4462
): (Ctxt, Expression) = {
45-
(context, new ArrayAccessExpr(command.arguments(0), command.arguments(1)))
63+
64+
val indices = command.arguments.tail.foldLeft(command.arguments.head) { case (acc, level) => new ArrayAccessExpr(acc, level) }
65+
66+
(context, indices)
4667
}
4768
}
4869

49-
implicit val canSet: Understands[Ctxt, Apply[ffi.Set, Expression, Expression]] =
50-
new Understands[Ctxt, Apply[ffi.Set, Expression, Expression]] {
70+
implicit val canSet: Understands[Ctxt, Apply[Set, Expression, Expression]] =
71+
new Understands[Ctxt, Apply[Set, Expression, Expression]] {
5172
override def perform(
5273
context: Ctxt,
53-
command: Apply[ffi.Set, Expression, Expression]
74+
command: Apply[Set, Expression, Expression]
5475
): (Ctxt, Expression) = {
55-
(context, new AssignExpr(new ArrayAccessExpr(command.arguments(0), command.arguments(1)), command.arguments(2), AssignExpr.Operator.ASSIGN))
76+
val indices = command.arguments.init.tail.foldLeft(command.arguments.head) { case (acc, level) => new ArrayAccessExpr(acc, level) }
77+
78+
(context, new AssignExpr(indices, command.arguments.last, AssignExpr.Operator.ASSIGN))
5679
}
5780
}
5881

@@ -62,7 +85,9 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] {
6285
context: Ctxt,
6386
command: Apply[Length, Expression, Expression]
6487
): (Ctxt, Expression) = {
65-
(context, new FieldAccessExpr(command.arguments(0), "length"))
88+
val indices = command.arguments.tail.foldLeft(command.arguments.head) { case (acc, level) => new ArrayAccessExpr(acc, level) }
89+
90+
(context, new FieldAccessExpr(indices, "length"))
6691
}
6792
}
6893
}
@@ -80,9 +105,10 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] {
80105
toResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type],
81106
projectResolution: ContextSpecificResolver => TypeRep => Generator[Ctxt, Type]
82107
): ContextSpecificResolver => TypeRep => Generator[Ctxt, Type] = k => {
83-
case TypeRep.Array(elemRep) =>
108+
case TypeRep.Array(elemTypeRep) =>
109+
84110
for {
85-
elemType <- projectResolution(k)(elemRep)
111+
elemType <- projectResolution(k)(elemTypeRep)
86112
} yield new ArrayType(elemType)
87113
case other => toResolution(k)(other)
88114
}
@@ -94,14 +120,72 @@ class Arrays[Ctxt, AP <: AnyParadigm](val base:AP) extends Arrs[Ctxt] {
94120
canCreateArray: Understands[Ctxt, Apply[CreateArray[Type], Expression, Expression]]
95121
): ContextSpecificResolver => InstanceRep => Generator[Ctxt, Expression] =
96122
k => rep => rep.tpe match {
97-
case TypeRep.Array(elemTypeRep) =>
98-
for {
99-
elems <- forEach(rep.inst.asInstanceOf[Seq[elemTypeRep.HostType]]) { elem =>
100-
projectReification(k)(InstanceRep(elemTypeRep)(elem))
123+
case TypeRep.Array(elemTypeRep) => {
124+
125+
126+
// helper function to get flattened elements
127+
def elements(elemTypeRep:TypeRep)(elem:elemTypeRep.HostType) : Generator[Ctxt, Seq[Expression]] = {
128+
elemTypeRep match {
129+
case TypeRep.Array(innerElemTypeRep) => {
130+
val seq_gen = elem.asInstanceOf[Array[innerElemTypeRep.HostType]].map(innerElem => elements(innerElemTypeRep)(innerElem))
131+
for {
132+
flattened <- seq_gen.foldLeft(Command.lift[Ctxt,Seq[Expression]](Seq.empty[Expression])){ case (acc, next_gen) =>
133+
for {
134+
acc_result <- acc
135+
next_result <- next_gen
136+
} yield acc_result ++ next_result
137+
}
138+
} yield flattened
139+
}
140+
141+
// recursively translates innermost elements
142+
case _ => for {
143+
elems <- forEach(elem.asInstanceOf[Seq[elemTypeRep.HostType]]) { el =>
144+
projectReification(k)(InstanceRep(elemTypeRep)(el))
145+
}
146+
} yield elems
101147
}
102-
elemType <- projectResolution(k)(elemTypeRep)
103-
res <- Apply[CreateArray[Type], Expression, Expression](CreateArray(elemType), elems).interpret(canCreateArray)
148+
}
149+
150+
// helper function to get type of innermost element -- assume homogenous array
151+
def elementType(elemTypeRep:TypeRep)(elem:elemTypeRep.HostType) : Generator[Ctxt, Type] = {
152+
elemTypeRep match {
153+
case TypeRep.Array(innerElemTypeRep) =>
154+
elementType(innerElemTypeRep)(elem.asInstanceOf[Array[innerElemTypeRep.HostType]].head)
155+
156+
// recursively find type of innermost element
157+
case _ => for {
158+
elemType <- projectResolution(k)(elemTypeRep)
159+
} yield elemType
160+
}
161+
}
162+
163+
// helper function to get flattened elements
164+
def dimensions(elemTypeRep:TypeRep)(elem:elemTypeRep.HostType) : Seq[Int] = {
165+
elemTypeRep match {
166+
case TypeRep.Array(innerElemTypeRep) => {
167+
val outer = elem.asInstanceOf[Seq[elemTypeRep.HostType]].length
168+
169+
// inner arrays must be uniform length
170+
val inner = dimensions(innerElemTypeRep)(elem.asInstanceOf[Array[innerElemTypeRep.HostType]].head)
171+
outer +: inner
172+
}
173+
174+
// recursively translates innermost elements
175+
case _ => Seq(elem.asInstanceOf[Seq[elemTypeRep.HostType]].length)
176+
177+
}
178+
}
179+
180+
181+
for {
182+
elems <- elements(rep.tpe)(rep.inst)
183+
dims = dimensions(rep.tpe)(rep.inst)
184+
elemType <- elementType(rep.tpe)(rep.inst)
185+
res <- Apply[CreateArray[Type], Expression, Expression](CreateArray(elemType, dims), elems).interpret(canCreateArray)
104186
} yield res
187+
188+
}
105189
case _ => reify(k)(rep)
106190
}
107191

language/java/src/main/scala/org/combinators/ep/language/java/paradigm/ffi/Lists.scala

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import com.github.javaparser.ast.{ImportDeclaration, NodeList}
1212
import org.combinators.cogen.InstanceRep
1313
import org.combinators.cogen.TypeRep
1414
import org.combinators.cogen.paradigm.ffi.{Append, Cons, Create, Head, Tail, Lists as Lsts}
15-
import org.combinators.cogen.paradigm.{AddImport, Apply}
15+
import org.combinators.cogen.paradigm.{AddImport, Apply, GetMember}
1616

1717
trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] {
1818
case object ListsEnabled
@@ -59,7 +59,7 @@ trait Lists[Ctxt, AP <: AnyParadigm] extends Lsts[Ctxt] {
5959
} else {
6060
for {
6161
_ <- AddImport[Import](new ImportDeclaration("java.util.Arrays", false, false)).interpret(canAddImport)
62-
} yield new MethodCallExpr(ObjectOriented.nameToExpression(ObjectOriented.fromComponents("java", "util", "Arrays")), "asList", new NodeList[Expression](command.arguments*))
62+
} yield new MethodCallExpr(ObjectOriented.nameToExpression(ObjectOriented.fromComponents("java", "util", "Arrays")), "asList", new NodeList[Expression](command.arguments:_*))
6363
}
6464
Command.runGenerator[Ctxt, Expression](gen, context)
6565
}
@@ -251,23 +251,28 @@ object Lists {
251251
type Aux[Ctxt, AP <: AnyParadigm, Gen <: Generics[AP]] = Lists[Ctxt, AP] {
252252
val generics: Gen
253253
}
254-
def apply[Ctxt, AP <: AnyParadigm, Gen[A <: AP] <: Generics[A]](
254+
def apply[Ctxt, AP <: AnyParadigm, Gen <: Generics[AP]](
255255
base: AP,
256+
getMember: Understands[Ctxt, GetMember[Expression, Name]],
257+
applyMethod: Understands[Ctxt, Apply[Expression, Expression, Expression]],
256258
applyType: Understands[Ctxt, Apply[Type, Type, Type]],
257259
addImport: Understands[Ctxt, AddImport[Import]])(
258-
generics: Gen[base.type]
260+
generics: Generics[base.type]
259261
): Aux[Ctxt, base.type, generics.type] = {
260262
val b: base.type = base
263+
val gm = getMember
264+
val appMeth = applyMethod
261265
val appTy = applyType
262266
val addImp = addImport
263267
val gen: generics.type = generics
264268

265-
case class Lsts(override val base: b.type,
266-
override val applyType: Understands[Ctxt, Apply[Type, Type, Type]],
267-
override val addImport: Understands[Ctxt, AddImport[Import]],
268-
override val generics: gen.type
269-
) extends Lists[Ctxt, b.type]
270-
271-
Lsts(b, appTy, addImp, gen)
269+
new Lists[Ctxt, b.type] {
270+
lazy val base: b.type = b
271+
lazy val getMember = gm
272+
lazy val applyMethod = appMeth
273+
lazy val applyType = appTy
274+
lazy val addImport = addImp
275+
lazy val generics: gen.type = gen
276+
}
272277
}
273278
}

0 commit comments

Comments
 (0)