Skip to content

Commit

Permalink
Fix "Duplicate Local Variables in Object Scope" (#234)
Browse files Browse the repository at this point in the history
Fixes #178
  • Loading branch information
stephenamar-db authored Dec 12, 2024
1 parent 5149b6e commit 29bcc9a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
6 changes: 5 additions & 1 deletion sjsonnet/src/sjsonnet/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ trait Expr{
val n = getClass.getName
if(n.startsWith("sjsonnet.Expr$")) n.substring(14) else n
}

override def toString: String = s"$exprErrorString@$pos"
}
object Expr{
private final def arrStr(a: Array[_]): String = {
Expand Down Expand Up @@ -165,7 +167,9 @@ object Expr{

trait ObjBody extends Expr
object ObjBody{
case class MemberList(pos: Position, binds: Array[Bind], fields: Array[Member.Field], asserts: Array[Member.AssertStmt]) extends ObjBody
case class MemberList(pos: Position, binds: Array[Bind], fields: Array[Member.Field], asserts: Array[Member.AssertStmt]) extends ObjBody {
override def toString: String = s"MemberList($pos, ${arrStr(binds)}, ${arrStr(fields)}, ${arrStr(asserts)})"
}
case class ObjComp(pos: Position,
preLocals: Array[Bind],
key: Expr,
Expand Down
9 changes: 9 additions & 0 deletions sjsonnet/src/sjsonnet/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,15 @@ class Parser(val currentFile: Path,
case (pos, exprs, None) =>
val binds = {
val b = exprs.iterator.filter(_.isInstanceOf[Expr.Bind]).asInstanceOf[Iterator[Expr.Bind]].toArray
val seen = collection.mutable.Set.empty[String]
var overlap: String = null
b.foreach {
case Expr.Bind(_, n, _, _) =>
if (seen(n)) overlap = n
else seen.add(n)
case _ =>
}
if (overlap != null) Fail.opaque("no duplicate local: " + overlap)
if(b.isEmpty) null else b
}
val fields = exprs.iterator.filter(_.isInstanceOf[Expr.Member.Field]).asInstanceOf[Iterator[Expr.Member.Field]].toArray
Expand Down
15 changes: 14 additions & 1 deletion sjsonnet/test/src/sjsonnet/ParserTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import scala.collection.mutable
import utest._
import Expr._
import fastparse.Parsed
import Val.{True, Num}
import Val.{Num, True}
import sjsonnet.Expr.FieldName.Fixed
object ParserTests extends TestSuite{
def parse(s: String, strictImportSyntax: Boolean = false) = fastparse.parse(s, new Parser(null, strictImportSyntax, mutable.HashMap.empty, mutable.HashMap.empty).document(_)).get.value._1
def parseErr(s: String, strictImportSyntax: Boolean = false) = fastparse.parse(s, new Parser(null, strictImportSyntax, mutable.HashMap.empty, mutable.HashMap.empty).document(_), verboseFailures = true).asInstanceOf[Parsed.Failure].msg
Expand All @@ -26,6 +27,18 @@ object ParserTests extends TestSuite{
test("duplicateFields") {
parseErr("{ a: 1, a: 2 }") ==> """Expected no duplicate field: a:1:14, found "}""""
}
test("localInObj") {
parse("""{
|local x = 1,
|a: x,
|}""".stripMargin).toString ==> (ObjBody.MemberList(pos(2), Array(Bind(pos(8), "x", null, Num(pos(12), 1))),
Array(Member.Field(pos(15), Fixed("a"), false, null, Member.Visibility.Normal, Id(pos(18), "x"))), null)).toString
parseErr("""{
|local x = 1,
|local x = x + 1,
|a: x,
|}""".stripMargin) ==> """Expected no duplicate local: x:5:1, found "}""""
}
test("givenDuplicateFieldsInListComprehension_expectError") {
parseErr("""{ ["bar"]: x for x in [1, 2]}""") ==> """Expected no duplicate field: "bar" :1:29, found "}""""
}
Expand Down

0 comments on commit 29bcc9a

Please sign in to comment.