Output typed classes. Filter constraints before inserting them as method generics

This commit is contained in:
Andreas Stadelmeier 2021-11-17 06:39:26 +01:00
parent 0c59de6f63
commit 39c9adb794
5 changed files with 54 additions and 15 deletions

View File

@ -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;
}

View File

@ -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))
}
}

View File

@ -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 {

View File

@ -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")

View File

@ -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<A extends Object> extends Object{\n add(a){\n return this;\n}\n}")
println(result)
}
/*
test("PaperExample"){
val result = FJTypeinference.typeinference("class List<A extends Object> 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<A extends Object> 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)))
}
}