Skip to content

Commit

Permalink
507 Provide More Output Types (#510)
Browse files Browse the repository at this point in the history
Add the ability to present strings and constants directly
in an application output.
  • Loading branch information
reid-spencer authored Dec 15, 2023
1 parent 8c4f0e4 commit d599fc6
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ trait SequenceDiagramSupport {
@SuppressWarnings(Array("org.wartremover.warts.OptionPartial"))
case class SequenceDiagram(sds: SequenceDiagramSupport, useCase: UseCase) extends FileBuilder {

final val indent_per_level = 4
private final val indent_per_level = 4

def generate: Seq[String] = {
sb.append("sequenceDiagram"); nl
Expand All @@ -44,7 +44,7 @@ case class SequenceDiagram(sds: SequenceDiagramSupport, useCase: UseCase) extend
sb.toString().split('\n').toSeq
}

def actorsFirst(a: (String, Definition), b: (String, Definition)): Boolean = {
private def actorsFirst(a: (String, Definition), b: (String, Definition)): Boolean = {
a._2 match
case _: User if b._2.isInstanceOf[User] => a._1 < b._1
case _: User => true
Expand Down
15 changes: 9 additions & 6 deletions language/src/main/scala/com/ossuminc/riddl/language/AST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ object AST { // extends ast.AbstractDefinitions with ast.Definitions with ast.Ri
def loc: At
}

/** The things that can be found at the top level of the parse */
sealed trait TopLevelValue extends RiddlValue

/** Represents a literal string parsed between quote characters in the input
*
* @param loc
Expand Down Expand Up @@ -177,7 +180,7 @@ object AST { // extends ast.AbstractDefinitions with ast.Definitions with ast.Ri
* @param text
* The text of the comment, everything after the // to the end of line
*/
case class Comment(loc: At, text: String = "") extends RiddlValue {
case class Comment(loc: At, text: String = "") extends TopLevelValue {
def format: String = "//" + text
}

Expand Down Expand Up @@ -349,7 +352,7 @@ object AST { // extends ast.AbstractDefinitions with ast.Definitions with ast.Ri
sealed trait RepositoryDefinition extends Definition

/** Base trait of definitions defined at root scope */
sealed trait RootDefinition extends Definition
sealed trait RootDefinition extends Definition with TopLevelValue

/** Base trait of definitions define within a Streamlet */
sealed trait StreamletDefinition extends Definition
Expand Down Expand Up @@ -1781,8 +1784,8 @@ object AST { // extends ast.AbstractDefinitions with ast.Definitions with ast.Ri
case class ConstantRef(
loc: At = At.empty,
pathId: PathIdentifier = PathIdentifier.empty
) extends Reference[Field] {
override def format: String = s"const ${pathId.format}"
) extends Reference[Constant] {
override def format: String = s"constant ${pathId.format}"
}

/** A type definition which associates an identifier with a type expression.
Expand Down Expand Up @@ -3302,7 +3305,7 @@ object AST { // extends ast.AbstractDefinitions with ast.Definitions with ast.Ri
comments: Seq[Comment] = Seq.empty[Comment]
) extends GenericInteraction {
def relationship: LiteralString =
LiteralString(loc+(6+ from.pathId.format.length), "focuses on ")
LiteralString(loc + (6 + from.pathId.format.length), "focuses on ")
override def kind: String = "Focus On URL"
}

Expand Down Expand Up @@ -3548,7 +3551,7 @@ object AST { // extends ast.AbstractDefinitions with ast.Definitions with ast.Ri
nounAlias: String,
id: Identifier,
verbAlias: String,
putOut: TypeRef,
putOut: TypeRef | ConstantRef | LiteralString,
outputs: Seq[OutputDefinition] = Seq.empty[OutputDefinition],
brief: Option[LiteralString] = None,
description: Option[Description] = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private[parsing] trait ApplicationParser {
(undefined(Seq.empty[GroupDefinition]) | groupDefinitions) ~
close ~ briefly ~ description ~ comments
).map { case (loc, alias, id, elements, brief, description, comments) =>
Group(loc, alias, id, elements, brief, description)
Group(loc, alias, id, elements, brief, description, comments)
}
}

Expand All @@ -69,10 +69,32 @@ private[parsing] trait ApplicationParser {

private def appOutput[u: P]: P[Output] = {
P(
location ~ outputAliases ~/ identifier ~ presentationAliases ~/ typeRef ~
location ~ outputAliases ~/ identifier ~ presentationAliases ~/ ( literalString | constantRef | typeRef ) ~/
outputDefinitions ~ briefly ~ description ~ comments
).map { case (loc, nounAlias, id, verbAlias, putOut, outputs, brief, description, comments) =>
Output(loc, nounAlias, id, verbAlias, putOut, outputs, brief, description, comments)
putOut match {
case t: TypeRef =>
Output(loc, nounAlias, id, verbAlias, t, outputs, brief, description, comments)
case c: ConstantRef =>
Output(loc, nounAlias, id, verbAlias, c, outputs, brief, description, comments)
case l: LiteralString =>
Output(loc, nounAlias, id, verbAlias, l, outputs, brief, description, comments)
case x: RiddlValue =>
// this should never happen but the derived base class, RiddlValue, demands it
val xval = x.format
error(s"Expected a type reference, constant reference, or literal string, not: $xval")
Output(
loc,
nounAlias,
id,
verbAlias,
LiteralString(loc, s"INVALID: `$xval``"),
outputs,
brief,
description,
comments
)
}
}
}

Expand Down Expand Up @@ -107,7 +129,7 @@ private[parsing] trait ApplicationParser {
location ~ inputAliases ~/ identifier ~/ acquisitionAliases ~/ typeRef ~
inputDefinitions ~ briefly ~ description ~ comments
).map { case (loc, inputAlias, id, acquisitionAlias, putIn, inputs, brief, description, comments) =>
Input(loc, inputAlias, id, acquisitionAlias, putIn, inputs, brief, description)
Input(loc, inputAlias, id, acquisitionAlias, putIn, inputs, brief, description, comments)
}
}

Expand All @@ -119,7 +141,7 @@ private[parsing] trait ApplicationParser {
}

private def applicationDefinitions[u: P]: P[Seq[ApplicationDefinition]] = {
P(applicationDefinition.rep(0))
P(applicationDefinition.rep(0, comments))
}

private def applicationInclude[u: P]: P[Include[ApplicationDefinition]] = {
Expand All @@ -131,20 +153,20 @@ private[parsing] trait ApplicationParser {
}

private def applicationBody[u: P]: P[(Seq[ApplicationOption], Seq[ApplicationDefinition])] = {
undefined((Seq.empty[ApplicationOption], Seq.empty[ApplicationDefinition]))
applicationOptions ~ applicationDefinitions
}

def application[u: P]: P[Application] = {
P(
location ~ Keywords.application ~/ identifier ~ authorRefs ~ is ~ open ~
(emptyApplication | (applicationOptions ~ applicationDefinitions)) ~
(emptyApplication | applicationBody) ~
close ~ briefly ~ description ~ comments
).map { case (loc, id, authors, (options, content), brief, description, comments) =>
val groups = content.groupBy(_.getClass)
val types = mapTo[Type](groups.get(classOf[Type]))
val constants = mapTo[Constant](groups.get(classOf[Constant]))
val invariants = mapTo[Invariant](groups.get(classOf[Invariant]))
val grps = mapTo[Group](groups.get(classOf[Group]))
val groupDefinitions = mapTo[Group](groups.get(classOf[Group]))
val handlers = mapTo[Handler](groups.get(classOf[Handler]))
val functions = mapTo[Function](groups.get(classOf[Function]))
val inlets = mapTo[Inlet](groups.get(classOf[Inlet]))
Expand All @@ -163,7 +185,7 @@ private[parsing] trait ApplicationParser {
types,
constants,
invariants,
grps,
groupDefinitions,
handlers,
inlets,
outlets,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.ossuminc.riddl.language.At
import fastparse.*
import fastparse.MultiLineWhitespace.*

import java.lang.Character.{isLetter, isLetterOrDigit}
import java.net.URI
import java.nio.file.Files
import scala.reflect.{ClassTag, classTag}
Expand Down Expand Up @@ -58,10 +57,6 @@ private[parsing] trait CommonParser extends NoWhiteSpaceParsers {
P(Punctuation.undefinedMark./).map(_ => f)
}

def whiteSpaceChar[u: P]: P[Unit] = {
CharIn(" \t\n")
}

def literalStrings[u: P]: P[Seq[LiteralString]] = { P(literalString.rep(1)) }

private def markdownLines[u: P]: P[Seq[LiteralString]] = {
Expand Down Expand Up @@ -200,9 +195,9 @@ private[parsing] trait CommonParser extends NoWhiteSpaceParsers {
map: Map[Class[Definition], Seq[Definition]]
) {
def extract[T <: Definition: ClassTag]: Seq[T] = {
val classe = classTag[T].runtimeClass
val clazzTag = classTag[T].runtimeClass
map
.get(classe.asInstanceOf[Class[Definition]])
.get(clazzTag.asInstanceOf[Class[Definition]])
.fold(Seq.empty[T])(_.map(_.asInstanceOf[T]))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
domain foo {
application foo2 {
page target is { ??? }
constant ThingToDisplay is string = "A displayed thing"
type Foo is record { ??? }
page target is {
output a displays "something moving but not a movie"
output c displays record Foo
output b displays constant foo.foo2.ThingToDisplay
}
menu choice is {
button b acquires Nothing
item i1 acquires String is { ??? }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ case class ResolutionPass(input: PassInput, outputs: PassesOutput) extends Pass(
case in: Input =>
resolveATypeRef(in.putIn, parentsAsSeq)
case out: Output =>
resolveATypeRef(out.putOut, parentsAsSeq)
out.putOut match {
case typ: TypeRef => resolveATypeRef(typ, parentsAsSeq)
case const: ConstantRef => resolveARef[Constant](const, parentsAsSeq)
case _: LiteralString => () // not a reference
}
case cg: ContainedGroup =>
resolveARef[Group](cg.group, parentsAsSeq)
case gi: GenericInteraction =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,11 @@ case class ValidationPass(
parents: Seq[Definition]
): Unit = {
checkDefinition(parents, out)
checkTypeRef(out.putOut, out, parents)
out.putOut match {
case typ: TypeRef => checkTypeRef(typ, out, parents)
case const: ConstantRef => checkRef[Constant](const, out, parents)
case str: LiteralString => checkNonEmpty(str.s, "string to put out", out, Messages.Error)
}
checkDescription(out)
}

Expand Down Expand Up @@ -759,22 +763,31 @@ case class ValidationPass(
case Some(d) if d.isAppRelated =>
d match {
case output @ Output(loc, _, id, _, putOut, _, _, _, _) =>
checkTypeRef(putOut, parents.head, parents.tail) match {
case Some(Type(_, _, typEx, _, _, _)) if typEx.isContainer =>
typEx match {
case ate: AggregateUseCaseTypeExpression
if ate.usecase == EventCase || ate.usecase == ResultCase =>
None // events and results are permitted
case ty: TypeExpression => // everything else is not
Some(
error(
s"${output.identify} showing ${putOut.format} of type ${ty.format} is invalid " +
s" because ${o.identify} is a vital definition which can only send Events and Results",
loc
)
)
putOut match {
case typRef: TypeRef =>
checkTypeRef(typRef, parents.head, parents.tail) match {
case Some(Type(_, _, typEx, _, _, _)) if typEx.isContainer =>
typEx match {
case ate: AggregateUseCaseTypeExpression
if ate.usecase == EventCase || ate.usecase == ResultCase =>
None // events and results are permitted
case ty: TypeExpression => // everything else is not
Some(
error(
s"${output.identify} showing ${typRef.format} of type ${ty.format} is invalid " +
s" because ${o.identify} is a vital definition which can only send Events and Results",
loc
)
)
}
case _ => None //
}
case _ => None //
case constRef: ConstantRef =>
checkRef[Constant](constRef, parents.head, parents.tail)
Option.empty[Message]
case str: LiteralString =>
checkNonEmptyValue (str, "string to put out", parents.head, Messages.Error)
Option.empty[Message]
}
case _ => None
}
Expand Down

0 comments on commit d599fc6

Please sign in to comment.