Skip to content

Commit

Permalink
WIP: Started looking to statement breakdown for methods to start trac…
Browse files Browse the repository at this point in the history
…king affected view nodes. If this works, we can refactor the rest of the parser to use these methods recursively.
  • Loading branch information
Amanda Hinchman-Dominguez committed Jan 7, 2019
1 parent 764f42f commit 66686fc
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 63 deletions.
9 changes: 2 additions & 7 deletions UITest.kt
Expand Up @@ -12,17 +12,12 @@ class UITest {
}

@Test
fun testitem() {

}

@Test
fun testform() {
fun testtextfield() {

}

@Test
fun testbutton() {
fun testtextfield() {

}

Expand Down
9 changes: 6 additions & 3 deletions src/main/kotlin/com/github/ast/parser/Class.kt
Expand Up @@ -7,12 +7,15 @@ data class ClassBreakDown(val className: String,
val classProperties: ArrayList<Property>,
val classMethods: ArrayList<Method>)

data class Property(val propertyName: String,
data class Property(val valOrVar: String,
val propertyName: String,
val propertyType: String)

data class Method(val methodName: String,
data class Method(val name: String,
val parameters: ArrayList<Property>,
val returnType: String = "Unit")
val returnType: String = "Unit",
val methodStatements: ArrayList<String>,
val viewNodesAffected: ArrayList<String>)

// I'm actually not sure if it's beneficial to keep an index of the path for a directed graph
// but I'mma put it in here anyway
Expand Down
28 changes: 0 additions & 28 deletions src/main/kotlin/com/github/ast/parser/GsonNodeConversion.kt

This file was deleted.

155 changes: 130 additions & 25 deletions src/main/kotlin/com/github/ast/parser/KParser.kt
@@ -1,19 +1,17 @@
package com.github.ast.parser

import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.*
import kastree.ast.Node
import kastree.ast.psi.Parser
import tornadofx.*

class KParser : Controller() {

var classes = ArrayList<ClassBreakDown>()
var independentFunctions = ArrayList<String>()
private var independentFunctions = ArrayList<String>()
var detectedInputs = ArrayList<String>()
var detectedUIControls = HashMap<String, ArrayList<String>>()
val gson = Gson()

fun parseAST(textFile: String) {
val file = Parser.parseFile(textFile, true)
Expand All @@ -27,33 +25,116 @@ class KParser : Controller() {
}

private fun breakDownClass(className: String, file: Node.File) {
val classProperties = ArrayList<ClassProperties>()
val classMembers = ArrayList<String>()
val classProperties = ArrayList<Property>()
val classMethods = ArrayList<Method>()

// Save for all files
(file.decls[0] as Node.Decl.Structured).members.forEach {
when (it) {
is Node.Decl.Structured -> println("this is probably a companion object")
is Node.Decl.Property -> convertToMemberJsonProperty(it, classProperties, className)
is Node.Decl.Func -> it.name ?: classMembers.add(it.name.toString())
is Node.Decl.Property -> convertToClassProperty(it, classProperties, className)
is Node.Decl.Func -> breakdownClassMethod(it, classMethods)
}
}
classes.add(ClassBreakDown(className, classProperties, classMembers))
classes.add(ClassBreakDown(className, classProperties, classMethods))
}

private fun breakdownClassMethod(method: Node.Decl.Func, classMethods: ArrayList<Method>) {
val methodJson = gson.toJsonTree(method).asJsonObject
val methodStatements = ArrayList<String>()
val methodStmts = methodJson.body().block().stmts()
if (methodStmts.size() > 0) {
methodStmts.forEach { statement ->
val stmt = statement.asJsonObject
when {
stmt.has("expr") ->
methodStatements.add(breakdownExpr(stmt.expr(), ""))
stmt.has("decl") ->
methodStatements.add(breakdownDecl(stmt.decl(), ""))
else -> println("stmt has$stmt")
}
}
}

val parameters = ArrayList<Property>()
methodJson.params().forEach { parameter ->
val param = parameter.asJsonObject
val paramType = param.type().ref().pieces().getObject(0).name()
parameters.add(Property("val", param.name(), paramType))
}

val returnType = methodJson.type().ref().pieces().getObject(0).name()

// TODO write a mechanism to detect nodes per function after AST parse job is complete
classMethods.add(Method(
name = methodJson.name(),
parameters = parameters,
returnType = returnType,
methodStatements = methodStatements,
viewNodesAffected = ArrayList<String>()))
}

private fun breakdownDecl(decl: JsonObject, buildStmt: String): String {
val isolated = decl.vars().getObject(0)
val isolatedName = isolated.name()
val property = getProperty(decl, isolated, isolatedName)
val declaration = "$buildStmt${property.valOrVar} $isolatedName: $isolated ="
return "$declaration = ${breakdownExpr(decl, buildStmt)}"
}

private fun breakdownExpr(expr: JsonObject, buildStmt: String): String {
when {
expr.has("lhs") &&
expr.has("oper") &&
expr.has("rhs")-> breakdownBinaryOperation(expr, buildStmt)
expr.has("args") -> getArguments(expr.args(), buildStmt)
expr.has("name") -> buildStmt + expr.name()
expr.has("expr") -> breakdownExpr(expr.expr(), buildStmt)
}
return buildStmt
}

/**
* Gets arguments in expressions
*/
private fun getArguments(arguments: JsonArray, buildStmt: String): String {
var buildArgs = "$buildStmt("
arguments.forEachIndexed { index, argument ->
val elem = argument.asJsonObject.expr().elems().getObject(0)
when {
elem.has("str") -> buildArgs += "${elem.get("str")}"
elem.has("expr") -> buildArgs += breakdownExpr(elem, buildArgs)
else -> println("Looks like this element type is: $elem")
}
buildArgs += if (index < arguments.size()) ", " else ")"
}
return buildArgs
}

// TODO - look into other types of binary operations
private fun breakdownBinaryOperation(expr: JsonObject, buildStmt: String): String {
return if (expr.oper().token() == "DOT") {
"$buildStmt${breakdownExpr(expr.lhs(), buildStmt)}.${breakdownExpr(expr.rhs(), buildStmt)}"
} else {
"Binary Operation has: ${expr.oper().token()}"
}
}

/***
* Properties -
* Properties tend to have 2 types:
* Properties tend to have 2 types I care about:
* 1) kastree.ast.Node.Expr.Call -> is a member property of a certain class
* 2) kastree.ast.Node.Expr.Name -> an independent member property
*
* Note: This is the older version of getting properties. Down the road this ought to
* be refactored to use the above recursive functions
*/
private fun convertToMemberJsonProperty(property: Node.Decl.Property,
propList: ArrayList<ClassProperties>,
className: String) {
private fun convertToClassProperty(property: Node.Decl.Property,
propList: ArrayList<Property>,
className: String) {
val secondBit = "expr=Call(expr=Name(name="
val string = property.toString()

val gson = Gson()
val nodesElement: JsonElement = gson.toJsonTree(property)

if (string.contains(secondBit)) {
Expand All @@ -67,23 +148,27 @@ class KParser : Controller() {

val classProperty = when {
node.expr().has("lhs") -> getObservableProperty(node, isolatedName)
else -> getClassProperty(node, isolated, isolatedName)
else -> getProperty(node, isolated, isolatedName)
}

propList.add(classProperty)
}
}

private fun getObservableProperty(node: JsonObject, isolatedName: String): ClassProperties {
/**
* Observable class properties ought to be refactored to use the recursive breakdown
* above for Binary Operations
*/
private fun getObservableProperty(node: JsonObject, isolatedName: String): Property {
val type = node.expr().lhs().expr().name()

// get list
val elements = node.expr().lhs().args()
var list = ""

// build objects for primitive lists
val isolatedType = when (type) {
"listOf" -> {
// get list
val elements = node.expr().lhs().args()
var list = ""

elements.forEach { element ->
val elemType = element.asJsonObject.expr().expr().name()
list += "$elemType("
Expand All @@ -92,9 +177,10 @@ class KParser : Controller() {
val elem = property.asJsonObject.expr().elems().getObject(0)
when {
elem.has("str") -> list += "${elem.get("str")}"
elem.has("expr") -> list += breakdownExpr(elem, list)
else -> println("Looks like this element type is: $elem")
}
list += if (index != objectItems.size()) ", " else ")"
list += if (index != objectItems.size() - 1) ", " else ").observable"
}
}
list
Expand All @@ -104,10 +190,15 @@ class KParser : Controller() {
type
}
}
return ClassProperties(isolatedName, isolatedType)
val valOrVar = if (node.readOnly()) "val " else "var "

return Property(valOrVar, isolatedName, isolatedType)
}

private fun getClassProperty(node: JsonObject, isolated: JsonObject, isolatedName: String): ClassProperties {
/**
* This is probably fine for now
*/
private fun getProperty(node: JsonObject, isolated: JsonObject, isolatedName: String): Property {

val type = node.expr().expr().name()

Expand Down Expand Up @@ -142,8 +233,9 @@ class KParser : Controller() {
}
else -> type
}
val valOrVar = if (node.readOnly()) "val " else "var "

return ClassProperties(isolatedName, isolatedType)
return Property(valOrVar, isolatedName, isolatedType)
}

// For TornadoFX DSLs
Expand Down Expand Up @@ -214,4 +306,17 @@ class KParser : Controller() {

private fun JsonObject.elems(): JsonArray = this.get("elems").asJsonArray

private fun JsonObject.body(): JsonObject = this.get("body").asJsonObject

private fun JsonObject.decl(): JsonObject = this.get("decl").asJsonObject

private fun JsonObject.readOnly(): Boolean = this.get("readOnly").asBoolean

private fun JsonObject.delegated(): Boolean = this.get("delegated").asBoolean

private fun JsonObject.oper(): JsonObject = this.get("oper").asJsonObject

private fun JsonObject.token(): String = this.get("token").asString

private fun JsonObject.params(): JsonArray = this.get("params").asJsonArray
}

0 comments on commit 66686fc

Please sign in to comment.