New Import Syntax (#1070)

This commit is contained in:
Marcin Kostrzewa 2020-08-07 15:42:24 +02:00 committed by GitHub
parent 1f8a4b802f
commit b2fbf1a848
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 106 additions and 71 deletions

View File

@ -219,8 +219,7 @@ object AstToIr {
)
case _ => Error.Syntax(typed, Error.Syntax.InvalidStandaloneSignature)
}
case _ =>
throw new UnhandledEntity(inputAst, "translateModuleSymbol")
case _ => Error.Syntax(inputAst, Error.Syntax.UnexpectedExpression)
}
}

View File

@ -510,15 +510,19 @@ object IR {
).flatten
override def showCode(indent: Int): String = {
val renameCode = rename.map(n => s" as $n").getOrElse("")
val allCode = if (isAll) " all" else ""
val onlyPart = onlyNames
.map(names => s" only ${names.mkString(" ")}")
.getOrElse("")
val hidingPart = hiddenNames
.map(names => s" hiding ${names.mkString(" ")}")
.getOrElse("")
s"import ${name.name}$renameCode$allCode$onlyPart$hidingPart"
val renameCode = rename.map(n => s" as ${n.name}").getOrElse("")
if (isAll) {
val onlyPart = onlyNames
.map(names => " " + names.map(_.name).mkString(", "))
.getOrElse("")
val hidingPart = hiddenNames
.map(names => s" hiding ${names.map(_.name).mkString(", ")}")
.getOrElse("")
val all = if (onlyNames.isDefined) "" else " all"
s"from ${name.name}$renameCode import$onlyPart$all$hidingPart"
} else {
s"import ${name.name}$renameCode"
}
}
/**

View File

@ -1,4 +1,4 @@
import TestNonImportedOverloads.Util all
from TestNonImportedOverloads.Util import all
X.method = 10

View File

@ -1,3 +1,3 @@
import TestSimpleImports.Atom all
from TestSimpleImports.Atom import all
Main.main = (X 1).method

View File

@ -1,3 +1,3 @@
import Test_Hiding_Error.Atom all hiding X
from Test_Hiding_Error.Atom import all hiding X
Main.main = (X 1).method

View File

@ -1,3 +1,3 @@
import Test_Hiding_Success.Atom all hiding Y
from Test_Hiding_Success.Atom import all hiding Y
Main.main = (X 1).method

View File

@ -786,6 +786,23 @@ class AstToIrTest extends CompilerTest with Inside {
}
}
"properly support different kinds of imports" in {
val imports = List(
"import Foo.Bar as Baz",
"import Foo.Bar",
"from Foo.Bar import Baz",
"from Foo.Bar import Baz, Spam",
"from Foo.Bar import all",
"from Foo.Bar as Eggs import all hiding Spam",
"from Foo.Bar import all hiding Spam, Eggs"
)
imports
.mkString("\n")
.toIrModule
.imports
.map(_.showCode()) shouldEqual imports
}
"AST translation of erroneous constructs" should {
"result in a syntax error when encountering " +
"unbalanced parentheses in application" in {

View File

@ -267,64 +267,78 @@ object Builtin {
case _ => internalError
}
}
val (qualifiedImport, itemsImport) = {
val qualNamePat = Pattern.SepList(Pattern.Cons(), Opr("."))
val rename = Var("as") :: Pattern.Cons()
val `import` = {
val qualNamePat = Pattern.SepList(Pattern.Cons(), Opr("."))
val rename = Var("as") :: Pattern.Cons()
val all: Pattern = Var("all")
val only: Pattern = Var("only") :: Pattern.Cons().many
val hiding: Pattern = Var("hiding") :: Pattern.Cons().many
Definition(
Var(
"import"
) -> (qualNamePat :: rename.opt :: (all :: (only | hiding).opt).opt)
) { ctx =>
ctx.body match {
case List(s1) =>
val tup1 = s1.body.asInstanceOf[Match.Seq[Shifted[AST]]]
val tup2 = tup1.elem._2.asInstanceOf[Match.Seq[Shifted[AST]]]
val nameMatch = tup1.elem._1
val renameMatch = tup2.elem._1
val elemsMatch = tup2.elem._2
val name: List1[AST.Ident.Cons] =
List1(
nameMatch.toStream
.map(_.wrapped)
.flatMap(AST.Ident.Cons.any.unapply)
).get
val rename: Option[AST.Ident.Cons] =
renameMatch.toStream.map(_.wrapped).collectFirst {
case AST.Ident.Cons.any(n) => n
def extractRename(
matched: Pattern.Match
): (List1[AST.Ident.Cons], Option[AST.Ident.Cons]) = {
val (nameMatch, renameMatch) =
matched.asInstanceOf[Match.Seq[Shifted[AST]]].elem
val name: List1[AST.Ident.Cons] =
List1(
nameMatch.toStream
.map(_.wrapped)
.flatMap(AST.Ident.Cons.any.unapply)
).get
val rename: Option[AST.Ident.Cons] = {
renameMatch.toStream.map(_.wrapped).collectFirst {
case AST.Ident.Cons.any(n) => n
}
}
(name, rename)
}
val itemsImport = {
val all: Pattern = Var("all")
val items = Pattern.SepList(Pattern.Cons(), Opr(","))
val hiding = Var("hiding") :: items
Definition(
Var("from") -> (qualNamePat :: rename.opt),
Var("import") -> ((all :: hiding.opt) | items)
) { ctx =>
ctx.body match {
case List(imp, itemsMatch) =>
val (name, rename) = extractRename(imp.body)
val (hiding, items) = itemsMatch.body match {
case Match.Or(_, Left(hidden)) =>
val hiddenItems = hidden.toStream
.map(_.wrapped)
.flatMap(AST.Ident.Cons.any.unapply)
(List1(hiddenItems), None)
case Match.Or(_, Right(imported)) =>
val importedItems = imported.toStream
.map(_.wrapped)
.flatMap(AST.Ident.Cons.any.unapply)
(None, List1(importedItems))
case _ => internalError
}
val (isAll, only, hiding) = elemsMatch match {
case Match.Or(_, Left(Match.Seq(_, (_, onlyHidingMaybeMatch)))) =>
onlyHidingMaybeMatch match {
case Match.Or(_, Left(maybeHidingMatch)) =>
maybeHidingMatch match {
case Match.Or(_, Left(onlyMatch)) =>
val onlyConses: List[AST.Ident.Cons] =
onlyMatch.toStream
.map(_.wrapped)
.flatMap(AST.Ident.Cons.any.unapply)
(true, List1(onlyConses), None)
case Match.Or(_, Right(hidingMatch)) =>
val hidingConses: List[AST.Ident.Cons] =
hidingMatch.toStream
.map(_.wrapped)
.flatMap(AST.Ident.Cons.any.unapply)
(true, None, List1(hidingConses))
case _ => internalError
}
case _ => (true, None, None)
}
case _ => (false, None, None)
}
AST.Import(name, rename, isAll, only, hiding)
case _ => internalError
AST.Import(name, rename, true, items, hiding)
case _ => internalError
}
}
}
}
val qualifiedImport = {
Definition(
Var(
"import"
) -> (qualNamePat :: rename.opt)
) { ctx =>
ctx.body match {
case List(s1) =>
val (name, rename) = extractRename(s1.body)
AST.Import(name, rename, false, None, None)
case _ => internalError
}
}
}
(qualifiedImport, itemsImport)
}
val privateDef = {
Definition(Var("private") -> Pattern.Expr()) { ctx =>
ctx.body match {
@ -373,7 +387,8 @@ object Builtin {
if_then,
if_then_else,
polyglotJavaImport,
`import`,
itemsImport,
qualifiedImport,
defn,
arrow,
foreign,

View File

@ -1,3 +1,3 @@
import Test.Import_Loop.B all only My_Type
from Test.Import_Loop.B import My_Type
foo = My_Type.bar 10

View File

@ -1,4 +1,4 @@
import Test.Names.Definitions all only My_Type Another_Constant
from Test.Names.Definitions import My_Type, Another_Constant
import Base.Test
Definitions.Foo.my_method = case this of