Skip to content

Commit

Permalink
680 feature return character range for error in messages (#690)
Browse files Browse the repository at this point in the history
Extend the At class to have a start and end position. 

This allows better support for visual editors, by allowing messages to be specify a range of the source text. This change applies this throughout RIDDL. 
* Adjust the At class to have a end `endOffset` field
* Improve URL class, get rid of warnings, add a test case
* Make parsing use two Index values for each production
* Capture both those values in At constructor
* add a errorLoc: At function to definitions to reference the default character rrange for an error
* Adjust all test cases to work
* Upgrade to sbt-ossuminc 0.17.1
  • Loading branch information
reid-spencer authored Nov 16, 2024
1 parent fad24ef commit ff68964
Show file tree
Hide file tree
Showing 69 changed files with 1,605 additions and 1,750 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class UseCaseDiagramTest extends AbstractRunPassTest {
val outputs: PassesOutput = PassesOutput()
val pid = PathIdentifier(At(), Seq("foo"))
val item = Domain(At(), Identifier(At(), "foo"))
val parent = Root(Contents(item))
val parent = Root(At(), Contents(item))
outputs.refMap.add[Domain](pid, parent, item)
val passesResult = PassesResult(PassInput.empty, outputs)
case class TestUseCaseDiagramSupport(passesResult: PassesResult) extends UseCaseDiagramSupport {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AdaptorWriterTest extends WriterTest {
|| _Briefly_ | No brief description. |
|| _Authors_ | |
|| _Definition Path_ | Root.Adaptors.One.FromTwo |
|| _View Source Link_ | [hugo/src/test/input/adaptors.riddl(4:5)]() |
|| _View Source Link_ | [hugo/src/test/input/adaptors.riddl(77->372)]() |
|| _Used By_ | None |
|| _Uses_ | None |
|
Expand All @@ -70,7 +70,7 @@ class AdaptorWriterTest extends WriterTest {
|| :---: | :--- |
|| _Briefly_ | No brief description. |
|| _Definition Path_ | FromTwo.Root.Adaptors.One.Adaptation |
|| _View Source Link_ | [hugo/src/test/input/adaptors.riddl(6:15)]() |
|| _View Source Link_ | [hugo/src/test/input/adaptors.riddl(158->368)]() |
|| _Used By_ | None |
|| _Uses_ | None |
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class MarkdownWriterTest extends HugoTestBase {
|| _Briefly_ | Just For Testing |
|| _Authors_ | |
|| _Definition Path_ | Root.TestDomain |
|| _View Source Link_ | [empty(1:1)]() |
|| _View Source Link_ | [empty(0->294)]() |
|| _Used By_ | None |
|| _Uses_ | None |
|
Expand Down Expand Up @@ -98,7 +98,7 @@ class MarkdownWriterTest extends HugoTestBase {
|| :---: | :--- |
|| _Briefly_ | No brief description. |
|| _Definition Path_ | TestDomain.Root.MyString |
|| _View Source Link_ | [empty(3:3)]() |
|| _View Source Link_ | [empty(84->154)]() |
|| _Used By_ | None |
|| _Uses_ | None |
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class RepositoryWriterTest extends WriterTest {
|| _Briefly_ | No brief description. |
|| _Authors_ | |
|| _Definition Path_ | Root.Repository.One.Repo |
|| _View Source Link_ | [hugo/src/test/input/repository.riddl(3:5)]() |
|| _View Source Link_ | [hugo/src/test/input/repository.riddl(46->85)]() |
|| _Used By_ | None |
|| _Uses_ | None |
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Messages.*
import com.ossuminc.riddl.language.parsing.RiddlParserInput
import com.ossuminc.riddl.language.parsing.RiddlParserInput.*
import com.ossuminc.riddl.utils.{pc, AbstractTestingBasis, StringLogger, URL, CommonOptions}
import scala.io.AnsiColor.*


class MessagesTest extends AbstractTestingBasis {

Expand Down Expand Up @@ -151,14 +153,22 @@ class MessagesTest extends AbstractTestingBasis {
Messages.logMessages(mix)
val content = slog.toString
val expected =
"""[info] empty(1:1)info
|[style] empty(1:1)style
|[missing] empty(1:1)missing
|[usage] empty(1:1)usage
|[warning] empty(1:1)warning
|[error] empty(1:1)error
|[severe] empty(1:1)severe
s"""$BLUE$BOLD[info] empty(1:1->1):$RESET
|${BLUE}info$RESET
|$GREEN$BOLD[style] empty(1:1->1):$RESET
|${GREEN}style$RESET
|$GREEN$BOLD[missing] empty(1:1->1):$RESET
|${GREEN}missing$RESET
|$GREEN$BOLD[usage] empty(1:1->1):$RESET
|${GREEN}usage$RESET
|$YELLOW$BOLD[warning] empty(1:1->1):$RESET
|${YELLOW}warning$RESET
|$RED$BOLD[error] empty(1:1->1):$RESET
|${RED}error$RESET
|$RED_B$BLACK$BOLD[severe] empty(1:1->1):$RESET
|$RED_B${BLACK}severe$RESET
|""".stripMargin
info(s"Comparing expected:\n$expected\nwith actual:\n$content\n")
content mustBe expected
}
}
Expand All @@ -168,18 +178,24 @@ class MessagesTest extends AbstractTestingBasis {
Messages.logMessages(mix)
val content = pc.log.toString
val expected =
"""[severe] Severe Message Count: 1
|[severe] empty(1:1)severe
|[error] Error Message Count: 1
|[error] empty(1:1)error
|[usage] Usage Message Count: 1
|[usage] empty(1:1)usage
|[missing] Missing Message Count: 1
|[missing] empty(1:1)missing
|[style] Style Message Count: 1
|[style] empty(1:1)style
|[info] Info Message Count: 1
|[info] empty(1:1)info
s"""$RED_B$BLACK$BOLD[severe] Severe Message Count: 1$RESET
|$RED_B$BLACK$BOLD[severe] empty(1:1->1):$RESET
|$RED_B${BLACK}severe$RESET
|$RED$BOLD[error] Error Message Count: 1$RESET
|$RED$BOLD[error] empty(1:1->1):$RESET
|${RED}error$RESET
|$GREEN$BOLD[usage] Usage Message Count: 1$RESET
|$GREEN$BOLD[usage] empty(1:1->1):$RESET
|${GREEN}usage$RESET
|$GREEN$BOLD[missing] Missing Message Count: 1$RESET
|$GREEN$BOLD[missing] empty(1:1->1):$RESET
|${GREEN}missing$RESET
|$GREEN$BOLD[style] Style Message Count: 1$RESET
|$GREEN$BOLD[style] empty(1:1->1):$RESET
|${GREEN}style$RESET
|$BLUE$BOLD[info] Info Message Count: 1$RESET
|$BLUE$BOLD[info] empty(1:1->1):$RESET
|${BLUE}info$RESET
|""".stripMargin
content mustBe expected
}
Expand All @@ -188,30 +204,31 @@ class MessagesTest extends AbstractTestingBasis {

"has inquiry methods" in {
val mix_formatted = mix.format
mix_formatted.length must be(115)
mix_formatted.length must be(150)
mix.isOnlyWarnings must be(false)
mix.isOnlyIgnorable must be(false)
mix.hasErrors must be(true)
mix.hasWarnings must be(true)
}

"format a correct string for empty location" in {
val msg = Message(At(1, 2, RiddlParserInput.empty), "the_message", Warning)
val rpi = RiddlParserInput.empty
val msg = Message(At(1, 2, rpi), "the_message", Warning)
val content = msg.format
val expected = "empty(1:2)the_message"
val expected = "empty(1:2->3):\nthe_message"
content mustBe expected
}

"format to locate output for non-empty location" in {
val rip: RiddlParserInput = RiddlParserInput("test", URL.empty, "test")
val rip: RiddlParserInput = RiddlParserInput("TEST INPUT", URL.empty, "test")
val at = At(1, 2, rip)
val msg = Message(at, "the_message", Warning)
val content = msg.format
BOLD
val expected =
"""empty(1:2):
s"""empty(1:2->3):
|the_message:
|test
| ^""".stripMargin
|T${BOLD}E${RESET}ST INPUT""".stripMargin
content mustBe expected
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
fail(msg)
case Right((content, rpi)) =>
content mustBe
Domain((1, 1, rpi), Identifier((1, 8, rpi), "foo-fah|roo"))
Domain(At(rpi, 0, 31), Identifier(At(rpi, 7, 21), "foo-fah|roo"))
}
}
"allow nested domains" in { (td: TestData) =>
Expand Down Expand Up @@ -153,7 +153,7 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
fail(msg)
case Right((content, rpi)) =>
content mustBe
Context((1, 17, rpi), id = Identifier((1, 25, rpi), "bar"))
Context(At(rpi, 16, 39), id = Identifier(At(rpi, 24, 28), "bar"))
}
}
"allow options on context definitions" in { (td: TestData) =>
Expand All @@ -173,12 +173,12 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
case Right((content, rpi)) =>
content must be(
Context(
(1, 1, rpi),
Identifier((1, 9, rpi), "bar"),
At(rpi, 0, 70),
Identifier(At(rpi, 8, 12), "bar"),
Contents(
OptionValue((2, 10, rpi), "service", Seq.empty),
OptionValue((3, 10, rpi), "wrapper", Seq.empty),
OptionValue((4, 10, rpi), "gateway", Seq.empty)
OptionValue(At(rpi, 19, 36), "service", Seq.empty),
OptionValue(At(rpi, 36, 53), "wrapper", Seq.empty),
OptionValue(At(rpi, 53, 68), "gateway", Seq.empty)
)
)
)
Expand All @@ -197,47 +197,19 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
fail(msg)
case Right((content, rpi)) =>
val expected = Type(
(2, 1, rpi),
Identifier((2, 6, rpi), "Vikings"),
At(rpi, 17, 96),
Identifier(At(rpi, 22, 30), "Vikings"),
Enumeration(
(2, 16, rpi),
At(rpi, 32, 96),
Contents(
Enumerator(
(3, 3, rpi),
Identifier((3, 3, rpi), "Ragnar"),
None
),
Enumerator(
(3, 10, rpi),
Identifier((3, 10, rpi), "Lagertha"),
None
),
Enumerator(
(3, 19, rpi),
Identifier((3, 19, rpi), "Bjorn"),
None
),
Enumerator(
(3, 25, rpi),
Identifier((3, 25, rpi), "Floki"),
None
),
Enumerator(
(3, 31, rpi),
Identifier((3, 31, rpi), "Rollo"),
None
),
Enumerator(
(3, 37, rpi),
Identifier((3, 37, rpi), "Ivar"),
None
),
Enumerator(
(3, 42, rpi),
Identifier((3, 42, rpi), "Aslaug"),
None
),
Enumerator((3, 49, rpi), Identifier((3, 49, rpi), "Ubbe"), None)
Enumerator(At(rpi, 43, 50), Identifier(At(rpi, 43, 50), "Ragnar"), None),
Enumerator(At(rpi, 50, 59), Identifier(At(rpi, 50, 59), "Lagertha"), None),
Enumerator(At(rpi, 59, 65), Identifier(At(rpi, 59, 65), "Bjorn"), None),
Enumerator(At(rpi, 65, 71), Identifier(At(rpi, 65, 71), "Floki"), None),
Enumerator(At(rpi, 71, 77), Identifier(At(rpi, 71, 77), "Rollo"), None),
Enumerator(At(rpi, 77, 82), Identifier(At(rpi, 77, 82), "Ivar"), None),
Enumerator(At(rpi, 82, 89), Identifier(At(rpi, 82, 89), "Aslaug"), None),
Enumerator(At(rpi, 89, 94), Identifier(At(rpi, 89, 94), "Ubbe"), None)
)
)
)
Expand All @@ -252,9 +224,9 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
fail(msg)
case Right((content, rpi)) =>
content mustBe Invariant(
(1, 11, rpi),
Identifier((1, 11, rpi), "large"),
Option(LiteralString((1, 20, rpi), "x is greater or equal to 10"))
At(rpi, 0, 49),
Identifier(At(rpi, 10, 16), "large"),
Option(LiteralString(At(rpi, 19, 48), "x is greater or equal to 10"))
)
}
}
Expand All @@ -276,25 +248,25 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
fail(msg)
case Right((content, rpi)) =>
val expected = Entity(
(1, 1, rpi),
Identifier((1, 8, rpi), "Hamburger"),
At(rpi, 0, 161),
Identifier(At(rpi, 7, 17), "Hamburger"),
Contents(
OptionValue((2, 10, rpi), "transient", Seq.empty),
OptionValue((3, 10, rpi), "aggregate", Seq.empty),
OptionValue(At(rpi, 24, 43), "transient", Seq.empty),
OptionValue(At(rpi, 43, 62), "aggregate", Seq.empty),
Type(
(4, 3, rpi),
Identifier((4, 8, rpi), "Foo"),
At(rpi, 62, 90),
Identifier(At(rpi, 67, 71), "Foo"),
Aggregation(
(4, 15, rpi),
Contents(Field((4, 17, rpi), Identifier((4, 17, rpi), "x"), String_((4, 20, rpi))))
At(rpi, 74, 90),
Contents(Field(At(rpi, 76, 86), Identifier(At(rpi, 76, 77), "x"), String_(At(rpi, 79, 86))))
)
),
State(
(5, 3, rpi),
Identifier((5, 9, rpi), "BurgerState"),
TypeRef((5, 24, rpi), "type", PathIdentifier((5, 29, rpi), List("BurgerStruct")))
At(rpi, 90, 131),
Identifier(At(rpi, 96, 108), "BurgerState"),
TypeRef(At(rpi, 111, 131), "type", PathIdentifier(At(rpi, 116, 131), List("BurgerStruct")))
),
Handler((6, 11, rpi), Identifier((6, 11, rpi), "BurgerHandler"))
Handler(At(rpi, 131, 159), Identifier(At(rpi, 139, 153), "BurgerHandler"))
)
)
content mustBe expected
Expand All @@ -308,12 +280,12 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
fail(msg)
case Right((content, rpi)) =>
content mustBe Adaptor(
(1, 1, rpi),
Identifier((1, 9, rpi), "fuzz"),
InboundAdaptor((1, 14, rpi)),
At(rpi, 0, 44),
Identifier(At(rpi, 8, 13), "fuzz"),
InboundAdaptor(At(rpi, 13, 18)),
ContextRef(
(1, 19, rpi),
PathIdentifier((1, 27, rpi), Seq("foo", "bar"))
At(rpi, 18, 34),
PathIdentifier(At(rpi, 26, 34), Seq("foo", "bar"))
),
Contents.empty
)
Expand All @@ -335,8 +307,8 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
case Left(errors) =>
val msg = errors.map(_.format).mkString
fail(msg)
case Right((function, _)) =>
inside(function) {
case Right((function: Function, _)) =>
function match
case Function(
_,
Identifier(_, "foo"),
Expand All @@ -345,15 +317,14 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
_,
_
) =>
firstAggrContents must be(
Contents(Field(At(3, 14, rpi), Identifier(At(3, 14, rpi), "b"), Bool(At(3, 18, rpi)), Contents.empty))
)
secondAggrContents must be(
Contents(
Field(At(4, 13, rpi), Identifier(At(4, 13, rpi), "i"), Integer(At(4, 17, rpi)), Contents.empty)
)
)
}
val firstExpected =
Field(At(rpi, 32, 43), Identifier(At(rpi, 32, 34), "b"), Bool(At(rpi, 36, 43)), Contents.empty)
firstAggrContents.head must be(firstExpected)
val secondExpected =
Field(At(rpi, 57, 68), Identifier(At(rpi, 57, 59), "i"), Integer(At(rpi, 61, 68)), Contents.empty)
secondAggrContents.head must be(secondExpected)
end match

}
}
"handle a comment" in { (td: TestData) =>
Expand Down Expand Up @@ -381,7 +352,7 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
case Left(errors) => fail(errors.format)
case Right((domain, rpi)) =>
val typ = domain.contexts.head.types.head
typ.typEx mustBe Replica((3, 18, rpi), Integer((3, 29, rpi)))
typ.typEx mustBe Replica(At(rpi, 49, 70), Integer(At(rpi, 60, 70)))
}
}
"parse from a complex file" in { (td: TestData) =>
Expand All @@ -407,12 +378,12 @@ class ParserTest extends ParsingTest with org.scalatest.Inside {
*/
root.contents.startsWith(
Seq(
LineComment((1, 1, rpi), "Top Level Author"),
LineComment(At(rpi, 0, 20), "Top Level Author"),
Author(
(2, 1, rpi),
Identifier((2, 8, rpi), "Reid"),
LiteralString((2, 23, rpi), "Reid"),
LiteralString((2, 37, rpi), "[email protected]")
At(rpi, 20, 77),
Identifier(At(rpi, 27, 32), "Reid"),
LiteralString(At(rpi, 43, 49), "Reid"),
LiteralString(At(rpi, 57, 73), "[email protected]")
)
)
)
Expand Down
Loading

0 comments on commit ff68964

Please sign in to comment.