diff --git a/Notes.md b/Notes.md new file mode 100644 index 0000000..1cad78d --- /dev/null +++ b/Notes.md @@ -0,0 +1,22 @@ +# Notes on AST Parsing + +### Generics + +Generics will always look like this: +AST Parsing for ItemViewModel +```$xslt +CallConstructor(type=Simple(pieces=[Piece(name=ItemViewModel, typeParams=[Type(mods=[], ref=Simple(pieces=[Piece(name=CatSchedule, typeParams=[])]))])]), typeArgs=[Type(mods=[], ref=Simple(pieces=[Piece(name=CatSchedule, typeParams=[])]))], args=[], lambda=null) +``` + + +Getting the generic type: +```$xslt +"List<" + node.expr().typeArgs().getObject(0).ref().getType() + ">" +``` + + +##### Difference between Type Parameter and Type Argument + +**Type parameter** is blueprint or placeholder for a type declared in generic. + +**Type argument** is actual type used to parametrize generic. \ No newline at end of file diff --git a/src/main/kotlin/com/github/ast/parser/KParser.kt b/src/main/kotlin/com/github/ast/parser/KParser.kt index 0616f4c..e979b3e 100644 --- a/src/main/kotlin/com/github/ast/parser/KParser.kt +++ b/src/main/kotlin/com/github/ast/parser/KParser.kt @@ -72,9 +72,9 @@ interface KParser { * - structs: companion objects, etc TODO get to this eventually * * @param className: [String] -> Node.Decl.name of class - * @param file: [Node.File] -> kastree.ast.Node.File + * @param structuredNode: [Node.Decl.Structured] -> kastree.ast.Node.Decl.Structured */ - fun breakDownClass(className: String, file: Node.File) + fun breakDownClass(className: String, structuredNode: Node.Decl.Structured) /** * Convert method with [Gson] and start breaking down class methods @@ -106,7 +106,7 @@ interface KParser { * @param methodStatements: [ArrayList] -> ArrayList of [String] passed down * to preserve methods per class */ - fun breakdownBody(body: JsonObject, methodStatements: ArrayList) + fun breakdownBody(body: JsonObject, methodStatements: ArrayList): ArrayList /** * Breakdown the contents of a method located in a block, or { }. @@ -116,7 +116,7 @@ interface KParser { * @param methodStatements: [ArrayList] -> ArrayList of [Method] passed down * to preserve methods per class */ - fun breakdownStmts(stmts: JsonArray, methodStatements: ArrayList? = ArrayList()) + fun breakdownStmts(stmts: JsonArray, methodStatements: ArrayList = ArrayList()): ArrayList /** * Determine whether a node declaration is an expression: @@ -163,12 +163,11 @@ interface KParser { fun breakdownExpr( expr: JsonObject, buildStmt: String, - methodStatements: ArrayList? = arrayListOf() + methodStatements: ArrayList = arrayListOf() ): String /** - * TODO FIND THE DIFFERENCE BETWEEN PARAMS, ARGUMENTS, AND PARAMS - * Breaks down parameter values passed within a method call + * Breaks down parameter values defined in a function call * * @param params: [JsonArray] -> node parameters * @param buildStmt: [String] -> Buildup of statement string to record @@ -179,7 +178,7 @@ interface KParser { fun getParams(params: JsonArray, buildStmt: String): String /** - * TODO FIND THE DIFFERENCE BETWEEN PARAMS, ARGUMENTS, AND PARAMS + * TODO FIND ELEMENT DEFINITION * Breaks down elements within a collection * * @param elems: [JsonArray] -> node elements @@ -191,8 +190,7 @@ interface KParser { fun getElems(elems: JsonArray, buildStmt: String): String /** - * TODO FIND THE DIFFERENCE BETWEEN PARAMS, ARGUMENTS, AND PARAMS - * Breaks down parameter values passed within a method call + * Breaks down argument, the actual value passed to the function * * @param arguments: [JsonArray] -> node arguments * @param buildStmt: [String] -> Buildup of statement string to record @@ -268,15 +266,4 @@ interface KParser { */ fun getProperty(node: JsonObject, isolated: JsonObject, isolatedName: String): Property - /*** - * Kastree readOnly values indicates whether a value is mutable or immutable. - * - * @param node: [JsonObject] - node property - * @param isolated: [JsonObject] - for potential dependency injection - * @param isolatedName: [String] - name assigned to property - * - * @return [String] 'val' or 'var' - */ - fun valOrVar(node: JsonObject): String - } diff --git a/src/main/kotlin/com/github/ast/parser/KParserImpl.kt b/src/main/kotlin/com/github/ast/parser/KParserImpl.kt index 05dd11e..05b1d2d 100644 --- a/src/main/kotlin/com/github/ast/parser/KParserImpl.kt +++ b/src/main/kotlin/com/github/ast/parser/KParserImpl.kt @@ -30,39 +30,41 @@ open class KParserImpl( override val gson = Gson() - var utils = KParserUtils() - override fun parseAST(textFile: String) { val file = Parser.parseFile(textFile, true) file.decls.forEach { node -> when (node) { - is Node.Decl.Structured -> breakDownClass(node.name, file) + is Node.Decl.Structured -> breakDownClass(node.name, node) is Node.Decl.Func -> node.name ?: independentFunctions.add(node.name.toString()) } } } - override fun breakDownClass(className: String, file: Node.File) { + override fun breakDownClass(className: String, structuredNode: Node.Decl.Structured) { val classParents = ArrayList() val classProperties = ArrayList() val classMethods = ArrayList() - val structuredNode = file.decls[0] as Node.Decl.Structured + structuredNode.parents.forEach { parentClass -> + val superClassNode = gson.toJsonTree(parentClass).asJsonObject + var superClass = superClassNode.type().getType() + + // if parent class accepts generic parameters + if (superClassNode.hasTypeArgs()) { + superClass += getGenericTypeArgs(superClassNode) + } - // collecting this info for test information - structuredNode.parents.forEach { - val superClass = gson.toJsonTree(it).asJsonObject.type().getType() classParents.add(superClass) componentBreakdownFunction(superClass, className) } // Save for all files - structuredNode.members.forEach { - when (it) { + structuredNode.members.forEach { member -> + when (member) { is Node.Decl.Structured -> println("this is probably a companion object") - is Node.Decl.Property -> convertToClassProperty(it, classProperties, className) - is Node.Decl.Func -> breakdownClassMethod(it, classMethods) + is Node.Decl.Property -> convertToClassProperty(member, classProperties, className) + is Node.Decl.Func -> breakdownClassMethod(member, classMethods) } } @@ -73,8 +75,6 @@ open class KParserImpl( val methodJson = gson.toJsonTree(method).asJsonObject val methodContent = ArrayList() - breakdownBody(methodJson.body(), methodContent) - val parameters = ArrayList() methodJson.params().forEach { parameter -> val param = parameter.asJsonObject @@ -87,6 +87,8 @@ open class KParserImpl( parameters.add(Property("val", param.name(), paramType)) } + methodContent.addAll(breakdownBody(methodJson.body(), methodContent)) + var returnType = "Unit" if (methodJson.has("type")) { returnType = methodJson.type().ref().getType() @@ -104,29 +106,39 @@ open class KParserImpl( ) } - override fun breakdownBody(body: JsonObject, methodStatements: ArrayList) { + override fun breakdownBody(body: JsonObject, methodStatements: ArrayList): ArrayList { + val stmtArray = arrayListOf() + stmtArray.addAll(methodStatements) + when { - body.has("block") -> breakdownStmts(body.block().stmts(), methodStatements) - body.has("expr") -> methodStatements.add(breakdownExpr(body.expr(), "")) - else -> methodStatements.add(breakdownBinaryOperation((body.expr()), "")) + body.hasBlock() -> stmtArray.addAll(breakdownStmts(body.block().stmts(), methodStatements)) + body.hasDeclaration() || + body.hasExpression() -> stmtArray.add(breakdownExpr(body.expr(), "")) + else -> stmtArray.add(breakdownBinaryOperation((body.expr()), "")) } + + return stmtArray } - override fun breakdownStmts(stmts: JsonArray, methodStatements: ArrayList?) { + override fun breakdownStmts(stmts: JsonArray, methodStatements: ArrayList): ArrayList { + val stmtArray = arrayListOf() + stmtArray.addAll(methodStatements) + stmts.forEach { statement -> val stmt = statement.asJsonObject when { - stmt.has("expr") -> methodStatements?.add(breakdownExpr(stmt.expr(), "")) - stmt.has("decl") -> methodStatements?.add(breakdownDecl(stmt.decl(), "")) + stmt.hasExpression() -> stmtArray.add(breakdownExpr(stmt.expr(), "")) + stmt.hasDeclaration() -> stmtArray.add(breakdownDecl(stmt.decl(), "")) else -> println("stmt has$stmt") } } + return stmtArray } override fun breakdownDecl(decl: JsonObject, buildStmt: String): String { return when { - decl.has("expr") -> breakdownDeclProperty(decl, buildStmt) - decl.has("body") -> { + decl.hasExpression() -> breakdownDeclProperty(decl, buildStmt) + decl.hasBody() -> { breakdownBody(decl.body(), arrayListOf()) "method body here: $decl" } @@ -134,50 +146,32 @@ open class KParserImpl( } } - /** - * Not fucked up but does not account for all decl property types nor does it format properly - */ override fun breakdownDeclProperty(decl: JsonObject, buildStmt: String): String { - val isolated = decl.vars().getObject(0) - val isolatedName = isolated.name() - var expression = breakdownExpr(decl.expr(), "") - val property = when { - decl.expr().has("expr") -> { - if (decl.expr().has("args")) { - expression = getArguments(decl.expr().args(), expression) - } - - if (decl.expr().has("expr") && decl.expr().has("oper")) { - Property(valOrVar(decl), isolatedName, decl.vars().getObject(0).type().ref().pieces().getObject(0).name()) - } else { - getProperty( - decl, - isolated, - isolatedName) - } + val propertyName = decl.vars().getObject(0).name() + val propertyValue = when { + decl.expr().hasExpressionCall() -> getExpressionCall(decl.expr()) + decl.expr().has("expr") && decl.expr().has("oper") -> { + var expression = breakdownExpr(decl.expr(), "") + expression += decl.vars().getObject(0).type().ref().getType() + expression + } + decl.expr().hasBinaryOperation() -> breakdownBinaryOperation(decl.expr(), "") + decl.expr().has("value") -> { + var expression = breakdownBinaryOperation(decl.expr(), "") + expression } - decl.expr().has("lhs") && - decl.expr().has("oper") && - decl.expr().has("rhs") -> Property( - valOrVar(decl), - isolatedName, - breakdownBinaryOperation(decl.expr(), "") - ) - decl.expr().has("value") -> Property( - valOrVar(decl), - isolatedName, - utils.getPrimitiveType(decl.expr())) else -> TODO() } - val declaration = "$buildStmt${property.valOrVar} $isolatedName: ${property.propertyType}" - return "$declaration = $expression" + val declaration = "${valOrVar(decl)} $propertyName" + + return "$declaration = $propertyValue" } override fun breakdownExpr( expr: JsonObject, buildStmt: String, - methodStatements: ArrayList? + methodStatements: ArrayList ): String { var exprStmt = buildStmt exprStmt += when { @@ -185,11 +179,11 @@ open class KParserImpl( expr.has("oper") && expr.has("rhs")-> breakdownBinaryOperation(expr, exprStmt) expr.has("args") -> getArguments(expr.args(), exprStmt) - expr.has("name") -> exprStmt + expr.name() + expr.has("name") -> expr.name() expr.has("expr") -> breakdownExpr(expr.expr(), exprStmt) expr.has("elems") -> getElems(expr.elems(), exprStmt) expr.has("params") -> getParams(expr.params(), exprStmt) - expr.has("value") -> exprStmt + utils.getPrimitiveValue(expr) + expr.has("value") -> exprStmt + getPrimitiveValue(expr) expr.has("block") -> breakdownStmts(expr.block().stmts(), methodStatements) expr.size() == 0 -> {} else -> println(expr) @@ -197,6 +191,29 @@ open class KParserImpl( return exprStmt } + private fun getExpressionCall(expr: JsonObject): String { + val anonymousFunction = if (expr.hasLambda()) getLambda(expr.lambda()) else "" + return getArguments(expr.args(), expr.expr().name()) + anonymousFunction + } + + private fun getLambda(lambda: JsonObject): String { + var buildLambda = "" + buildLambda += breakdownFunction(lambda.func()).forEach(::println) + return buildLambda + } + + private fun breakdownFunction(func: JsonObject): ArrayList { + val functionContent = ArrayList() + when { + func.hasParams() -> functionContent.add("params: " + getParams(func.params(), "")) + func.hasBody() -> functionContent.addAll(breakdownBody(func.body(), functionContent)) + func.hasBlock() -> functionContent.addAll(breakdownStmts(func.block().stmts(), functionContent)) + else -> functionContent.add("") + } + + return functionContent + } + override fun getParams(params: JsonArray, buildStmt: String): String { var buildParams = buildStmt params.forEach { parameter -> @@ -211,14 +228,12 @@ open class KParserImpl( elems.forEach { val elem = it.asJsonObject buildElems += when { - elem.has("str") -> elem.str() - elem.has("expr") -> breakdownExpr(elem, buildElems) - elem.has("value") -> utils.getPrimitiveValue(elem) - elem.has("lhs") && - elem.has("oper") && - elem.has("rhs") -> breakdownBinaryOperation(elem, buildElems) - elem.has("name") -> elem.name() - elem.has("recv") -> elem.recv().type().getType() + elem.hasName() -> elem.name() + elem.hasString() -> elem.str() + elem.hasExpression() -> breakdownExpr(elem, buildElems) + elem.hasPrimitiveValue() -> getPrimitiveValue(elem) + elem.hasBinaryOperation() -> breakdownBinaryOperation(elem, buildElems) + elem.hasReceiver() -> elem.recv().type().getType() else -> println("Looks like this element type is: $elem") } } @@ -231,13 +246,13 @@ open class KParserImpl( if (arguments.size() > 0) { arguments.forEachIndexed { index, argument -> val arg = argument.asJsonObject - val argExpression = argument.asJsonObject.expr() + val argExpression = arg.expr() buildArgs += when { - argExpression.has("name") -> argExpression.name() - argExpression.has("recv") -> argExpression.recv().type().getType() + "::class" - argExpression.has("elems") -> getElems(argExpression.elems(), buildArgs) - argExpression.has("expr") -> breakdownExpr(argExpression.expr(), "") + argExpression.hasName() -> argExpression.name() + argExpression.hasReceiver() -> argExpression.recv().type().getType() + "::class" + argExpression.hasElements() -> getElems(argExpression.elems(), buildArgs) + argExpression.hasExpression() -> breakdownExpr(argExpression.expr(), "") else -> "" // TODO } if (arg.has("name")) { @@ -254,37 +269,27 @@ open class KParserImpl( val lhs = expr.lhs() val leftHandSide = when { - lhs.has("value") -> utils.getPrimitiveValue(lhs) - lhs.has("name") -> lhs.name() - lhs.has("expr") -> { - var expression = breakdownExpr(lhs.expr(), "") - if (lhs.expr().has("args")) { - expression = getArguments(lhs.args(), expression) - } - expression - } - else -> breakdownBinaryOperation(expr.lhs(), buildBinary) + lhs.hasPrimitiveValue() -> getPrimitiveValue(lhs) + lhs.hasName() -> lhs.name() + lhs.hasExpressionCall() -> getExpressionCall(lhs) + lhs.hasExpression() -> breakdownExpr(lhs.expr(), "") + else -> breakdownBinaryOperation(expr.lhs(), buildBinary) } val oper = expr.oper() val operator = when { - oper.has("str") -> oper.str() - oper.has("token") -> utils.getToken(oper.token()) - else -> "{$oper}" + oper.hasString() -> oper.str() + oper.hasToken() -> getToken(oper.token()) + else -> "{$oper}" } val rhs = expr.rhs() val rightHandSide = when { - rhs.has("value") -> utils.getPrimitiveValue(rhs) - rhs.has("name") -> rhs.name() - rhs.has("expr") -> { - var expression = breakdownExpr(rhs.expr(), "") - if (rhs.expr().has("args")) { - expression = getArguments(rhs.args(), expression) - } - expression - } - else -> breakdownBinaryOperation(expr.rhs(), buildBinary) + rhs.hasPrimitiveValue() -> getPrimitiveValue(rhs) + rhs.hasName() -> rhs.name() + rhs.hasExpressionCall() -> getExpressionCall(rhs) + rhs.hasExpression() -> breakdownExpr(rhs.expr(), "") + else -> breakdownBinaryOperation(expr.rhs(), buildBinary) } buildBinary += "$leftHandSide$operator$rightHandSide" @@ -332,10 +337,9 @@ open class KParserImpl( * above for Binary Operations */ override fun getObservableProperty(node: JsonObject, isolatedName: String): Property { - val type = node.expr().lhs().expr().name() // build objects for primitive lists - val isolatedType = when (type) { + val isolatedType = when (val type = node.expr().lhs().expr().name()) { "listOf" -> { // get list val elements = node.expr().lhs().args() @@ -349,8 +353,8 @@ open class KParserImpl( objectItems.forEachIndexed { index, property -> val elem = property.asJsonObject.expr().elems().getObject(0) when { - elem.has("str") -> list += "${elem.get("str")}" - elem.has("expr") -> list += breakdownExpr(elem, list) + elem.hasString() -> list += "${elem.get("str")}" + elem.hasExpression() -> list += breakdownExpr(elem, list) else -> println("Looks like this element type is: $elem") } list += if (index != objectItems.size() - 1) ", " else ").observable" @@ -378,7 +382,7 @@ open class KParserImpl( when { // primitive property node.expr().expr().has("form") -> { - isolatedType = utils.getPrimitiveType(node.expr().expr().form()) + isolatedType = getPrimitiveType(node.expr().expr().form()) } // collection property node.expr().expr().has("name") -> { @@ -394,10 +398,9 @@ open class KParserImpl( } } "HashMap" -> "$type<" + - node.expr().typeArgs().getObject(0).ref().getType() + ","+ - node.expr().typeArgs().getObject(1).ref().getType() + ">" - "ArrayList" -> "$type<" + - node.expr().typeArgs().getObject(0).ref().getType() + ">" + node.getGenericTypeArgument(0) + "," + + node.getGenericTypeArgument(1) + ">" + "ArrayList" -> "$type<" + node.getGenericTypeArgument(0) + ">" "mutableListOf" -> { val listOfMemberType = node.expr().typeArgs() @@ -415,8 +418,6 @@ open class KParserImpl( return Property(valOrVar(node), isolatedName, isolatedType) } - override fun valOrVar(node: JsonObject): String = if (node.readOnly()) "val " else "var " - /** * Using enum classes to check for control values here */ diff --git a/src/main/kotlin/com/github/ast/parser/KParserUtils.kt b/src/main/kotlin/com/github/ast/parser/KParserUtils.kt index a71614c..081b9fc 100644 --- a/src/main/kotlin/com/github/ast/parser/KParserUtils.kt +++ b/src/main/kotlin/com/github/ast/parser/KParserUtils.kt @@ -2,59 +2,82 @@ package com.github.ast.parser import com.google.gson.JsonObject -class KParserUtils { - - fun getPrimitiveValue(value: JsonObject): String { - val gValue = value.get("value") - return when (value.get("form").asJsonPrimitive.toString()) { - "\"BOOLEAN\"" -> gValue.asBoolean.toString() - "\"BYTE\"" -> gValue.asByte.toString() - "\"CHAR\"" -> gValue.asCharacter.toString() - "\"DOUBLE\"" -> gValue.asDouble.toString() - "\"FLOAT\"" -> gValue.asFloat.toString() - "\"INT\"" -> gValue.asInt.toString() - "\"NULL\"" -> "null" - else -> "Unrecognized value type" - } +fun KParserImpl.getPrimitiveValue(value: JsonObject): String { + val gValue = value.get("value") + return when (value.get("form").asJsonPrimitive.toString()) { + "\"BOOLEAN\"" -> gValue.asBoolean.toString() + "\"BYTE\"" -> gValue.asByte.toString() + "\"CHAR\"" -> gValue.asCharacter.toString() + "\"DOUBLE\"" -> gValue.asDouble.toString() + "\"FLOAT\"" -> gValue.asFloat.toString() + "\"INT\"" -> gValue.asInt.toString() + "\"NULL\"" -> "null" + else -> "Unrecognized value type" } +} - // TODO rewrite to accept 2 types for primitive - fun getPrimitiveType(form: JsonObject): String { - return when (form.get("form").asJsonPrimitive.toString()) { - "\"BOOLEAN\"" -> "Boolean" - "\"BYTE\"" -> "Byte" - "\"CHAR\"" -> "Char" - "\"DOUBLE\"" -> "Double" - "\"FLOAT\"" -> "Float" - "\"INT\"" -> "Int" - "\"NULL\"" -> "null" - else -> "Unrecognized value type" // object type probs - } +// TODO rewrite to accept 2 types for primitive +fun KParserImpl.getPrimitiveType(form: JsonObject): String { + return when (form.get("form").asJsonPrimitive.toString()) { + "\"BOOLEAN\"" -> "Boolean" + "\"BYTE\"" -> "Byte" + "\"CHAR\"" -> "Char" + "\"DOUBLE\"" -> "Double" + "\"FLOAT\"" -> "Float" + "\"INT\"" -> "Int" + "\"NULL\"" -> "null" + else -> "Unrecognized value type" // object type probs } +} - fun getPrimitiveType(form: String): String { - return when (form) { - "\"BOOLEAN\"" -> "Boolean" - "\"BYTE\"" -> "Byte" - "\"CHAR\"" -> "Char" - "\"DOUBLE\"" -> "Double" - "\"FLOAT\"" -> "Float" - "\"INT\"" -> "Int" - "\"NULL\"" -> "null" - else -> "Unrecognized value type" // object type probs - } +fun KParserImpl.getPrimitiveType(form: String): String { + return when (form) { + "\"BOOLEAN\"" -> "Boolean" + "\"BYTE\"" -> "Byte" + "\"CHAR\"" -> "Char" + "\"DOUBLE\"" -> "Double" + "\"FLOAT\"" -> "Float" + "\"INT\"" -> "Int" + "\"NULL\"" -> "null" + else -> "Unrecognized value type" // object type probs + } +} + +fun KParserImpl.getToken(token: String): String { + return when (token) { + "DOT" -> "." + "ASSN" -> " = " + "NEQ" -> " != " + "NEG" -> " - " + "EQ" -> " == " + "RANGE" -> ".." + "AS" -> " as " + "ADD" -> " + " + else -> token } +} + +/*** + * Kastree readOnly values indicates whether a value is mutable or immutable. + * + * @param node: [JsonObject] - node property + * @param isolated: [JsonObject] - for potential dependency injection + * @param isolatedName: [String] - name assigned to property + * + * @return [String] 'val' or 'var' + */ +fun KParserImpl.valOrVar(node: JsonObject): String = if (node.readOnly()) "val " else "var " - fun getToken(token: String): String { - return when (token) { - "DOT" -> "." - "ASSN" -> " = " - "NEQ" -> " != " - "NEG" -> "-" - "EQ" -> " == " - "RANGE" -> " " - "AS" -> " as " - else -> token +fun KParserImpl.getGenericTypeArgs(node: JsonObject): String { + var result = "<" + val genericType = node.expr().typeArgs() + + for (i in 0..genericType.size()) { + result += genericType.getObject(i).ref().getType() + if (i < genericType.size()) { + result += ", " } } + + return "$result>" } \ No newline at end of file diff --git a/src/main/kotlin/com/github/ast/parser/NodeExtensions.kt b/src/main/kotlin/com/github/ast/parser/NodeExtensions.kt index d9b4209..d1be41c 100644 --- a/src/main/kotlin/com/github/ast/parser/NodeExtensions.kt +++ b/src/main/kotlin/com/github/ast/parser/NodeExtensions.kt @@ -3,9 +3,9 @@ package com.github.ast.parser import com.google.gson.JsonArray import com.google.gson.JsonObject -fun JsonObject.getType() = this.pieces().getObject(0).name() +fun JsonObject.getType(): String = this.pieces().getObject(0).name() -fun JsonObject.getCollectionType(num: Int) = this.expr().typeArgs().getObject(num).ref().getType() +fun JsonObject.getGenericTypeArgument(num: Int): String = this.expr().typeArgs().getObject(num).ref().getType() fun JsonObject.lambda(): JsonObject = this.get("lambda").asJsonObject @@ -61,4 +61,40 @@ fun JsonObject.str(): String = this.get("str").asString fun JsonObject.name(): String = this.get("name").asString -fun JsonObject.form(): String = this.get("form").asString \ No newline at end of file +fun JsonObject.form(): String = this.get("form").asString + +// next check + +fun JsonObject.hasBody(): Boolean = this.has("body") + +fun JsonObject.hasBlock(): Boolean = this.has("block") + +fun JsonObject.hasParams(): Boolean = this.has("params") + +fun JsonObject.hasDeclaration(): Boolean = this.has("decl") + +fun JsonObject.hasName(): Boolean = this.has("name") + +fun JsonObject.hasString(): Boolean = this.has("str") + +fun JsonObject.hasToken(): Boolean = this.has("token") + +fun JsonObject.hasExpression(): Boolean = this.has("expr") + +fun JsonObject.hasPrimitiveValue(): Boolean = this.has("value") + +fun JsonObject.hasBinaryOperation(): Boolean = this.has("lhs") && this.has("oper") && this.has("rhs") + +fun JsonObject.hasReceiver(): Boolean = this.has("recv") + +fun JsonObject.hasElements(): Boolean = this.has("recv") + +fun JsonObject.hasLambda(): Boolean = this.has("lambda") + +fun JsonObject.hasFunc(): Boolean = this.has("func") + +fun JsonObject.hasArgs(): Boolean = this.has("args") + +fun JsonObject.hasTypeArgs(): Boolean = this.has("typeArgs") + +fun JsonObject.hasExpressionCall(): Boolean = this.hasExpression() && this.hasTypeArgs() && this.hasArgs() \ No newline at end of file diff --git a/src/main/kotlin/com/github/ast/parser/frameworkconfigurations/TornadoFX.kt b/src/main/kotlin/com/github/ast/parser/frameworkconfigurations/TornadoFX.kt index e8513f1..3bb7c22 100644 --- a/src/main/kotlin/com/github/ast/parser/frameworkconfigurations/TornadoFX.kt +++ b/src/main/kotlin/com/github/ast/parser/frameworkconfigurations/TornadoFX.kt @@ -62,8 +62,20 @@ fun KParserImpl.saveComponentBreakdown( if (!currentTFXView.type.isNullOrEmpty()) { views[className] = currentTFXView - // TODO need to create a contravariant function to allow this to happen - // parser.views.add(currentTFXView) + } +} + +/** + * TornadoFX specific: + * Detects TornadoFX Scopes for Views + */ +fun KParserImpl.mapNodesToFunctions( + isolatedName: String, + className: String, + node: JsonObject +) { + if (isolatedName == "scope") { + views[className]?.scope = node.expr().rhs().ref().getType() } } diff --git a/src/main/kotlin/com/github/hd/tornadofxsuite/EditorFSM.kt b/src/main/kotlin/com/github/hd/tornadofxsuite/EditorFSM.kt new file mode 100644 index 0000000..fdb8d60 --- /dev/null +++ b/src/main/kotlin/com/github/hd/tornadofxsuite/EditorFSM.kt @@ -0,0 +1,70 @@ +package com.github.hd.tornadofxsuite + +/** + * Experimental example FSM for smarter testing + */ + +sealed class EditorFragment { + var modelState = ModelState.NotDirty + + fun commitModel() {} + + open class OwnerTextField: EditorFragment() { + fun onChangeText() { + modelState.initModelStateTransition() + } + } + + open class CatTextField: EditorFragment() { + fun onChangeText() { + modelState.initModelStateTransition() + } + } + + open class TimeTextField: EditorFragment() { + fun onChangeText() { + modelState.initModelStateTransition() + } + } + + class SaveButton(var toggle: Toggle = Toggle.Disable): EditorFragment() { + fun toggleButtonOnDirtyModel(model: ModelState) { + toggle.enableOnDirty(model) + } + + fun saveModel() { + if (toggle.isButtonEnabled()) { + commitModel() + } + } + } +} + +enum class Toggle { + Enable, Disable; + + fun isButtonEnabled(): Boolean { + return when (this) { + Enable -> true + Disable -> false + } + } + + fun enableOnDirty(model: ModelState): Toggle { + return when (model) { + ModelState.Dirty -> Enable + ModelState.NotDirty -> Disable + } + } +} + +enum class ModelState { + Dirty, NotDirty; + + fun initModelStateTransition(): ModelState { + return when (this) { + Dirty -> NotDirty + NotDirty -> Dirty + } + } +} \ No newline at end of file