Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Displayable Types #494

Merged
merged 19 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
49 changes: 49 additions & 0 deletions compiler/lib/src/main/scala/analysis/Analysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,55 @@ case class Analysis(
}
}

/** Gets the reason for a non-displayable type at an AST node id
*
* The id must identify an AST node with a non-displayable type,
* or the function will intentionally crash. */
def getReasonForNonDisplayableTypeAt(id: AstNode.Id): String = {
def getElementReason(id: AstNode.Id): String = {
val reason = getReasonForNonDisplayableTypeAt(id)
s"\n\n${Locations.get(id)}\nbecause this type is not displayable$reason"
}
this.typeMap(id) match {
case a: Type.Array =>
val id = a.node._2.data.eltType.id
getElementReason(id)
case s: Type.Struct =>
val idOpt = s.node._2.data.members.map(_._2.data.typeName.id).find(
id => !this.typeMap(id).isDisplayable
)
idOpt.map(getElementReason).getOrElse(
throw new InternalError(
"a non-displayable struct type must have a non-displayable member type"
)
)
case t =>
t.getDefNodeId.map(id => s"\n\n${Locations.get(id)}\nType is defined here").getOrElse(
throw new InternalError(
"a non-displayable type at an AST node ID must have a definition"
)
)
}
}

/** Checks for a displayable type */
def checkDisplayableType(id: AstNode.Id, errorMsg: String): Result.Result[Unit] = {
val loc = Locations.get(id)
val t = this.typeMap(id)
if (t.isDisplayable) Right(())
else {
val reason = getReasonForNonDisplayableTypeAt(id)
Left(SemanticError.InvalidType(loc, s"$errorMsg$reason"))
}
}

/** Checks that all parameters in a formal param list are displayable */
def checkDisplayableParams(nodes: Ast.FormalParamList, errorMsg: String): Result.Result[Unit] = {
Result.foldLeft (nodes) (()) ((result, aNode) =>
checkDisplayableType(aNode._2.data.typeName.id, errorMsg)
)
}

}

object Analysis {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ object Command {
priority <- Right(a.getBigIntValueOpt(data.priority))
_ <- Analysis.checkForDuplicateParameter(data.params)
_ <- checkRefParams(data.params)
_ <- a.checkDisplayableParams(data.params, "type of command parameter is not displayable")
}
yield {
val kind = data.kind match {
Expand Down
1 change: 1 addition & 0 deletions compiler/lib/src/main/scala/analysis/Semantics/Event.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ object Event {
}
for {
_ <- checkRefParams(data.params)
_ <- a.checkDisplayableParams(data.params, "type of event is not displayable")
format <- Analysis.computeFormat(
data.format,
data.params.map(aNode => a.typeMap(aNode._2.data.typeName.id))
Expand Down
1 change: 1 addition & 0 deletions compiler/lib/src/main/scala/analysis/Semantics/Param.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ object Param {
default <- Result.mapOpt(data.default, computeDefaultValue)
setOpcodeOpt <- a.getNonnegativeBigIntValueOpt(data.setOpcode)
saveOpcodeOpt <- a.getNonnegativeBigIntValueOpt(data.saveOpcode)
_ <- a.checkDisplayableType(data.typeName.id, "type of parameter is not displayable")
}
yield {
val (setOpcode, defaultOpcode1) = computeOpcode(setOpcodeOpt, defaultOpcode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ object TlmChannel {
)
lowLimits <- computeLimits(a, data.low)
highLimits <- computeLimits(a, data.high)
_ <- a.checkDisplayableType(data.typeName.id, "type of telemetry channel is not displayable")
}
yield TlmChannel(aNode, channelType, update, format, lowLimits, highLimits)
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/lib/src/main/scala/analysis/Semantics/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ sealed trait Type {
/** Is this type promotable to an array type? */
def isPromotableToArray: Boolean = isNumeric

/** Is this type displayable? */
def isDisplayable: Boolean = false

/** Is this type a float type? */
def isFloat: Boolean = false

Expand Down Expand Up @@ -62,6 +65,7 @@ object Type {
extends Type with Primitive with Int
{
override def getDefaultValue = Some(Value.PrimitiveInt(0, kind))
override def isDisplayable = true
override def toString = kind match {
case PrimitiveInt.I8 => "I8"
case PrimitiveInt.I16 => "I16"
Expand Down Expand Up @@ -99,6 +103,7 @@ object Type {
case class Float(kind: Float.Kind) extends Type with Primitive {
override def getDefaultValue = Some(Value.Float(0, kind))
override def isFloat = true
override def isDisplayable = true
override def toString = kind match {
case Float.F32 => "F32"
case Float.F64 => "F64"
Expand All @@ -119,13 +124,15 @@ object Type {
override def getDefaultValue = Some(Value.Boolean(false))
override def toString = "bool"
override def isPromotableToArray = true
override def isDisplayable = true
}

/** The type of a string */
case class String(size: Option[AstNode[Ast.Expr]]) extends Type {
override def getDefaultValue = Some(Value.String(""))
override def toString = "string"
override def isPromotableToArray = true
override def isDisplayable = true
}

/** The type of arbitrary-width integers */
Expand Down Expand Up @@ -161,6 +168,7 @@ object Type {
override def getArraySize = anonArray.getArraySize
override def getDefNodeId = Some(node._2.id)
override def hasNumericMembers = anonArray.hasNumericMembers
override def isDisplayable = anonArray.eltType.isDisplayable
override def toString = "array " ++ node._2.data.name
}

Expand Down Expand Up @@ -198,6 +206,7 @@ object Type {
override def getDefNodeId = Some(node._2.id)
override def isConvertibleToNumeric = true
override def isPromotableToArray = true
override def isDisplayable = true
override def toString = "enum " ++ node._2.data.name
}

Expand All @@ -217,6 +226,7 @@ object Type {
override def getDefaultValue: Option[Value.Struct] = default
override def getDefNodeId = Some(node._2.id)
override def hasNumericMembers = anonStruct.hasNumericMembers
override def isDisplayable = anonStruct.members.values.forall(_.isDisplayable)
override def toString = "struct " ++ node._2.data.name
}

Expand Down
32 changes: 32 additions & 0 deletions compiler/lib/src/test/scala/semantics/TypeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,36 @@ class TypeSpec extends AnyWordSpec {
}
}

"displayable type" should {
val displayable = List(
I32,
F32,
Boolean,
String(None),
defaultEnum,
defaultArray,
defaultStruct,
array("A1", AnonArray(None, array("A2", AnonArray(None, I32)))),
struct("S1", AnonStruct(Map("x" -> I32)))
)
val notDisplayable = List(
Integer,
AnonArray(None, I32),
AnonStruct(Map()),
defaultAbsType,
array("A3", AnonArray(None, defaultAbsType)),
array("A4", AnonArray(None, array("A5", AnonArray(None, defaultAbsType)))),
struct("S2", AnonStruct(Map("x" -> defaultAbsType))),
struct("S3", AnonStruct(Map("x" -> struct("S4", AnonStruct(Map("x" -> defaultAbsType))))))
)
displayable.foreach {
ty => s"be true for $ty" in
assert(ty.isDisplayable)
}
notDisplayable.foreach {
ty => s"be false for $ty" in
assert(!ty.isDisplayable)
}
}

}
22 changes: 22 additions & 0 deletions compiler/tools/fpp-check/test/command/not_displayable.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Fw {
port Cmd
port CmdReg
port CmdResponse
}

type T

struct S {
x: T
y: U32
} default { y = 1 }

active component Comp {

command recv port cmdIn
command reg port cmdRegOut
command resp port cmdResponseOut

async command C(a1: S)

}
15 changes: 15 additions & 0 deletions compiler/tools/fpp-check/test/command/not_displayable.ref.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/command/not_displayable.fpp:20.23
async command C(a1: S)
^
error: type of command parameter is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/command/not_displayable.fpp:10.6
x: T
^
because this type is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/command/not_displayable.fpp:7.1
type T
^
Type is defined here
1 change: 1 addition & 0 deletions compiler/tools/fpp-check/test/command/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ duplicate_opcode_implicit
duplicate_param
missing_ports
negative_opcode
not_displayable
ok
ref_params
sync_priority
Expand Down
17 changes: 17 additions & 0 deletions compiler/tools/fpp-check/test/event/not_displayable.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Fw {
port Log
port LogText
port Time
}

type T

active component C {

time get port timeGetOut
event port logOut
text event port logTextOut

event E(x: T) severity activity low format "{}"

}
10 changes: 10 additions & 0 deletions compiler/tools/fpp-check/test/event/not_displayable.ref.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/not_displayable.fpp:15.14
event E(x: T) severity activity low format "{}"
^
error: type of event is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/event/not_displayable.fpp:7.1
type T
^
Type is defined here
1 change: 1 addition & 0 deletions compiler/tools/fpp-check/test/event/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ format_too_many_repls
missing_ports
negative_id
negative_throttle
not_displayable
ok
ref_params
throttle_too_large
Expand Down
16 changes: 16 additions & 0 deletions compiler/tools/fpp-check/test/param/not_displayable.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Fw {
port PrmGet
port PrmSet
}

type T

active component Comp {

param get port prmGetOut

param set port prmSetOut

param P: T

}
10 changes: 10 additions & 0 deletions compiler/tools/fpp-check/test/param/not_displayable.ref.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/param/not_displayable.fpp:14.12
param P: T
^
error: type of parameter is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/param/not_displayable.fpp:6.1
type T
^
Type is defined here
1 change: 1 addition & 0 deletions compiler/tools/fpp-check/test/param/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ missing_ports
negative_id
negative_save_opcode
negative_set_opcode
not_displayable
ok
"
20 changes: 20 additions & 0 deletions compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Fw {
port Time
port Tlm
}

struct S1 { x: S2 }

struct S2 { x: A1 }

array A1 = [3] A2

array A2 = [3] T

type T

passive component C {
telemetry port tlmOut
time get port timeGetOut
telemetry C: S1
}
30 changes: 30 additions & 0 deletions compiler/tools/fpp-check/test/tlm_channel/not_displayable.ref.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp:19.16
telemetry C: S1
^
error: type of telemetry channel is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp:6.16
struct S1 { x: S2 }
^
because this type is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp:8.16
struct S2 { x: A1 }
^
because this type is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp:10.16
array A1 = [3] A2
^
because this type is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp:12.16
array A2 = [3] T
^
because this type is not displayable

[ local path prefix ]/compiler/tools/fpp-check/test/tlm_channel/not_displayable.fpp:14.1
type T
^
Type is defined here
1 change: 1 addition & 0 deletions compiler/tools/fpp-check/test/tlm_channel/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ format_too_many_repls
limit_not_numeric
missing_ports
negative_id
not_displayable
ok
"
Loading
Loading