Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pr-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
env:
# Set LANG=C to simulate least-common-denominator target deployment environments:
LANG: C
SCALANATIVE_THREAD_STACK_SIZE: 10m
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: to prevent stackoverflow in native tests scala-native/scala-native#4253

name: Sjsonnet build for ${{ matrix.lang }} on JDK ${{ matrix.java }}
steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ out/
.bloop
/project/.bloop
/project/project/
/project/metals.sbt
/project/metals.sbt
2 changes: 1 addition & 1 deletion bench/src/main/scala/sjsonnet/ParserBenchmark.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ParserBenchmark {
def main(bh: Blackhole): Unit = {
bh.consume(allFiles.foreach { case (p, s) =>
val res = fastparse.parse(s, new Parser(p, true, HashMap.empty, HashMap.empty).document(_))
bh.consume(res.asInstanceOf[Success[_]])
bh.consume(res.asInstanceOf[Success[?]])
})
}
}
4 changes: 2 additions & 2 deletions bench/src/main/scala/sjsonnet/ProfilingEvaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ class ProfilingEvaluator(resolver: CachedResolver,
case a: Array[Expr.Bind] => a.iterator.flatMap(getChildren).toSeq
case a: Array[Expr.Member.Field] => a.iterator.flatMap(getChildren).toSeq
case a: Array[Expr.Member.AssertStmt] => a.iterator.flatMap(getChildren).toSeq
case s: Seq[_] => s.collect { case e: Expr => e }
case s: Some[_] => s.collect { case e: Expr => e }
case s: Seq[?] => s.collect { case e: Expr => e }
case s: Some[?] => s.collect { case e: Expr => e }
case _ => Nil
}.filter(_ != null).toSeq
case _ => Nil
Expand Down
20 changes: 17 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
val sjsonnetVersion = "0.4.15.1"

scalaVersion in Global := "2.13.16"
val scala213 = "2.13.16"
val scala3 = "3.3.5"

cancelable in Global := true

val scala3Options = Seq()
val scala2Options = Seq("-opt:l:inline", "-opt-inline-from:sjsonnet.*,sjsonnet.**", "-Xsource:3")

lazy val commonSettings = Seq(
scalaVersion := scala3,
crossScalaVersions := Seq(scala213, scala3),
scalacOptions ++= {CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) => scala3Options
case _ => scala2Options
}}
)

lazy val main = (project in file("sjsonnet"))
.settings(commonSettings: _*)
.settings(
Compile / scalacOptions ++= Seq("-opt:l:inline", "-opt-inline-from:sjsonnet.*,sjsonnet.**"),
Test / fork := true,
Test / javaOptions += "-Xss100m",
Test / baseDirectory := (ThisBuild / baseDirectory).value,
Expand Down Expand Up @@ -56,6 +69,7 @@ lazy val main = (project in file("sjsonnet"))
lazy val bench = (project in file("bench"))
.dependsOn(main % "compile->test")
.enablePlugins(JmhPlugin)
.settings(commonSettings: _*)
.settings(
run / fork := true,
)
)
4 changes: 2 additions & 2 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.util.Base64

val sjsonnetVersion = "0.4.15.1"

val scalaVersions = Seq("2.12.20", "2.13.16")
val scalaVersions = Seq("2.12.20", "2.13.16", "3.3.5")

trait SjsonnetCrossModule extends CrossScalaModule with PublishModule {
def crossValue: String
Expand Down Expand Up @@ -153,7 +153,7 @@ object sjsonnet extends Module {
ivy"org.yaml:snakeyaml::2.0",
ivy"com.google.re2j:re2j:1.8",
)
def scalacOptions = Seq("-opt:l:inline", "-opt-inline-from:sjsonnet.*,sjsonnet.**")
def scalacOptions = Seq("-opt:l:inline", "-opt-inline-from:sjsonnet.*,sjsonnet.**", "-Xsource:3")

object test extends ScalaTests with CrossTests {
def forkArgs = Seq("-Xss100m")
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.10.0
sbt.version=1.10.11
3 changes: 1 addition & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
//addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.7")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.3")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3")
7 changes: 5 additions & 2 deletions sjsonnet/server/src/sjsonnet/SjsonnetServerMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@ class Server[T](lockBase: String,

@volatile var done = false
@volatile var idle = false
val t = new Thread(() =>
try {
val t = new Thread(new Runnable{
override def run(): Unit = {
try {
val (result, newStateCache) = sm.main0(
args,
sm.stateCache,
Expand All @@ -173,6 +174,8 @@ class Server[T](lockBase: String,
} finally{
done = true
idle = true
}
}
},
"SjsonnetServerActionRunner"
)
Expand Down
10 changes: 5 additions & 5 deletions sjsonnet/src-jvm-native/sjsonnet/CachedResolvedFile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class CachedResolvedFile(val resolvedImportPath: OsPath, memoryLimitBytes: Long,
// Assert that the file is less than limit
assert(jFile.length() <= memoryLimitBytes, s"Resolved import path $resolvedImportPath is too large: ${jFile.length()} bytes > ${memoryLimitBytes} bytes")

private[this] val resolvedImportContent: ResolvedFile = {
private val resolvedImportContent: ResolvedFile = {
// TODO: Support caching binary data
if (jFile.length() > cacheThresholdBytes) {
// If the file is too large, then we will just read it from disk
Expand All @@ -38,11 +38,11 @@ class CachedResolvedFile(val resolvedImportPath: OsPath, memoryLimitBytes: Long,
}
}

private[this] def readString(jFile: File): String = {
private def readString(jFile: File): String = {
new String(Files.readAllBytes(jFile.toPath), StandardCharsets.UTF_8);
}

private[this] def readRawBytes(jFile: File): Array[Byte] = Files.readAllBytes(jFile.toPath)
private def readRawBytes(jFile: File): Array[Byte] = Files.readAllBytes(jFile.toPath)

/**
* A method that will return a reader for the resolved import. If the import is too large, then this will return
Expand All @@ -67,12 +67,12 @@ class CachedResolvedFile(val resolvedImportPath: OsPath, memoryLimitBytes: Long,
}


override lazy val contentHash: String = {
override def contentHash(): String = {
if (resolvedImportContent == null) {
// If the file is too large, then we will just read it from disk
Platform.hashFile(jFile)
} else {
resolvedImportContent.contentHash
resolvedImportContent.contentHash()
}
}

Expand Down
2 changes: 1 addition & 1 deletion sjsonnet/src-jvm-native/sjsonnet/OsPath.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ case class OsPath(p: os.Path) extends Path{
":" + Util.prettyIndex(lineStarts, offset)
}

p.relativeTo(os.pwd) + offsetStr
p.relativeTo(os.pwd).toString + offsetStr
}
}
12 changes: 6 additions & 6 deletions sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ object SjsonnetMain {
private def writeFile(config: Config, f: os.Path, contents: String): Either[String, Unit] =
handleWriteFile(os.write.over(f, contents, createFolders = config.createDirs.value))

private def writeToFile(config: Config, wd: os.Path)(materialize: Writer => Either[String, _]): Either[String, String] = {
private def writeToFile(config: Config, wd: os.Path)(materialize: Writer => Either[String, ?]): Either[String, String] = {
config.outputFile match{
case None =>
val sw = new StringWriter
Expand Down Expand Up @@ -199,12 +199,12 @@ object SjsonnetMain {
importer = importer match{
case Some(i) => new Importer {
def resolve(docBase: Path, importName: String): Option[Path] =
i(docBase, importName).map(OsPath)
i(docBase, importName).map(OsPath.apply)
def read(path: Path, binaryData: Boolean): Option[ResolvedFile] = {
readPath(path, binaryData)
}
}
case None => resolveImport(config.jpaths.map(os.Path(_, wd)).map(OsPath), allowedInputs)
case None => resolveImport(config.jpaths.map(os.Path(_, wd)).map(OsPath.apply), allowedInputs)
},
parseCache,
settings = new Settings(
Expand All @@ -217,7 +217,7 @@ object SjsonnetMain {
strictSetOperations = config.strictSetOperations.value,
throwErrorForInvalidSets = config.throwErrorForInvalidSets.value,
),
storePos = (position: Position) => if (config.yamlDebug.value) currentPos = position else null,
storePos = (position: Position) => if (config.yamlDebug.value) currentPos = position else (),
warnLogger = warnLogger,
std = std
)
Expand All @@ -242,7 +242,7 @@ object SjsonnetMain {
Right(writer.toString)
}
}
relPath = os.FilePath(multiPath) / os.RelPath(f)
relPath = (os.FilePath(multiPath) / os.RelPath(f)).asInstanceOf[os.FilePath]
_ <- writeFile(config, relPath.resolveFrom(wd), rendered)
} yield relPath
}
Expand Down Expand Up @@ -295,7 +295,7 @@ object SjsonnetMain {
* of caching on top of the underlying file system. Small files are read into memory, while large
* files are read from disk.
*/
private[this] def readPath(path: Path, binaryData: Boolean): Option[ResolvedFile] = {
private def readPath(path: Path, binaryData: Boolean): Option[ResolvedFile] = {
val osPath = path.asInstanceOf[OsPath].p
if (os.exists(osPath) && os.isFile(osPath)) {
Some(new CachedResolvedFile(path.asInstanceOf[OsPath], memoryLimitBytes = Int.MaxValue.toLong, binaryData = binaryData))
Expand Down
6 changes: 3 additions & 3 deletions sjsonnet/src-jvm/sjsonnet/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ object Platform {
yaml.size match {
case 0 => "{}"
case 1 => yaml.head match {
case m: java.util.Map[_, _] => new JSONObject(m).toString()
case l: java.util.List[_] => new JSONArray(l).toString()
case m: java.util.Map[?, ?] => new JSONObject(m).toString()
case l: java.util.List[?] => new JSONArray(l).toString()
case _ => new JSONArray(yaml.asJava).get(0).toString
}
case _ => new JSONArray(yaml.asJava).toString()
Expand Down Expand Up @@ -89,7 +89,7 @@ object Platform {
// Same as go-jsonnet https://github.com/google/go-jsonnet/blob/2b4d7535f540f128e38830492e509a550eb86d57/builtins.go#L959
def sha3(s: String): String = computeHash("SHA3-512", s)

private[this] val xxHashFactory = XXHashFactory.fastestInstance()
private val xxHashFactory = XXHashFactory.fastestInstance()

def hashFile(file: File): String = {
val buffer = new Array[Byte](8192)
Expand Down
6 changes: 3 additions & 3 deletions sjsonnet/src/sjsonnet/BaseCharRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output]

override def visitJsonableObject(length: Int, index: Int): ObjVisitor[T,T] = visitObject(length, index)

protected[this] val elemBuilder = new upickle.core.CharBuilder
protected val elemBuilder = new upickle.core.CharBuilder
def flushCharBuilder(): Unit = {
elemBuilder.writeOutToIfLongerThan(out, if (depth == 0) 0 else 1000)
}

protected[this] var depth: Int = 0
protected var depth: Int = 0


protected[this] var commaBuffered = false
protected var commaBuffered = false

def flushBuffer(): Unit = {
if (commaBuffered) {
Expand Down
33 changes: 17 additions & 16 deletions sjsonnet/src/sjsonnet/BaseRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,28 @@ class BaseRenderer[T <: java.io.Writer]
indent: Int = -1,
escapeUnicode: Boolean = false) extends ujson.JsVisitor[T, T]{

override def visitJsonableObject(length: Int, index: Int): ObjVisitor[T,T] = visitObject(length, index)

var depth: Int = 0
val colonSnippet = if (indent == -1) ":" else ": "
val colonSnippet: String = if (indent == -1) ":" else ": "

var commaBuffered = false

def flushBuffer() = {
def flushBuffer(): Unit = {
if (commaBuffered) {
commaBuffered = false
out.append(',')
renderIndent()
}
}
def visitArray(length: Int, index: Int) = new ArrVisitor[T, T] {

override def visitJsonableObject(length: Int, index: Int): ObjVisitor[T,T] = visitObject(length, index)

def visitArray(length: Int, index: Int): upickle.core.ArrVisitor[T,T]{def subVisitor: sjsonnet.BaseRenderer[T]} = new ArrVisitor[T, T] {
flushBuffer()
out.append('[')

depth += 1
renderIndent()
def subVisitor = BaseRenderer.this
def subVisitor: sjsonnet.BaseRenderer[T] = BaseRenderer.this
def visitValue(v: T, index: Int): Unit = {
flushBuffer()
commaBuffered = true
Expand All @@ -50,13 +51,13 @@ class BaseRenderer[T <: java.io.Writer]
}
}

def visitObject(length: Int, index: Int) = new ObjVisitor[T, T] {
def visitObject(length: Int, index: Int): ObjVisitor[T,T] = new ObjVisitor[T, T] {
flushBuffer()
out.append('{')
depth += 1
renderIndent()
def subVisitor = BaseRenderer.this
def visitKey(index: Int) = BaseRenderer.this
def subVisitor: sjsonnet.BaseRenderer[T] = BaseRenderer.this
def visitKey(index: Int): sjsonnet.BaseRenderer[T]= BaseRenderer.this
def visitKeyValue(s: Any): Unit = out.append(colonSnippet)
def visitValue(v: T, index: Int): Unit = {
commaBuffered = true
Expand All @@ -70,31 +71,31 @@ class BaseRenderer[T <: java.io.Writer]
}
}

def visitNull(index: Int) = {
def visitNull(index: Int): T = {
flushBuffer()
out.append("null")
out
}

def visitFalse(index: Int) = {
def visitFalse(index: Int): T = {
flushBuffer()
out.append("false")
out
}

def visitTrue(index: Int) = {
def visitTrue(index: Int): T = {
flushBuffer()
out.append("true")
out
}

def visitFloat64StringParts(s: CharSequence, decIndex: Int, expIndex: Int, index: Int) = {
def visitFloat64StringParts(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): T = {
flushBuffer()
out.append(s)
out
}

override def visitFloat64(d: Double, index: Int) = {
override def visitFloat64(d: Double, index: Int): T = {
d match{
case Double.PositiveInfinity => visitString("Infinity", -1)
case Double.NegativeInfinity => visitString("-Infinity", -1)
Expand All @@ -109,15 +110,15 @@ class BaseRenderer[T <: java.io.Writer]
out
}

def visitString(s: CharSequence, index: Int) = {
def visitString(s: CharSequence, index: Int): T = {
flushBuffer()
if (s == null) out.append("null")
else BaseRenderer.escape(out, s, escapeUnicode)

out
}

final def renderIndent() = {
final def renderIndent(): Unit = {
if (indent == -1) ()
else {
out.append('\n')
Expand Down
4 changes: 2 additions & 2 deletions sjsonnet/src/sjsonnet/DecimalFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package sjsonnet
*/
object DecimalFormat {

def trailingZeroes(n: Long) = {
def trailingZeroes(n: Long): Int = {
var count = 0
var current = n
var done = false
Expand All @@ -31,7 +31,7 @@ object DecimalFormat {
val n = (n0 / Math.pow(10, trailingZeroes(n0))).toInt
assert(n == math.abs(n))
val nWidth = if (n == 0) 1 else Math.log10(n).toInt + 1
(n + "0" * (minWidth - nWidth)).take(maxWidth)
("" + n + "0" * (minWidth - nWidth)).take(maxWidth)
}
}
def format(fracLengthOpt: Option[(Int, Int)], expLengthOpt: Option[Int], number: Double): String = {
Expand Down
Loading