mirror of
https://github.com/enso-org/enso.git
synced 2024-09-17 16:17:25 +03:00
Polyglot Import Renaming (#1179)
This commit is contained in:
parent
3d88e7f227
commit
3eee990429
@ -97,10 +97,12 @@ object AstToIr {
|
||||
val imports = presentBlocks.collect {
|
||||
case AST.Import.any(list) => translateImport(list)
|
||||
case AST.JavaImport.any(imp) =>
|
||||
val pkg = imp.path.init.map(_.name)
|
||||
val cls = imp.path.last.name
|
||||
val pkg = imp.path.init.map(_.name)
|
||||
val cls = imp.path.last.name
|
||||
val rename = imp.rename.map(_.name)
|
||||
Module.Scope.Import.Polyglot(
|
||||
Module.Scope.Import.Polyglot.Java(pkg.mkString("."), cls),
|
||||
rename,
|
||||
getIdentifiedLocation(imp)
|
||||
)
|
||||
}
|
||||
|
@ -157,11 +157,10 @@ class IrToTruffle(
|
||||
|
||||
// Register the imports in scope
|
||||
imports.foreach {
|
||||
case Import.Polyglot(Import.Polyglot.Java(pkg, cls), _, _, _) =>
|
||||
val fullName = s"$pkg.$cls"
|
||||
case poly @ Import.Polyglot(i: Import.Polyglot.Java, _, _, _, _) =>
|
||||
this.moduleScope.registerPolyglotSymbol(
|
||||
cls,
|
||||
context.getEnvironment.lookupHostSymbol(fullName)
|
||||
poly.getVisibleName,
|
||||
context.getEnvironment.lookupHostSymbol(i.getJavaName)
|
||||
)
|
||||
case i: Import.Module =>
|
||||
this.moduleScope.addImport(
|
||||
|
@ -718,6 +718,12 @@ object IR {
|
||||
sealed trait Entity {
|
||||
val langName: String
|
||||
|
||||
/** Returns the name this object is visible as from Enso code.
|
||||
*
|
||||
* @return the visible name of this object
|
||||
*/
|
||||
def getVisibleName: String
|
||||
|
||||
def showCode(indent: Int = 0): String
|
||||
}
|
||||
|
||||
@ -731,6 +737,14 @@ object IR {
|
||||
extends Entity {
|
||||
val langName = "java"
|
||||
|
||||
override def getVisibleName: String = className
|
||||
|
||||
/** Returns the fully qualified Java name of this object.
|
||||
*
|
||||
* @return the Java-side name of the imported entity
|
||||
*/
|
||||
def getJavaName: String = s"$packageName.$className"
|
||||
|
||||
override def showCode(indent: Int): String =
|
||||
s"$packageName.$className"
|
||||
}
|
||||
@ -739,12 +753,15 @@ object IR {
|
||||
/** An import of a polyglot class.
|
||||
*
|
||||
* @param entity language-specific information on the imported entity
|
||||
* @param rename the name this object should be visible under in the
|
||||
* importing scope
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
*/
|
||||
sealed case class Polyglot(
|
||||
entity: Polyglot.Entity,
|
||||
rename: Option[String],
|
||||
override val location: Option[IdentifiedLocation],
|
||||
override val passData: MetadataStorage = MetadataStorage(),
|
||||
override val diagnostics: DiagnosticStorage = DiagnosticStorage()
|
||||
@ -755,6 +772,8 @@ object IR {
|
||||
/** Creates a copy of `this`.
|
||||
*
|
||||
* @param entity language-specific information on the imported entity
|
||||
* @param rename the name this object should be visible under in the
|
||||
* importing scope
|
||||
* @param location the source location that the node corresponds to
|
||||
* @param passData the pass metadata associated with this node
|
||||
* @param diagnostics compiler diagnostics for this node
|
||||
@ -763,13 +782,14 @@ object IR {
|
||||
*/
|
||||
def copy(
|
||||
entity: Polyglot.Entity = entity,
|
||||
rename: Option[String] = rename,
|
||||
location: Option[IdentifiedLocation] = location,
|
||||
passData: MetadataStorage = passData,
|
||||
diagnostics: DiagnosticStorage = diagnostics,
|
||||
id: Identifier = id
|
||||
): Polyglot = {
|
||||
val res =
|
||||
Polyglot(entity, location, passData, diagnostics)
|
||||
Polyglot(entity, rename, location, passData, diagnostics)
|
||||
res.id = id
|
||||
res
|
||||
}
|
||||
@ -795,10 +815,17 @@ object IR {
|
||||
override def mapExpressions(fn: Expression => Expression): Polyglot =
|
||||
this
|
||||
|
||||
/** Returns the name this object is visible as from Enso code.
|
||||
*
|
||||
* @return the visible name of this object
|
||||
*/
|
||||
def getVisibleName: String = rename.getOrElse(entity.getVisibleName)
|
||||
|
||||
override def toString: String =
|
||||
s"""
|
||||
|IR.Module.Scope.Import.Polyglot(
|
||||
|entity = $entity,
|
||||
|rename = $rename,
|
||||
|location = $location,
|
||||
|passData = ${this.showPassData},
|
||||
|diagnostics = $diagnostics,
|
||||
@ -809,7 +836,8 @@ object IR {
|
||||
override def children: List[IR] = List()
|
||||
|
||||
override def showCode(indent: Int): String = {
|
||||
s"polyglot ${entity.langName} import ${entity.showCode(indent)}"
|
||||
val renamePart = rename.map(name => s"as $name").getOrElse("")
|
||||
s"polyglot ${entity.langName} import ${entity.showCode(indent)} $renamePart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package org.enso.compiler.pass.analyse
|
||||
|
||||
import org.enso.compiler.context.{InlineContext, ModuleContext}
|
||||
import org.enso.compiler.core.IR
|
||||
import org.enso.compiler.core.IR.Module.Scope.Import.Polyglot
|
||||
import org.enso.compiler.core.ir.MetadataStorage.ToPair
|
||||
import org.enso.compiler.data.BindingsMap
|
||||
import org.enso.compiler.pass.IRPass
|
||||
@ -51,10 +50,7 @@ case object BindingAnalysis extends IRPass {
|
||||
}
|
||||
val importedPolyglot = ir.imports.collect {
|
||||
case poly: IR.Module.Scope.Import.Polyglot =>
|
||||
val sym = poly.entity match {
|
||||
case Polyglot.Java(_, className) => className
|
||||
}
|
||||
BindingsMap.PolyglotSymbol(sym)
|
||||
BindingsMap.PolyglotSymbol(poly.getVisibleName)
|
||||
}
|
||||
val moduleMethods = ir.bindings
|
||||
.collect {
|
||||
|
@ -51,6 +51,7 @@ class BindingAnalysisTest extends CompilerTest {
|
||||
val ir =
|
||||
"""
|
||||
|polyglot java import foo.bar.baz.MyClass
|
||||
|polyglot java import foo.bar.baz.OtherClass as Renamed_Class
|
||||
|
|
||||
|type Foo a b c
|
||||
|type Bar
|
||||
@ -66,7 +67,7 @@ class BindingAnalysisTest extends CompilerTest {
|
||||
ir.getMetadata(BindingAnalysis) shouldEqual Some(
|
||||
BindingsMap(
|
||||
List(Cons("Foo", 3), Cons("Bar", 0), Cons("Baz", 2)),
|
||||
List(PolyglotSymbol("MyClass")),
|
||||
List(PolyglotSymbol("MyClass"), PolyglotSymbol("Renamed_Class")),
|
||||
List(ModuleMethod("foo")),
|
||||
ctx.module
|
||||
)
|
||||
|
@ -353,8 +353,11 @@ object Shape extends ShapeImplicit {
|
||||
isAll: Boolean,
|
||||
onlyNames: Option[List1[AST.Ident]],
|
||||
hidingNames: Option[List1[AST.Ident]]
|
||||
) extends SpacelessAST[T]
|
||||
final case class JavaImport[T](path: List1[AST.Ident]) extends SpacelessAST[T]
|
||||
) extends SpacelessAST[T]
|
||||
final case class JavaImport[T](
|
||||
path: List1[AST.Ident],
|
||||
rename: Option[AST.Ident.Cons]
|
||||
) extends SpacelessAST[T]
|
||||
final case class Mixfix[T](name: List1[AST.Ident], args: List1[T])
|
||||
extends SpacelessAST[T]
|
||||
final case class Group[T](body: Option[T]) extends SpacelessAST[T]
|
||||
@ -2422,7 +2425,8 @@ object AST {
|
||||
type JavaImport = ASTOf[Shape.JavaImport]
|
||||
|
||||
object JavaImport {
|
||||
def apply(path: List1[Ident]): JavaImport = Shape.JavaImport[AST](path)
|
||||
def apply(path: List1[Ident], rename: Option[Ident.Cons]): JavaImport =
|
||||
Shape.JavaImport[AST](path, rename)
|
||||
def unapply(t: AST): Option[List1[Ident]] =
|
||||
Unapply[JavaImport].run(t => t.path)(t)
|
||||
val any = UnapplyByType[JavaImport]
|
||||
|
@ -98,21 +98,30 @@ object Builtin {
|
||||
val polyglotJavaImport = {
|
||||
val javaQualName =
|
||||
Pattern.SepList(Pattern.Cons().or(Pattern.Var()), AST.Opr("."))
|
||||
val rename = Var("as") :: Pattern.Cons()
|
||||
Definition(
|
||||
Var("polyglot") -> Pattern.fromAST(Var("java")),
|
||||
Var("import") -> javaQualName
|
||||
Var("import") -> (javaQualName :: rename.opt)
|
||||
) { ctx =>
|
||||
ctx.body match {
|
||||
case List(_, segments) =>
|
||||
case List(_, nameAndRename) =>
|
||||
val (nameMatch, renameMatch) =
|
||||
nameAndRename.body.asInstanceOf[Match.Seq[Shifted[AST]]].elem
|
||||
val nonDot: List[AST.Ident] =
|
||||
segments.body.toStream.map(_.wrapped).collect {
|
||||
nameMatch.toStream.map(_.wrapped).collect {
|
||||
case AST.Ident.Var.any(v) => v: AST.Ident
|
||||
case AST.Ident.Cons.any(c) => c: AST.Ident
|
||||
}
|
||||
val rename: Option[AST.Ident.Cons] = {
|
||||
renameMatch.toStream.map(_.wrapped).collectFirst {
|
||||
case AST.Ident.Cons.any(n) => n
|
||||
}
|
||||
}
|
||||
// The optional unwrap is safe by construction - the pattern
|
||||
// guarantees at least one Var or Cons in the match result.
|
||||
AST.JavaImport(
|
||||
List1.fromListOption(nonDot).getOrElse(internalError)
|
||||
List1.fromListOption(nonDot).getOrElse(internalError),
|
||||
rename
|
||||
)
|
||||
case _ => internalError
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ polyglot java import java.lang.Integer
|
||||
polyglot java import java.lang.Float
|
||||
polyglot java import java.lang.String
|
||||
polyglot java import java.util.ArrayList
|
||||
polyglot java import java.lang.StringBuilder as Java_String_Builder
|
||||
|
||||
spec = describe "Java FFI" <|
|
||||
it "should call methods imported from Java" <|
|
||||
@ -22,4 +23,9 @@ spec = describe "Java FFI" <|
|
||||
(Integer.sum [1, 2] + 3) . should_equal 6
|
||||
it "should auto-convert strings across the polyglot boundary" <|
|
||||
(String.format ["%s bar %s", "baz", "quux"] + " foo").should_equal "baz bar quux foo"
|
||||
|
||||
it "should support Java import renaming" <|
|
||||
builder = Java_String_Builder.new [].to_array
|
||||
builder.append ["foo"]
|
||||
builder.append ["bar"]
|
||||
str = builder.toString []
|
||||
str.should_equal "foobar"
|
||||
|
Loading…
Reference in New Issue
Block a user