diff --git a/compiler/lib/src/main/scala/ast/Ast.scala b/compiler/lib/src/main/scala/ast/Ast.scala index 2bc91ef2e..3f01040c0 100644 --- a/compiler/lib/src/main/scala/ast/Ast.scala +++ b/compiler/lib/src/main/scala/ast/Ast.scala @@ -64,6 +64,7 @@ object Ast { final case class DefEnum(node: AstNode[Ast.DefEnum]) extends Node final case class DefStateMachine(node: AstNode[Ast.DefStateMachine]) extends Node final case class DefStruct(node: AstNode[Ast.DefStruct]) extends Node + final case class DefVector(node: AstNode[Ast.DefVector]) extends Node final case class SpecCommand(node: AstNode[Ast.SpecCommand]) extends Node final case class SpecContainer(node: AstNode[Ast.SpecContainer]) extends Node final case class SpecEvent(node: AstNode[Ast.SpecEvent]) extends Node @@ -98,6 +99,17 @@ object Ast { isDictionaryDef: Boolean ) + /* Vector definition */ + final case class DefVector( + name: Ident, + size: AstNode[Expr], + sizePrefixType: Option[AstNode[TypeName]], + eltType: AstNode[TypeName], + default: Option[AstNode[Expr]], + format: Option[AstNode[String]], + isDictionaryDef: Boolean + ) + /** Component definition */ final case class DefComponent( kind: ComponentKind, @@ -165,6 +177,7 @@ object Ast { final case class DefStruct(node: AstNode[Ast.DefStruct]) extends Node final case class DefSystem(node: AstNode[Ast.DefSystem]) extends Node final case class DefTopology(node: AstNode[Ast.DefTopology]) extends Node + final case class DefVector(node: AstNode[Ast.DefVector]) extends Node final case class SpecInclude(node: AstNode[Ast.SpecInclude]) extends Node final case class SpecLoc(node: AstNode[Ast.SpecLoc]) extends Node } @@ -197,6 +210,7 @@ object Ast { final case class DefSignal(node: AstNode[Ast.DefSignal]) extends Node final case class DefState(node: AstNode[Ast.DefState]) extends Node final case class DefStruct(node: AstNode[Ast.DefStruct]) extends Node + final case class DefVector(node: AstNode[Ast.DefVector]) extends Node final case class SpecInclude(node: AstNode[Ast.SpecInclude]) extends Node final case class SpecInitialTransition(node: AstNode[Ast.SpecInitialTransition]) extends Node } diff --git a/compiler/lib/src/main/scala/ast/AstTransformer.scala b/compiler/lib/src/main/scala/ast/AstTransformer.scala index a851eed19..49ecf6576 100644 --- a/compiler/lib/src/main/scala/ast/AstTransformer.scala +++ b/compiler/lib/src/main/scala/ast/AstTransformer.scala @@ -128,6 +128,11 @@ trait AstTransformer { node: Ast.Annotated[AstNode[Ast.DefTopology]] ): ResultAnnotatedNode[Ast.DefTopology] = Right(default(in), node) + def defVectorAnnotatedNode( + in: In, + node: Ast.Annotated[AstNode[Ast.DefVector]] + ): ResultAnnotatedNode[Ast.DefVector] = Right(default(in), node) + def exprArrayNode(in: In, node: AstNode[Ast.Expr], e: Ast.ExprArray): ResultNode[Ast.Expr] = Right(default(in), node) @@ -330,6 +335,8 @@ trait AstTransformer { transform(defStateMachineAnnotatedNode(in, (pre, node1, post)), Ast.ComponentMember.DefStateMachine(_)) case Ast.ComponentMember.DefStruct(node1) => transform(defStructAnnotatedNode(in, (pre, node1, post)), Ast.ComponentMember.DefStruct(_)) + case Ast.ComponentMember.DefVector(node1) => + transform(defVectorAnnotatedNode(in, (pre, node1, post)), Ast.ComponentMember.DefVector(_)) case Ast.ComponentMember.SpecCommand(node1) => transform(specCommandAnnotatedNode(in, (pre, node1, post)), Ast.ComponentMember.SpecCommand(_)) case Ast.ComponentMember.SpecContainer(node1) => @@ -456,6 +463,8 @@ trait AstTransformer { transform(defStateAnnotatedNode(in, (pre, node1, post)), Ast.StateMachineMember.DefState(_)) case Ast.StateMachineMember.DefStruct(node1) => transform(defStructAnnotatedNode(in, (pre, node1, post)), Ast.StateMachineMember.DefStruct(_)) + case Ast.StateMachineMember.DefVector(node1) => + transform(defVectorAnnotatedNode(in, (pre, node1, post)), Ast.StateMachineMember.DefVector(_)) case Ast.StateMachineMember.SpecInclude(node1) => transform(specIncludeAnnotatedNode(in, (pre, node1, post)), Ast.StateMachineMember.SpecInclude(_)) case Ast.StateMachineMember.SpecInitialTransition(node1) => @@ -503,6 +512,8 @@ trait AstTransformer { transform(defSystemAnnotatedNode(in, (pre, node1, post)), Ast.ModuleMember.DefSystem(_)) case Ast.ModuleMember.DefTopology(node1) => transform(defTopologyAnnotatedNode(in, (pre, node1, post)), Ast.ModuleMember.DefTopology(_)) + case Ast.ModuleMember.DefVector(node1) => + transform(defVectorAnnotatedNode(in, (pre, node1, post)), Ast.ModuleMember.DefVector(_)) case Ast.ModuleMember.SpecInclude(node1) => transform(specIncludeAnnotatedNode(in, (pre, node1, post)), Ast.ModuleMember.SpecInclude(_)) case Ast.ModuleMember.SpecLoc(node1) => diff --git a/compiler/lib/src/main/scala/ast/AstVisitor.scala b/compiler/lib/src/main/scala/ast/AstVisitor.scala index 5becb4444..efef9571e 100644 --- a/compiler/lib/src/main/scala/ast/AstVisitor.scala +++ b/compiler/lib/src/main/scala/ast/AstVisitor.scala @@ -62,6 +62,8 @@ trait AstVisitor { def defTopologyAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefTopology]]): Out = default(in) + def defVectorAnnotatedNode(in: In, node: Ast.Annotated[AstNode[Ast.DefVector]]): Out = default(in) + def exprArrayNode(in: In, node: AstNode[Ast.Expr], e: Ast.ExprArray): Out = default(in) def exprArraySubscriptNode(in: In, node: AstNode[Ast.Expr], e: Ast.ExprArraySubscript): Out = default(in) @@ -156,6 +158,7 @@ trait AstVisitor { case Ast.ComponentMember.DefEnum(node1) => defEnumAnnotatedNode(in, (pre, node1, post)) case Ast.ComponentMember.DefStateMachine(node1) => defStateMachineAnnotatedNode(in, (pre, node1, post)) case Ast.ComponentMember.DefStruct(node1) => defStructAnnotatedNode(in, (pre, node1, post)) + case Ast.ComponentMember.DefVector(node1) => defVectorAnnotatedNode(in, (pre, node1, post)) case Ast.ComponentMember.SpecCommand(node1) => specCommandAnnotatedNode(in, (pre, node1, post)) case Ast.ComponentMember.SpecContainer(node1) => specContainerAnnotatedNode(in, (pre, node1, post)) case Ast.ComponentMember.SpecEvent(node1) => specEventAnnotatedNode(in, (pre, node1, post)) @@ -213,6 +216,7 @@ trait AstVisitor { case Ast.ModuleMember.DefStruct(node1) => defStructAnnotatedNode(in, (pre, node1, post)) case Ast.ModuleMember.DefSystem(node1) => defSystemAnnotatedNode(in, (pre, node1, post)) case Ast.ModuleMember.DefTopology(node1) => defTopologyAnnotatedNode(in, (pre, node1, post)) + case Ast.ModuleMember.DefVector(node1) => defVectorAnnotatedNode(in, (pre, node1, post)) case Ast.ModuleMember.SpecInclude(node1) => specIncludeAnnotatedNode(in, (pre, node1, post)) case Ast.ModuleMember.SpecLoc(node1) => specLocAnnotatedNode(in, (pre, node1, post)) } @@ -232,6 +236,7 @@ trait AstVisitor { case Ast.StateMachineMember.DefSignal(node1) => defSignalAnnotatedNode(in, (pre, node1, post)) case Ast.StateMachineMember.DefState(node1) => defStateAnnotatedNode(in, (pre, node1, post)) case Ast.StateMachineMember.DefStruct(node1) => defStructAnnotatedNode(in, (pre, node1, post)) + case Ast.StateMachineMember.DefVector(node1) => defVectorAnnotatedNode(in, (pre, node1, post)) case Ast.StateMachineMember.SpecInclude(node1) => specIncludeAnnotatedNode(in, (pre, node1, post)) case Ast.StateMachineMember.SpecInitialTransition(node1) => specInitialTransitionAnnotatedNode(in, (pre, node1, post)) } diff --git a/compiler/lib/src/main/scala/codegen/AstWriter.scala b/compiler/lib/src/main/scala/codegen/AstWriter.scala index be3d7c343..8556870b7 100644 --- a/compiler/lib/src/main/scala/codegen/AstWriter.scala +++ b/compiler/lib/src/main/scala/codegen/AstWriter.scala @@ -60,6 +60,23 @@ object AstWriter extends AstVisitor with LineUtils { ).map(indentIn) } + override def defVectorAnnotatedNode( + in: In, + aNode: Ast.Annotated[AstNode[Ast.DefVector]] + ) = { + val (_, node, _) = aNode + val data = node.data + prefixWithDictionary("def vector", data.isDictionaryDef) ++ + List.concat( + ident(data.name), + linesOpt(addPrefix("size prefix type", typeNameNode), data.sizePrefixType), + addPrefix("size", exprNode) (data.size), + typeNameNode(data.eltType), + linesOpt(addPrefix("default", exprNode), data.default), + linesOpt(addPrefix("format", applyToData(string)), data.format) + ).map(indentIn) + } + override def defChoiceAnnotatedNode( in: In, aNode: Ast.Annotated[AstNode[Ast.DefChoice]] diff --git a/compiler/lib/src/main/scala/codegen/FppWriter.scala b/compiler/lib/src/main/scala/codegen/FppWriter.scala index 8ad5bbf30..903b3cfe8 100644 --- a/compiler/lib/src/main/scala/codegen/FppWriter.scala +++ b/compiler/lib/src/main/scala/codegen/FppWriter.scala @@ -160,6 +160,27 @@ object FppWriter extends AstVisitor with LineUtils { joinOpt (data.format) (" format ") (applyToData(string)) } + override def defVectorAnnotatedNode( + in: In, + aNode: Ast.Annotated[AstNode[Ast.DefVector]] + ) = { + val (_, node, _) = aNode + val data = node.data + val start = + lines(prefixWithDictionary(s"vector ${ident(data.name)} = [", data.isDictionaryDef)) + val withSize = + data.sizePrefixType match { + case Some(tn) => + start.join ("") (typeNameNode(tn)).join (" size ") (exprNode(data.size)) + case None => + start.join ("size ") (exprNode(data.size)) + } + withSize. + join ("] ") (typeNameNode(data.eltType)). + joinOpt (data.default) (" default ") (exprNode). + joinOpt (data.format) (" format ") (applyToData(string)) + } + override def defChoiceAnnotatedNode( in: In, aNode: Ast.Annotated[AstNode[Ast.DefChoice]] diff --git a/compiler/lib/src/main/scala/syntax/Lexer.scala b/compiler/lib/src/main/scala/syntax/Lexer.scala index d59f46e13..7e615843b 100644 --- a/compiler/lib/src/main/scala/syntax/Lexer.scala +++ b/compiler/lib/src/main/scala/syntax/Lexer.scala @@ -129,6 +129,7 @@ object Lexer { ("type", TYPE), ("unmatched", UNMATCHED), ("update", UPDATE), + ("vector", VECTOR), ("warning", WARNING), ("with", WITH), ("yellow", YELLOW) @@ -359,6 +360,7 @@ object Lexer { case U8 => Token.U8() case UNMATCHED => Token.UNMATCHED() case UPDATE => Token.UPDATE() + case VECTOR => Token.VECTOR() case WARNING => Token.WARNING() case WITH => Token.WITH() case YELLOW => Token.YELLOW() diff --git a/compiler/lib/src/main/scala/syntax/Parser.scala b/compiler/lib/src/main/scala/syntax/Parser.scala index e9ecc7426..ee5deeafb 100644 --- a/compiler/lib/src/main/scala/syntax/Parser.scala +++ b/compiler/lib/src/main/scala/syntax/Parser.scala @@ -34,6 +34,7 @@ object Parser extends Parsers { node(defStateMachine) ^^ (n => Ast.ComponentMember.DefStateMachine(n)) | node(defStruct) ^^ (n => Ast.ComponentMember.DefStruct(n)) | + node(defVector) ^^ (n => Ast.ComponentMember.DefVector(n)) | node(specCommand) ^^ (n => Ast.ComponentMember.SpecCommand(n)) | node(specContainer) ^^ (n => Ast.ComponentMember.SpecContainer(n)) | @@ -101,6 +102,34 @@ object Parser extends Parsers { } } + def defVector: Parser[Ast.DefVector] = { + opt(dictionary) ~ (vector ~>! ident <~! equals) ~! + vectorSize ~! node(typeName) ~! + opt(default ~>! exprNode) ~! + opt(format ~>! node(literalString)) ^^ { + case dictionary ~ name ~ vectorSize ~ eltType ~ default ~ format => + val (size, sizePrefixType) = vectorSize + Ast.DefVector( + name, + size, + sizePrefixType, + eltType, + default, + format, + dictionary.isDefined + ) + } + } + + /** Parses a vector size specifier of the form `[` [ _type-name_ ] `size` + * _expression_ `]`. Returns the maximum-size expression and the optional + * size-prefix type. */ + def vectorSize: Parser[(AstNode[Ast.Expr], Option[AstNode[Ast.TypeName]])] = { + lbracket ~>! (opt(node(typeName)) ~ (size ~>! exprNode)) <~! rbracket ^^ { + case sizePrefixType ~ size => (size, sizePrefixType) + } + } + private def defChoice: Parser[Ast.DefChoice] = { (choice ~> ident) ~! (lbrace ~> ifToken ~> node(ident)) ~! node( transitionExpr @@ -452,6 +481,7 @@ object Parser extends Parsers { node(defStruct) ^^ (n => Ast.ModuleMember.DefStruct(n)) | node(defSystem) ^^ (n => Ast.ModuleMember.DefSystem(n)) | node(defTopology) ^^ (n => Ast.ModuleMember.DefTopology(n)) | + node(defVector) ^^ (n => Ast.ModuleMember.DefVector(n)) | node(specInclude) ^^ (n => Ast.ModuleMember.SpecInclude(n)) | node(specLoc) ^^ (n => Ast.ModuleMember.SpecLoc(n)) | failure("module member expected") @@ -909,6 +939,7 @@ object Parser extends Parsers { node(defSignal) ^^ (n => Ast.StateMachineMember.DefSignal(n)) | node(defState) ^^ (n => Ast.StateMachineMember.DefState(n)) | node(defStruct) ^^ (n => Ast.StateMachineMember.DefStruct(n)) | + node(defVector) ^^ (n => Ast.StateMachineMember.DefVector(n)) | node(specInclude) ^^ (n => Ast.StateMachineMember.SpecInclude(n)) | node(specInitialTransition) ^^ (n => Ast.StateMachineMember.SpecInitialTransition(n)) | failure("state machine member expected") @@ -1365,6 +1396,8 @@ object Parser extends Parsers { private def update = accept("update", { case t: Token.UPDATE => t }) + private def vector = accept("vector", { case t: Token.VECTOR => t }) + private def warning = accept("warning", { case t: Token.WARNING => t }) private def yellow = accept("yellow", { case t: Token.YELLOW => t }) diff --git a/compiler/lib/src/main/scala/syntax/Token.scala b/compiler/lib/src/main/scala/syntax/Token.scala index 820f9fac6..9e161fc24 100644 --- a/compiler/lib/src/main/scala/syntax/Token.scala +++ b/compiler/lib/src/main/scala/syntax/Token.scala @@ -145,6 +145,7 @@ object Token { final case class U8() extends Token final case class UNMATCHED() extends Token final case class UPDATE() extends Token + final case class VECTOR() extends Token final case class WARNING() extends Token final case class WITH() extends Token final case class YELLOW() extends Token @@ -279,6 +280,7 @@ enum TokenId { case U8 case UNMATCHED case UPDATE + case VECTOR case WARNING case WITH case YELLOW diff --git a/compiler/lib/src/test/scala/syntax/Parser.scala b/compiler/lib/src/test/scala/syntax/Parser.scala index 1780e7446..4f69c3841 100644 --- a/compiler/lib/src/test/scala/syntax/Parser.scala +++ b/compiler/lib/src/test/scala/syntax/Parser.scala @@ -80,6 +80,36 @@ class ParserSpec extends AnyWordSpec { ) } + "def vector OK" should { + parseAllOK( + Parser.defVector, + List( + "vector v = [size 10] U32", + "vector v = [size 10] U32 default [ 1, 2 ]", + "vector v = [size 10] U32 default [ 1, 2 ] format \"{} counts\"", + "vector v = [U16 size 10] U32", + "vector v = [a.b.C size 10] U32", + "dictionary vector v = [U8 size 10] U32" + ) + ) + } + + "def vector error" should { + parseAllError( + Parser.defVector, + List( + // Missing the size keyword + "vector v = [10] U32", + // Missing the size expression + "vector v = [size] U32", + // Size-prefix type without the size keyword + "vector v = [U16 10] U32", + // Size-prefix type with missing size expression + "vector v = [U16 size] U32" + ) + ) + } + "def component OK" should { parseAllOK( Parser.defComponent, diff --git a/compiler/tools/fpp-format/test/include.ref.txt b/compiler/tools/fpp-format/test/include.ref.txt index 064e938b6..c8dc0c851 100644 --- a/compiler/tools/fpp-format/test/include.ref.txt +++ b/compiler/tools/fpp-format/test/include.ref.txt @@ -14,6 +14,15 @@ module DefinitionsAndSpecifiers { @ Array definition array A = [10] U32 default 0 format "{} counts" @< Array definition + @ Vector definition with default size-prefix type + vector V = [size 10] U32 @< Vector definition with default size-prefix type + + @ Vector definition with explicit size-prefix type + vector W = [U16 size 10] U32 default [ + 1 + 2 + ] format "{} counts" @< Vector definition with explicit size-prefix type + @ State machine outside a component state machine SO @< State machine outside a component diff --git a/compiler/tools/fpp-format/test/no_include.ref.txt b/compiler/tools/fpp-format/test/no_include.ref.txt index edf5642e6..3c9309370 100644 --- a/compiler/tools/fpp-format/test/no_include.ref.txt +++ b/compiler/tools/fpp-format/test/no_include.ref.txt @@ -14,6 +14,15 @@ module DefinitionsAndSpecifiers { @ Array definition array A = [10] U32 default 0 format "{} counts" @< Array definition + @ Vector definition with default size-prefix type + vector V = [size 10] U32 @< Vector definition with default size-prefix type + + @ Vector definition with explicit size-prefix type + vector W = [U16 size 10] U32 default [ + 1 + 2 + ] format "{} counts" @< Vector definition with explicit size-prefix type + @ State machine outside a component state machine SO @< State machine outside a component diff --git a/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt b/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt index eafd0cb6c..f38344aae 100644 --- a/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-ast.ref.txt @@ -24,6 +24,23 @@ def module default literal int 0 format {} counts @< Array definition + @ Vector definition with default size-prefix type + def vector + ident V + size literal int 10 + type name U32 + @< Vector definition with default size-prefix type + @ Vector definition with explicit size-prefix type + def vector + ident W + size prefix type type name U16 + size literal int 10 + type name U32 + default expr array + literal int 1 + literal int 2 + format {} counts + @< Vector definition with explicit size-prefix type @ State machine outside a component def state machine ident SO diff --git a/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt b/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt index 29c54865b..a98a783e6 100644 --- a/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-include-ast.ref.txt @@ -24,6 +24,23 @@ def module default literal int 0 format {} counts @< Array definition + @ Vector definition with default size-prefix type + def vector + ident V + size literal int 10 + type name U32 + @< Vector definition with default size-prefix type + @ Vector definition with explicit size-prefix type + def vector + ident W + size prefix type type name U16 + size literal int 10 + type name U32 + default expr array + literal int 1 + literal int 2 + format {} counts + @< Vector definition with explicit size-prefix type @ State machine outside a component def state machine ident SO diff --git a/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt b/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt index 29c54865b..a98a783e6 100644 --- a/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt +++ b/compiler/tools/fpp-syntax/test/syntax-stdin.ref.txt @@ -24,6 +24,23 @@ def module default literal int 0 format {} counts @< Array definition + @ Vector definition with default size-prefix type + def vector + ident V + size literal int 10 + type name U32 + @< Vector definition with default size-prefix type + @ Vector definition with explicit size-prefix type + def vector + ident W + size prefix type type name U16 + size literal int 10 + type name U32 + default expr array + literal int 1 + literal int 2 + format {} counts + @< Vector definition with explicit size-prefix type @ State machine outside a component def state machine ident SO diff --git a/compiler/tools/fpp-syntax/test/syntax.fpp b/compiler/tools/fpp-syntax/test/syntax.fpp index 694cd0e75..45c27019f 100644 --- a/compiler/tools/fpp-syntax/test/syntax.fpp +++ b/compiler/tools/fpp-syntax/test/syntax.fpp @@ -16,6 +16,14 @@ module DefinitionsAndSpecifiers { array A = [10] U32 default 0 format "{} counts" @< Array definition + @ Vector definition with default size-prefix type + vector V = [size 10] U32 + @< Vector definition with default size-prefix type + + @ Vector definition with explicit size-prefix type + vector W = [U16 size 10] U32 default [ 1, 2 ] format "{} counts" + @< Vector definition with explicit size-prefix type + @ State machine outside a component state machine SO @< State machine outside a component