Skip to content

Commit 40f25ec

Browse files
Temporarily parse using directives with a custom parser
1 parent de4280e commit 40f25ec

File tree

14 files changed

+142
-206
lines changed

14 files changed

+142
-206
lines changed

build.sc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@ class Build(val crossScalaVersion: String)
140140
Deps.scalametaTrees,
141141
Deps.scalaparse,
142142
Deps.shapeless,
143-
Deps.swoval,
144-
Deps.usingDirectives
143+
Deps.swoval
145144
)
146145

147146
private def vcsState = {

examples/utest/MyTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@using lib "com.lihaoyi::utest::0.7.10"
1+
// using "com.lihaoyi::utest::0.7.10"
22

33
import utest._
44

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package scala.build.preprocessing
2+
3+
final case class Directive(
4+
tpe: Directive.Type,
5+
values: Seq[String]
6+
)
7+
8+
object Directive {
9+
sealed abstract class Type(val name: String) extends Product with Serializable
10+
case object Using extends Type("using")
11+
case object Require extends Type("require")
12+
}

modules/build/src/main/scala/scala/build/preprocessing/DirectivesOutputStreamReporter.scala

Lines changed: 0 additions & 37 deletions
This file was deleted.

modules/build/src/main/scala/scala/build/preprocessing/DirectivesProcessor.scala

Lines changed: 0 additions & 104 deletions
This file was deleted.

modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package scala.build.preprocessing
22

3-
import com.virtuslab.using_directives.{Context, UsingDirectivesProcessor}
4-
import com.virtuslab.using_directives.config.Settings
5-
import com.virtuslab.using_directives.custom.model.Path
6-
import com.virtuslab.using_directives.reporter.ConsoleReporter
73
import dependency.AnyDependency
84
import dependency.parser.DependencyParser
95

106
import java.nio.charset.StandardCharsets
117

128
import scala.build.{Inputs, Os, Sources}
139
import scala.build.internal.AmmUtil
14-
import scala.build.options.{BuildOptions, ClassPathOptions}
10+
import scala.build.options.{BuildOptions, ClassPathOptions, ScalaOptions}
1511
import scala.collection.JavaConverters._
1612

1713
case object ScalaPreprocessor extends Preprocessor {
@@ -82,41 +78,44 @@ case object ScalaPreprocessor extends Preprocessor {
8278
}
8379
}
8480

85-
private def processUsing(
86-
content: String,
87-
printablePath: String
88-
): Option[(BuildOptions, String)] = {
89-
90-
val processor = {
91-
val reporter = new DirectivesOutputStreamReporter(System.err) // TODO Get that via a logger
92-
val settings = new Settings
93-
val context = new Context(reporter, settings)
94-
new UsingDirectivesProcessor(context)
95-
}
96-
97-
val contentChars = content.toCharArray
98-
val directives = processor.extract(contentChars)
99-
100-
val updatedOptions = DirectivesProcessor.process(directives.getFlattenedMap.asScala.toMap)
81+
private def directivesBuildOptions(directives: Seq[Directive]): BuildOptions =
82+
directives
83+
.filter(_.tpe == Directive.Using)
84+
.map { dir =>
85+
dir.values match {
86+
case Seq(depStr) if depStr.split(":").count(_.trim.nonEmpty) == 3 =>
87+
DependencyParser.parse(depStr) match {
88+
case Left(err) => sys.error(s"Error parsing dependency '$depStr': $err")
89+
case Right(dep) =>
90+
BuildOptions(
91+
classPathOptions = ClassPathOptions(
92+
extraDependencies = Seq(dep)
93+
)
94+
)
95+
}
96+
case Seq("scala", scalaVer) if scalaVer.nonEmpty =>
97+
BuildOptions(
98+
scalaOptions = ScalaOptions(
99+
scalaVersion = Some(scalaVer)
100+
)
101+
)
102+
case _ =>
103+
sys.error(s"Unrecognized using directive: ${dir.values.mkString(" ")}")
104+
}
105+
}
106+
.foldLeft(BuildOptions())(_ orElse _)
101107

102-
val codeOffset = directives.getCodeOffset()
108+
private def processUsing(content: String, printablePath: String): Option[(BuildOptions, String)] =
109+
TemporaryDirectivesParser.parseDirectives(content).flatMap {
110+
case (directives, updatedContent) =>
111+
// TODO Warn about unrecognized directives
112+
// TODO Report via some diagnostics malformed directives
103113

104-
val updatedContentOpt =
105-
if (codeOffset > 0)
106-
Some {
107-
val headerBytes = contentChars
108-
.iterator
109-
.take(codeOffset)
110-
.map(c => if (c.isControl) c else ' ')
111-
.toArray
112-
val mainBytes = contentChars.drop(codeOffset)
113-
new String(headerBytes ++ mainBytes)
114+
TemporaryDirectivesParser.parseDirectives(content).map {
115+
case (directives, updatedContent) =>
116+
(directivesBuildOptions(directives), updatedContent)
114117
}
115-
else None
116-
117-
if (updatedContentOpt.isEmpty) None
118-
else Some((updatedOptions, updatedContentOpt.getOrElse(content)))
119-
}
118+
}
120119

121120
private def processSpecialImports(
122121
content: String,
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package scala.build.preprocessing
2+
3+
import fastparse._
4+
import fastparse.NoWhitespace.noWhitespaceImplicit
5+
6+
object TemporaryDirectivesParser {
7+
8+
private def directive[_: P] = {
9+
def ws = P(" ".rep(1))
10+
def sc = P(";")
11+
def nl = P(("\r".? ~ "\n").rep(1))
12+
def tpe = {
13+
def usingTpe = P(ws.? ~ ("using" | "@using" | "// using"))
14+
.map(_ => (Directive.Using: Directive.Type))
15+
def requireTpe = P(ws.? ~ ("require" | "@require" | "// require"))
16+
.map(_ => (Directive.Require: Directive.Type))
17+
P(usingTpe | requireTpe)
18+
}
19+
20+
def simpleElem = P(CharPred(c => !c.isWhitespace && c != '"').rep(1).!)
21+
def charInQuote = P(
22+
CharPred(c => c != '"' && c != '\\').! |
23+
P("\\\\").map(_ => "\\") |
24+
P("\\\"").map(_ => "\"")
25+
)
26+
def quotedElem = P("\"" ~ charInQuote.rep ~ "\"").map(_.mkString)
27+
def elem = P(simpleElem | quotedElem)
28+
29+
P(tpe ~ ws ~ elem ~ (ws ~ elem).rep(0) ~ nl.? ~ sc.? ~ nl.?).map {
30+
case (tpe0, firstElem, otherElems) =>
31+
Directive(tpe0, firstElem +: otherElems)
32+
}
33+
}
34+
35+
private def maybeDirective[_: P] = {
36+
// TODO Use some cuts above to also catch malformed directives?
37+
P(directive.?)
38+
}
39+
40+
private def parseDirective(content: String, fromIndex: Int): Option[(Directive, Int)] = {
41+
// TODO Don't create a new String here
42+
val res = parse(content.drop(fromIndex), maybeDirective(_))
43+
res.fold((err, idx, _) => sys.error(err), (dirOpt, idx) => dirOpt.map((_, idx + fromIndex)))
44+
}
45+
46+
def parseDirectives(content: String): Option[(List[Directive], String)] = {
47+
48+
def helper(fromIndex: Int, acc: List[Directive]): (List[Directive], Int) =
49+
parseDirective(content, fromIndex) match {
50+
case None => (acc.reverse, fromIndex)
51+
case Some((dir, newIndex)) => helper(newIndex, dir :: acc)
52+
}
53+
54+
val (directives, codeStartsAt) = helper(0, Nil)
55+
56+
if (codeStartsAt == 0) {
57+
assert(directives.isEmpty)
58+
None
59+
}
60+
else
61+
Some((
62+
directives,
63+
content.take(codeStartsAt).map(c => if (c.isControl) c else ' ') ++
64+
content.drop(codeStartsAt)
65+
))
66+
}
67+
68+
}

modules/build/src/test/scala/scala/build/tests/BuildTests.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ class BuildTests extends munit.FunSuite {
217217
test("dependencies - using") {
218218
val testInputs = TestInputs(
219219
os.rel / "simple.sc" ->
220-
"""@using lib "com.lihaoyi::geny:0.6.5"
220+
"""using "com.lihaoyi::geny:0.6.5"
221221
|import geny.Generator
222222
|val g = Generator("Hel", "lo")
223223
|println(g.mkString)
@@ -252,8 +252,8 @@ class BuildTests extends munit.FunSuite {
252252
test("several dependencies - using") {
253253
val testInputs = TestInputs(
254254
os.rel / "simple.sc" ->
255-
"""@using lib "com.lihaoyi::geny:0.6.5"
256-
|@using lib "com.lihaoyi::pprint:0.6.6"
255+
"""using "com.lihaoyi::geny:0.6.5"
256+
|using "com.lihaoyi::pprint:0.6.6"
257257
|import geny.Generator
258258
|val g = Generator("Hel", "lo")
259259
|pprint.log(g)

modules/build/src/test/scala/scala/build/tests/SourcesTests.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ class SourcesTests extends munit.FunSuite {
4545
test("dependencies in .scala - using") {
4646
val testInputs = TestInputs(
4747
os.rel / "something.scala" ->
48-
"""@using lib "org1:name1:1.1"
49-
|@using lib "org2::name2:2.2"
50-
|@using lib "org3:::name3:3.3"
48+
"""using "org1:name1:1.1"
49+
|using "org2::name2:2.2"
50+
|using "org3:::name3:3.3"
5151
|import scala.collection.mutable
5252
|
5353
|object Something {
@@ -154,9 +154,9 @@ class SourcesTests extends munit.FunSuite {
154154
test("dependencies in .sc - using") {
155155
val testInputs = TestInputs(
156156
os.rel / "something.sc" ->
157-
"""@using lib "org1:name1:1.1"
158-
|@using lib "org2::name2:2.2"
159-
|@using lib "org3:::name3:3.3"
157+
"""using "org1:name1:1.1"
158+
|using "org2::name2:2.2"
159+
|using "org3:::name3:3.3"
160160
|import scala.collection.mutable
161161
|
162162
|def a = 1

modules/build/src/test/scala/scala/build/tests/TestUtil.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object TestUtil {
2121
val generated0 = generated()
2222
assert(
2323
generated0.map(_.toString).toSet == expected.toSet, {
24-
pprint.log(generated0)
24+
pprint.log(generated0.map(_.toString))
2525
pprint.log(expected)
2626
""
2727
}

0 commit comments

Comments
 (0)