Skip to content

Commit

Permalink
refactored and corrected code generation code
Browse files Browse the repository at this point in the history
  • Loading branch information
ikuraj committed Sep 13, 2012
1 parent 84aff9f commit 53c3396
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 60 deletions.
Binary file not shown.
Expand Up @@ -24,6 +24,7 @@ class ClassicStyleCodeGenerator extends CodeGenerator {
import FormatHelpers._
import Document._
import TransformContext._
import DocumentHelper._

/**
* main method (recursive) for transforming a intermediate (sub)tree
Expand Down Expand Up @@ -113,13 +114,20 @@ class ClassicStyleCodeGenerator extends CodeGenerator {
case Scala.Method(_, params, _) => params
case _ => throw new RuntimeException("Declared method but scala type is not")
}

// set if we need parentheses
val parenthesesRequired = decl.hasParentheses

// go through all combinations of parameters documents
return (List[Document]() /: getParamsCombinations(params.drop(2), paramsInfo, true)) {
(list, paramsDoc) => list :+
// TODO when to generate dot and when not??
//group(decl.getObjectName :: "." :: doParen(appIdentifier, paramsDoc))
group(doParenRecApp(decl.getObjectName, appIdentifier, paramsDoc))
group(
parenthesesRequired ?
(decl.getObjectName :: "." :: appIdentifier :: paren(paramsDoc)) |
decl.getObjectName :: "." :: appIdentifier
)
}
}

Expand Down Expand Up @@ -170,6 +178,9 @@ class ClassicStyleCodeGenerator extends CodeGenerator {
case Scala.Method(_, params, _) => params
case _ => throw new RuntimeException("Declared method but scala type is not")
}

// set if we need parentheses
val parenthesesRequired = decl.hasParentheses

// if the method needs this keyword
val needsThis = decl.hasThis
Expand All @@ -195,7 +206,11 @@ class ClassicStyleCodeGenerator extends CodeGenerator {
// and add them to the list
(listDocsTransformedParameters, paramsDoc) =>
listDocsTransformedParameters :+
group(doParenRecApp(receiverDoc, appIdentifier, paramsDoc))
group(
parenthesesRequired ?
(receiverDoc ?:: "." :: appIdentifier :: paren(paramsDoc)) |
receiverDoc ?:: "." :: appIdentifier
)
}
}
}
Expand Down Expand Up @@ -224,13 +239,13 @@ class ClassicStyleCodeGenerator extends CodeGenerator {
{
listOfAbstractions ++
// for all transformations of bodies
(List[Document]() /: transform(body)) {
(List[Document]() /: transform(body, Expr)) {
(listOfBodies, transformedBody) =>
listOfBodies :+ (
// transform argument variables
(
parenthesesRequired ?
paren(seqToDoc(vars, ",", { v: Variable => transform(v, Arg).head })) |
paren(seqToDoc(vars, ", ", { v: Variable => transform(v, Arg).head })) |
seqToDoc(vars, ",", { v: Variable => transform(v, Arg).head })
)
:/: "=>" :/:
Expand All @@ -248,21 +263,8 @@ class ClassicStyleCodeGenerator extends CodeGenerator {
abstractionResults
} // tree match
}

// helper method for application, output parentheses always
def doParenApp(appId: Document, params: Document) = appId :: paren(params)

// helper method
def doParenRecApp(receiverDoc: Document, appId: Document, params: Document) = {
// to match the empty document
val emptyMatch = empty

receiverDoc match {
case `emptyMatch` =>
appId :: paren(params)
case _:Document =>
receiverDoc :: "." :: appId :: paren(params)
}
}

}
Expand Up @@ -8,6 +8,7 @@ import ch.epfl.insynth.reconstruction.combinator.{ NormalDeclaration, AbsDeclara

import scala.text.Document
import scala.text.Document.empty
import scala.text.DocNil

/** companion object for more convenient application */
object CleanCodeGenerator {
Expand All @@ -24,6 +25,7 @@ class CleanCodeGenerator extends CodeGenerator {
import FormatHelpers._
import Document._
import TransformContext._
import DocumentHelper._

/**
* main method (recursive) for transforming a intermediate (sub)tree
Expand All @@ -34,32 +36,29 @@ class CleanCodeGenerator extends CodeGenerator {
override def transform(tree: Node, ctx: TransformContext = Expr): List[Document] = {

// a local variable to set if parentheses are needed
var parenthesesRequired = true
var parenthesesRequired = true

// do parentheses for parameters if needed
def doParenApp(appId: Document, params: Document) = {
if (parenthesesRequired)
(appId :: paren(params))
else
(appId :/: params)
}
def doParenApp(appId: Document, params: Document) =
params match {
case _ if parenthesesRequired => (appId :: paren(params))
case DocNil if !parenthesesRequired => appId
case _ => (appId :/: params)
}

def doParenRecApp(receiverDoc: Document, appId: Document, params: Document) = {
// to match the empty document
val emptyMatch = empty
receiverDoc match {
//case scala.text.DocNil =>
case `emptyMatch` =>
// if (parenthesesRequired)
// if receiver is empty then we always need this form
appId :: paren(params)
// else
// appId :/: params
case _:Document =>
if (parenthesesRequired)
(receiverDoc :: "." :: appId :: paren(params))
else
(receiverDoc :/: appId :/: params)
case DocNil =>
// if receiver is empty then we always need this form
doParenApp(appId, params)
case _: Document =>
if (parenthesesRequired)
(receiverDoc :: "." :: appId :: paren(params))
else
(receiverDoc :/: appId :/?: params)
}
}

def doParen(d: Document) = if (parenthesesRequired) paren(d) else d

tree match {
Expand Down Expand Up @@ -131,20 +130,28 @@ class CleanCodeGenerator extends CodeGenerator {
group("new" :/: doParenApp(appIdentifier, paramsDoc))
}
}

// method is on some object
if (decl.belongsToObject) {
assert(params(1).size == 1)
assert(params(1).head == NullLeaf)

// get info about parameters
val paramsInfo = decl.scalaType match {
case Scala.Method(_, params, _) => params
case _ => throw new RuntimeException("Declared method but scala type is not")
}

// set if we need parentheses
parenthesesRequired =
// if we have more than one parameter or this term is a single parameter
// to outer application
params.drop(2).size > 1 || ctx == SinglePar
{
// if we have more than one parameter or this term is a single parameter
// to outer application
(params.drop(2).size > 1 || ctx == SinglePar) &&
// and hasParentheses must be false
decl.hasParentheses
}

// go through all combinations of parameters documents
return (List[Document]() /: getParamsCombinations(params.drop(2), paramsInfo, parenthesesRequired)) {
(list, paramsDoc) =>
Expand All @@ -169,37 +176,47 @@ class CleanCodeGenerator extends CodeGenerator {
receiver match {
case Identifier(_, NormalDeclaration(receiverDecl)) if receiverDecl.isThis =>
List(empty)
case _ => transform(receiver, App) map { (_: Document) :: "." }
case _ => transform(receiver, App)
}
else transform(receiver, App) map { (_: Document) :: "." }
else transform(receiver, App)
}
// go through all the receiver objects and add to the list
(listDocsReceivers /: documentsForThis) {
(listDocsTransformedReceiver, receiverDoc) =>
{
listDocsTransformedReceiver :+ group(receiverDoc :: appIdentifier)
listDocsTransformedReceiver :+ group(receiverDoc :?/: appIdentifier)
}
}
}
}
} else if (!decl.isMethod) {
}

else if (!decl.isMethod) {
assert(!decl.isConstructor)
// just a function
//parenthesesRequired = params.tail.size >= 1 || ctx == SinglePar
parenthesesRequired = true
firstTermFunctionTransform
} else // if (decl.isMethod)
}

else // if (decl.isMethod)
{
// TODO solve parentheses here (with currying)
// get info about parameters
val paramsInfo = decl.scalaType match {
case Scala.Method(_, params, _) => params
case _ => throw new RuntimeException("Declared method but scala type is not")
}

// currying will handle parentheses if needed
parenthesesRequired = params.drop(2).size != 1 || ctx == SinglePar || ctx == App
parenthesesRequired =
(params.drop(2).size > 1 || ctx == SinglePar || ctx == App) &&
// and hasParentheses must be false
decl.hasParentheses

// if the method needs this keyword
val needsThis = decl.hasThis

(List[Document]() /: params(1)) {
(listDocsReceivers, receiver) =>
{
Expand All @@ -208,11 +225,13 @@ class CleanCodeGenerator extends CodeGenerator {
if (!needsThis)
receiver match {
case Identifier(_, NormalDeclaration(receiverDecl)) if receiverDecl.isThis =>
parenthesesRequired = params.drop(2).size >= 1
List(empty)
case _ => transform(receiver, App) // map { (_:Document) :: "." }
}
else transform(receiver, App) // map { (_:Document) :: "." }
}

// go through all the receiver objects and add to the list
(listDocsReceivers /: documentsForThis) {
(listDocsTransformedReceiver, receiverDoc) =>
Expand Down Expand Up @@ -246,11 +265,11 @@ class CleanCodeGenerator extends CodeGenerator {
{
listOfAbstractions ++
// for all transformations of bodies
(List[Document]() /: transform(body)) {
(List[Document]() /: transform(body, Expr)) {
(listOfBodies, transformedBody) =>
listOfBodies :+ (
// transform argument variables
doParen(seqToDoc(vars, ",", { v: Variable => transform(v, Arg).head }))
doParen(seqToDoc(vars, ", ", { v: Variable => transform(v, Arg).head }))
:/: "=>" :/:
// transform the body
transformedBody)
Expand Down
Expand Up @@ -18,6 +18,8 @@ abstract class CodeGenerator extends (Node => List[CodeGenOutput]) {
// import methods for easier document manipulation
import FormatHelpers._
import Document._
// convenience ?: operator
import Bool._

/**
* takes the tree and calls the recursive function and maps documents to Output elements
Expand Down Expand Up @@ -89,7 +91,7 @@ abstract class CodeGenerator extends (Node => List[CodeGenOutput]) {
def getParamsCombinationsRec(listOfPicked: List[Document], params: List[Set[Node]]):List[Document] = {
params match {
case List() =>
List(foldDoc(listOfPicked.tail, ","))
List(foldDoc(listOfPicked.tail, ", "))
case set :: list =>
(List[Document]() /: transform(set.toList, ctx)) {
(listSoFar, el) => {
Expand All @@ -104,12 +106,16 @@ abstract class CodeGenerator extends (Node => List[CodeGenOutput]) {

/**
* generates all documents which represent all combinations of parameters according
* to the given parameter list and paramsInfo (for curring)
* to the given parameter list and paramsInfo (for currying)
* @param params parameter list for transform
* @param paramsInfo parameter list information
* @return list of documents with all parameter combinations
*/
protected def getParamsCombinations(params: List[Set[Node]], paramsInfo: List[List[Scala.ScalaType]], parenthesesRequired: Boolean):List[Document] = {

// convenient solution for currying
val backToBackParentheses: Document = ")("

def getParamsCombinationsRec(
params: List[Set[Node]],
paramsInfo: List[List[Scala.ScalaType]]):List[Document] =
Expand All @@ -127,9 +133,7 @@ abstract class CodeGenerator extends (Node => List[CodeGenOutput]) {
(list, currentDocument) =>
// add the combination with current parentheses documents
list ++ currentListDocuments map {
paren(_:Document) ::
// if rest of the list is just one element it will be returned with no parentheses
{ if (restOfTheList.size == 1) currentDocument else paren(currentDocument) }
(_:Document) :: backToBackParentheses :: currentDocument
}
}
}
Expand All @@ -139,10 +143,33 @@ abstract class CodeGenerator extends (Node => List[CodeGenOutput]) {

// if there is only one parameter and parentheses will not be outputed we have
// to transform (potential) abstractions with braces
if (params.size == 1 && !parenthesesRequired)
getParamsCombinations(params, SinglePar)
else
getParamsCombinationsRec(params, paramsInfo)
val context:TransformContext = (params.size > 1 && !parenthesesRequired) ? SinglePar | Expr

// is curried?
if (paramsInfo.size > 1)
getParamsCombinationsRec(params, paramsInfo)
else
getParamsCombinations(params, context)
}

// declare an implicit helper
// ?:: concatenates the documents only if first one is not `empty` otherwise result is `empty`
sealed case class DocumentHelper(innerDoc: Document) {
def ?::(argDoc: Document) = addOrEmpty(argDoc, innerDoc)
def ?::(argDoc: String) = addOrEmpty(argDoc, innerDoc)
def :/?:(argDoc: Document): Document = innerDoc match {
case scala.text.DocNil => argDoc
case _ => argDoc :/: innerDoc
}
def :?/:(argDoc: Document): Document = argDoc match {
case scala.text.DocNil => innerDoc
case _ => argDoc :/: innerDoc
}
}

object DocumentHelper {
implicit def DocumentHelperCast(d: Document) = DocumentHelper(d)
implicit def DocumentHelperCast(s: String) = DocumentHelper(s)
}

// ternary operator support
Expand All @@ -153,7 +180,7 @@ abstract class CodeGenerator extends (Node => List[CodeGenOutput]) {
}

object Bool {
implicit def BooleanBool(b: Boolean) = Bool(b)
implicit def BooleanBool(b: Boolean): Bool = Bool(b)
}

}
Expand Down

0 comments on commit 53c3396

Please sign in to comment.