From 39c9adb794e665a5555f29c802d7d4453e037887 Mon Sep 17 00:00:00 2001 From: Andreas Stadelmeier Date: Wed, 17 Nov 2021 06:39:26 +0100 Subject: [PATCH] Output typed classes. Filter constraints before inserting them as method generics --- index.css | 6 +++- src/main/scala/hb/dhbw/FJTypeinference.scala | 7 ++-- src/main/scala/hb/dhbw/InsertTypes.scala | 13 ++++++-- src/main/scala/hb/dhbw/Main.scala | 35 ++++++++++++++++---- src/test/scala/IntegrationTest.scala | 8 +++-- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/index.css b/index.css index d406513..9732d24 100644 --- a/index.css +++ b/index.css @@ -53,7 +53,6 @@ textarea { } #fj-input, -#ast-output, #unify-output { width: 100%; height: 100%; @@ -73,6 +72,11 @@ textarea { } #ast-output { + width: 100%; + height: 100%; + box-sizing: border-box; + border-radius: 10px; + padding: 10px; border: 1px solid black; } diff --git a/src/main/scala/hb/dhbw/FJTypeinference.scala b/src/main/scala/hb/dhbw/FJTypeinference.scala index 818ab31..beafd6f 100644 --- a/src/main/scala/hb/dhbw/FJTypeinference.scala +++ b/src/main/scala/hb/dhbw/FJTypeinference.scala @@ -34,9 +34,9 @@ object FJTypeinference { ).toSet) private def cToUnifyType(c: Class): UnifyRefType = UnifyRefType(c.name, c.genericParams.map(it => convertType(it._1))) - def typeinference(str: String): Either[String, Set[Set[UnifyConstraint]]] = { + def typeinference(str: String): Either[String, (Set[Set[UnifyConstraint]], List[Class])] = { val ast = Parser.parse(str).map(ASTBuilder.fromParseTree(_)) - + var typedClasses: List[Class] = List() val typeResult = ast.map(ast => { var unifyResults = Set[Set[Set[UnifyConstraint]]]() ast.foldLeft(List[Class]())((cOld, c) => { @@ -45,11 +45,12 @@ object FJTypeinference { val unifyResult = Unify.unifyIterative(convertOrConstraints(typeResult._1), typeResult._2) //Insert intersection types val typeInsertedC = InsertTypes.insert(unifyResult, c) + typedClasses = typedClasses :+ typeInsertedC unifyResults = unifyResults + unifyResult cOld :+ typeInsertedC }) unifyResults }) - typeResult.map(_.flatten) + typeResult.map(it => (it.flatten, typedClasses)) } } diff --git a/src/main/scala/hb/dhbw/InsertTypes.scala b/src/main/scala/hb/dhbw/InsertTypes.scala index 8ff3d0e..ef05c1a 100644 --- a/src/main/scala/hb/dhbw/InsertTypes.scala +++ b/src/main/scala/hb/dhbw/InsertTypes.scala @@ -70,9 +70,18 @@ object InsertTypes { case TypeVariable(name) => GenericType(name) case RefType(name, params) => RefType(name, params.map(replaceTVWithGeneric(_))) } - val genericRetType = replaceTVWithGeneric(into.retType) - val genericParams = into.params.map(p => (replaceTVWithGeneric(p._1), p._2)) + def substType(t: Type) = constraints.map(_ match { + case EqualsDot(t1, t2) => if(t.equals(t1)) t2 else null + case _ => null + }).find(_ != null).getOrElse(t) + + val genericRetType = substType(replaceTVWithGeneric(into.retType)) + val genericParams = into.params.map(p => (substType(replaceTVWithGeneric(p._1)), p._2)) val constraintsForMethod = getLinkedCons(Set(genericRetType) ++ genericParams.map(_._1), constraints) + .filter(_ match { + case LessDot(GenericType(_), RefType(_,_)) => true + case _ => false + }) Method(into.genericParams ++ constraintsForMethod, genericRetType, into.name, genericParams, into.retExpr) } private def replaceTVWithGeneric(in: UnifyConstraint, genericNames: Set[String]): Constraint= in match { diff --git a/src/main/scala/hb/dhbw/Main.scala b/src/main/scala/hb/dhbw/Main.scala index 6439044..18b010c 100644 --- a/src/main/scala/hb/dhbw/Main.scala +++ b/src/main/scala/hb/dhbw/Main.scala @@ -36,23 +36,44 @@ object Main { def update(str: String): Unit = { val target = document.querySelector("#unify-output") - target.innerHTML = FJTypeinference.typeinference(str).fold( + val tiResult = FJTypeinference.typeinference(str) + target.innerHTML = tiResult.fold( (error) => error, - (result) => hljs.highlightAuto(prettyPrintHTML(result)).value + (result) => prettyPrintHTML(result._1) ) val astOutput = document.querySelector("#ast-output") - astOutput.innerHTML = Parser.parse(str).map( parseTree => - hljs.highlightAuto(prettyPrintAST(ASTBuilder.fromParseTree(parseTree))).value - ).merge + astOutput.innerHTML = tiResult.fold( + (error) => Parser.parse(str).map( parseTree => + hljs.highlightAuto(prettyPrintAST(ASTBuilder.fromParseTree(parseTree))).value + ).merge, + (result) => { + hljs.highlightAuto(prettyPrintAST(result._2)).value + } + ) } def prettyPrintAST(ast: List[Class]): String = { + def prettyPrintExpr(expr: Expr): String = expr match { + case LocalVar(x) => x + case FieldVar(e, f) => prettyPrintExpr(e)+"."+f + case MethodCall(e, name, params) => prettyPrintExpr(e)+"."+name+"("+params.map(prettyPrintExpr(_)).mkString(", ")+")" + case Constructor(className, params) => "new "+className+"(" + params.map(prettyPrintExpr(_)).mkString(", ") +")" + } + def prettyPrintType(l: Type): String = l match { + case RefType(name, List()) => name + case RefType(name, params) => name + "<" + params.map(prettyPrintType(_)).mkString(", ") + ">" + case GenericType(name) => name + } + def prettyPrintCons(constraint: Constraint)= constraint match{ + case LessDot(l, r) => prettyPrintType(l) + " extends " + prettyPrintType(r) + } ast.map(cl => { "class " + cl.name + "{\n" + cl.methods.map(m => { - " "+m.retType +" "+ m.name +"(" + ") {\n"+ - " return " + "TODO" + ";\n" + + " "+m.genericParams.map(prettyPrintCons(_)).mkString(", ") + " " + + prettyPrintType(m.retType) +" "+ m.name +"(" + ") {\n"+ + " return " + prettyPrintExpr(m.retExpr) + ";\n" + " }" }).mkString("\n") + "\n}" }).mkString("\n") diff --git a/src/test/scala/IntegrationTest.scala b/src/test/scala/IntegrationTest.scala index 0acbe3f..5830776 100644 --- a/src/test/scala/IntegrationTest.scala +++ b/src/test/scala/IntegrationTest.scala @@ -1,4 +1,4 @@ -import hb.dhbw.{FJTypeinference, Main} +import hb.dhbw.{ASTBuilder, FJTypeinference, InsertTypes, Main, Parser} import org.scalatest.FunSuite class IntegrationTest extends FunSuite { @@ -22,6 +22,7 @@ class IntegrationTest extends FunSuite { val result = FJTypeinference.typeinference("class List extends Object{\n add(a){\n return this;\n}\n}") println(result) } + /* test("PaperExample"){ val result = FJTypeinference.typeinference("class List extends Object{\n add( a){\n return this;\n}\n}\nclass Test extends Object{\nm(a){ return a.add(this);}\n}") println(result.map(Main.prettyPrint(_))) @@ -65,9 +66,12 @@ class IntegrationTest extends FunSuite { println(result.map(Main.prettyPrint(_))) } + + */ test("list.add") { val input = "class List extends Object{\nA f;\n add( a){\n return new List(a);\n}\n}\nclass Test extends Object{\n\nm(a){return a.add(this);}\n}" val result = FJTypeinference.typeinference(input ) - println(result.map(Main.prettyPrint(_))) + println(result.map(it => Main.prettyPrint(it._1))) + } }