diff --git a/compiler/lib/src/main/scala/analysis/Analyzers/TypeExpressionAnalyzer.scala b/compiler/lib/src/main/scala/analysis/Analyzers/TypeExpressionAnalyzer.scala index e9a2b8b28..56fdd8d7b 100644 --- a/compiler/lib/src/main/scala/analysis/Analyzers/TypeExpressionAnalyzer.scala +++ b/compiler/lib/src/main/scala/analysis/Analyzers/TypeExpressionAnalyzer.scala @@ -52,14 +52,12 @@ trait TypeExpressionAnalyzer override def defActionAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.DefAction]]) = { val (_, node, _) = aNode - val data = node.data opt(typeNameNode)(a, node.data.typeName) } override def defAliasTypeAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.DefAliasType]]) = { val (_, node1, _) = node - val data = node1.data - typeNameNode(a, data.typeName) + typeNameNode(a, node1.data.typeName) } override def defArrayAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.DefArray]]) = { diff --git a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckUseDefCycles.scala b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckUseDefCycles.scala index 3676d2dd7..ab4d75a4f 100644 --- a/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckUseDefCycles.scala +++ b/compiler/lib/src/main/scala/analysis/CheckSemantics/CheckUseDefCycles.scala @@ -9,6 +9,11 @@ object CheckUseDefCycles extends UseAnalyzer { override def constantUse(a: Analysis, node: AstNode[Ast.Expr], use: Name.Qualified) = visitUse(a, node, use) + override def defAliasTypeAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.DefAliasType]]) = { + val symbol = Symbol.AliasType(node) + visitDefPost(a, symbol, node, super.defAliasTypeAnnotatedNode) + } + override def defArrayAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.DefArray]]) = { val symbol = Symbol.Array(node) visitDefPost(a, symbol, node, super.defArrayAnnotatedNode) @@ -56,6 +61,7 @@ object CheckUseDefCycles extends UseAnalyzer { private def visitDefPre(a: Analysis, symbol: Symbol): Result = { symbol match { + case Symbol.AliasType(node) => defAliasTypeAnnotatedNode(a, node) case Symbol.Array(node) => defArrayAnnotatedNode(a, node) case Symbol.Constant(node) => defConstantAnnotatedNode(a, node) case Symbol.Enum(node) => defEnumAnnotatedNode(a, node) diff --git a/compiler/lib/src/main/scala/analysis/Semantics/Value.scala b/compiler/lib/src/main/scala/analysis/Semantics/Value.scala index bee9706dc..91b6721da 100644 --- a/compiler/lib/src/main/scala/analysis/Semantics/Value.scala +++ b/compiler/lib/src/main/scala/analysis/Semantics/Value.scala @@ -22,7 +22,7 @@ sealed trait Value { /** Convert this value to a type */ final def convertToType(t: Type): Option[Value] = { - if (Type.areIdentical(getType, t)) + if (Type.areIdentical(getType, t.getUnderlyingType)) Some(this) else convertToDistinctType(t) } @@ -125,7 +125,7 @@ object Value { } override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case Type.PrimitiveInt(kind1) => Some(PrimitiveInt(value, kind1)) case Type.Integer => Some(Integer(value)) case Type.Float(kind1) => Some(Float(value.doubleValue, kind1)) @@ -185,7 +185,7 @@ object Value { } override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case Type.PrimitiveInt(kind1) => Some(PrimitiveInt(value, kind1)) case Type.Integer => Some(Integer(value)) case Type.Float(kind1) => Some(Float(value.doubleValue, kind1)) @@ -229,7 +229,7 @@ object Value { override def isZero = (Math.abs(value) < Float.EPSILON) override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case Type.PrimitiveInt(kind1) => Some(PrimitiveInt(value.intValue, kind1)) case Type.Integer => Some(Integer(value.intValue)) case Type.Float(kind1) => Some(Float(value, kind1)) @@ -258,7 +258,7 @@ object Value { /** Boolean values */ case class Boolean(value: scala.Boolean) extends Value { - override def convertToDistinctType(t: Type) = promoteToAggregate(t) + override def convertToDistinctType(t: Type) = promoteToAggregate(t.getUnderlyingType) override def getType = Type.Boolean @@ -270,7 +270,7 @@ object Value { case class String(value: java.lang.String) extends Value { override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case Type.String(_) => Some(this) case _ => promoteToAggregate(t) } @@ -288,8 +288,8 @@ object Value { def convertElements(in: List[Value], t: Type, out: List[Value]): Option[List[Value]] = in match { case Nil => Some(out.reverse) - case head :: tail => head.convertToType(t) match { - case Some(v) => convertElements(tail, t, v :: out) + case head :: tail => head.convertToType(t.getUnderlyingType) match { + case Some(v) => convertElements(tail, t.getUnderlyingType, v :: out) case None => None } } @@ -307,7 +307,7 @@ object Value { } override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case anonArrayType : Type.AnonArray => convertToAnonArray(anonArrayType) case arrayType : Type.Array => convertToArray(arrayType) case _ => None @@ -340,7 +340,7 @@ object Value { anonArray.convertToArray(arrayType) override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case anonArrayType : Type.AnonArray => convertToAnonArray(anonArrayType) case arrayType : Type.Array => convertToArray(arrayType) case _ => None @@ -363,7 +363,7 @@ object Value { def convertToRepType: PrimitiveInt = PrimitiveInt(value._2, t.repType.kind) override def convertToDistinctType(t: Type) = - convertToRepType.convertToDistinctType(t) match { + convertToRepType.convertToDistinctType(t.getUnderlyingType) match { case Some(v) => Some(v) case None => promoteToAggregate(t) } @@ -407,7 +407,7 @@ object Value { } override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case anonStructType : Type.AnonStruct => convertToAnonStruct(anonStructType) case structType : Type.Struct => convertToStruct(structType) case _ => None @@ -445,7 +445,7 @@ object Value { def convertToStruct(structType: Type.Struct): Option[Value.Struct] = anonStruct.convertToStruct(structType) override def convertToDistinctType(t: Type) = - t match { + t.getUnderlyingType match { case anonStructType : Type.AnonStruct => convertToAnonStruct(anonStructType) case structType : Type.Struct => convertToStruct(structType) case _ => None diff --git a/compiler/tools/fpp-check/test/cycle/alias.fpp b/compiler/tools/fpp-check/test/cycle/alias.fpp new file mode 100644 index 000000000..86c3ba616 --- /dev/null +++ b/compiler/tools/fpp-check/test/cycle/alias.fpp @@ -0,0 +1,8 @@ +type TStructCycle = SSCycle + +struct SSCycle { + F1: string + F2: U32 + F3: bool + F4: TStructCycle +} diff --git a/compiler/tools/fpp-check/test/cycle/alias.ref.txt b/compiler/tools/fpp-check/test/cycle/alias.ref.txt new file mode 100644 index 000000000..5c4aba7ca --- /dev/null +++ b/compiler/tools/fpp-check/test/cycle/alias.ref.txt @@ -0,0 +1,7 @@ +fpp-check +[ local path prefix ]/compiler/tools/fpp-check/test/cycle/alias.fpp:1.1 +type TStructCycle = SSCycle +^ +error: encountered a use-def cycle: + use SSCycle at [ local path prefix ]/compiler/tools/fpp-check/test/cycle/alias.fpp:1.21 refers to definition SSCycle at [ local path prefix ]/compiler/tools/fpp-check/test/cycle/alias.fpp:3.1 + use TStructCycle at [ local path prefix ]/compiler/tools/fpp-check/test/cycle/alias.fpp:7.9 refers to definition TStructCycle at [ local path prefix ]/compiler/tools/fpp-check/test/cycle/alias.fpp:1.1 diff --git a/compiler/tools/fpp-check/test/cycle/tests.sh b/compiler/tools/fpp-check/test/cycle/tests.sh index 5e481746d..68fc82f80 100644 --- a/compiler/tools/fpp-check/test/cycle/tests.sh +++ b/compiler/tools/fpp-check/test/cycle/tests.sh @@ -1,4 +1,5 @@ tests=" +alias array constant_1 constant_2 diff --git a/compiler/tools/fpp-check/test/type/alias_type_ok.fpp b/compiler/tools/fpp-check/test/type/alias_type_ok.fpp new file mode 100644 index 000000000..53c83c8b1 --- /dev/null +++ b/compiler/tools/fpp-check/test/type/alias_type_ok.fpp @@ -0,0 +1,33 @@ +enum E1T { + E1 = 0 + E2 = 1 + E3 = 3 +} + +struct SS { + F1: string + F2: U32 + F3: bool +} + +type TU = U32 +type TS = string size 20 +type TE = E1T +type TB = bool +type TStruct = SS + +constant B = false + +array A1 = [2] TB default [B, B] +array A2 = [2] TE default [E1T.E1, E1T.E2] +array A3 = [2] TU default [1, 2] +array A4 = [2] TS default ["1", "2"] +array A5 = [2] TStruct default [{ + F1 = "test", + F2 = 1, + F3 = false, +}, { + F1 = "test2", + F2 = 2, + F3 = true, +}] diff --git a/compiler/tools/fpp-check/test/type/alias_type_ok.ref.txt b/compiler/tools/fpp-check/test/type/alias_type_ok.ref.txt new file mode 100644 index 000000000..e69de29bb diff --git a/compiler/tools/fpp-check/test/type/tests.sh b/compiler/tools/fpp-check/test/type/tests.sh index 23a290942..ed22dd524 100644 --- a/compiler/tools/fpp-check/test/type/tests.sh +++ b/compiler/tools/fpp-check/test/type/tests.sh @@ -1,4 +1,5 @@ tests=" +alias_type_ok string_size_negative string_size_not_numeric string_size_too_large diff --git a/compiler/tools/fpp-to-cpp/test/array/AliasTypeArrayAc.ref.cpp b/compiler/tools/fpp-to-cpp/test/array/AliasTypeArrayAc.ref.cpp new file mode 100644 index 000000000..9f6a83d35 --- /dev/null +++ b/compiler/tools/fpp-to-cpp/test/array/AliasTypeArrayAc.ref.cpp @@ -0,0 +1,191 @@ +// ====================================================================== +// \title AliasTypeArrayAc.cpp +// \author Generated by fpp-to-cpp +// \brief cpp file for AliasType array +// ====================================================================== + +#include "AliasTypeArrayAc.hpp" +#include "Fw/Types/Assert.hpp" + +// ---------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------- + +AliasType :: + AliasType() : + Serializable() +{ + // Construct using element-wise constructor + *this = AliasType( + 0, + 2, + 3 + ); +} + +AliasType :: + AliasType(const ElementType (&a)[SIZE]) : + Serializable() +{ + for (U32 index = 0; index < SIZE; index++) { + this->elements[index] = a[index]; + } +} + +AliasType :: + AliasType(const ElementType& e) : + Serializable() +{ + for (U32 index = 0; index < SIZE; index++) { + this->elements[index] = e; + } +} + +AliasType :: + AliasType( + const ElementType& e1, + const ElementType& e2, + const ElementType& e3 + ) : + Serializable() +{ + this->elements[0] = e1; + this->elements[1] = e2; + this->elements[2] = e3; +} + +AliasType :: + AliasType(const AliasType& obj) : + Serializable() +{ + for (U32 index = 0; index < SIZE; index++) { + this->elements[index] = obj.elements[index]; + } +} + +// ---------------------------------------------------------------------- +// Operators +// ---------------------------------------------------------------------- + +AliasType::ElementType& AliasType :: + operator[](const U32 i) +{ + FW_ASSERT(i < SIZE, static_cast(i), static_cast(SIZE)); + return this->elements[i]; +} + +const AliasType::ElementType& AliasType :: + operator[](const U32 i) const +{ + FW_ASSERT(i < SIZE, static_cast(i), static_cast(SIZE)); + return this->elements[i]; +} + +AliasType& AliasType :: + operator=(const AliasType& obj) +{ + if (this == &obj) { + return *this; + } + + for (U32 index = 0; index < SIZE; index++) { + this->elements[index] = obj.elements[index]; + } + return *this; +} + +AliasType& AliasType :: + operator=(const ElementType (&a)[SIZE]) +{ + for (U32 index = 0; index < SIZE; index++) { + this->elements[index] = a[index]; + } + return *this; +} + +AliasType& AliasType :: + operator=(const ElementType& e) +{ + for (U32 index = 0; index < SIZE; index++) { + this->elements[index] = e; + } + return *this; +} + +bool AliasType :: + operator==(const AliasType& obj) const +{ + for (U32 index = 0; index < SIZE; index++) { + if (!((*this)[index] == obj[index])) { + return false; + } + } + return true; +} + +bool AliasType :: + operator!=(const AliasType& obj) const +{ + return !(*this == obj); +} + +#ifdef BUILD_UT + +std::ostream& operator<<(std::ostream& os, const AliasType& obj) { + Fw::String s; + obj.toString(s); + os << s; + return os; +} + +#endif + +// ---------------------------------------------------------------------- +// Public member functions +// ---------------------------------------------------------------------- + +Fw::SerializeStatus AliasType :: + serialize(Fw::SerializeBufferBase& buffer) const +{ + Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; + for (U32 index = 0; index < SIZE; index++) { + status = buffer.serialize((*this)[index]); + if (status != Fw::FW_SERIALIZE_OK) { + return status; + } + } + return status; +} + +Fw::SerializeStatus AliasType :: + deserialize(Fw::SerializeBufferBase& buffer) +{ + Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; + for (U32 index = 0; index < SIZE; index++) { + status = buffer.deserialize((*this)[index]); + if (status != Fw::FW_SERIALIZE_OK) { + return status; + } + } + return status; +} + +#if FW_SERIALIZABLE_TO_STRING + +void AliasType :: + toString(Fw::StringBase& sb) const +{ + static const char *formatString = "[ " + "%s " + "%s " + "%s ]"; + + sb.format( + formatString, + this->elements[0], + this->elements[1], + this->elements[2] + ); +} + +#endif diff --git a/compiler/tools/fpp-to-cpp/test/array/AliasTypeArrayAc.ref.hpp b/compiler/tools/fpp-to-cpp/test/array/AliasTypeArrayAc.ref.hpp new file mode 100644 index 000000000..bf4891ee6 --- /dev/null +++ b/compiler/tools/fpp-to-cpp/test/array/AliasTypeArrayAc.ref.hpp @@ -0,0 +1,162 @@ +// ====================================================================== +// \title AliasTypeArrayAc.hpp +// \author Generated by fpp-to-cpp +// \brief hpp file for AliasType array +// ====================================================================== + +#ifndef AliasTypeArrayAc_HPP +#define AliasTypeArrayAc_HPP + +#include "FpConfig.hpp" +#include "Fw/Types/ExternalString.hpp" +#include "Fw/Types/Serializable.hpp" +#include "Fw/Types/String.hpp" + +//! An array of abstract type +class AliasType : + public Fw::Serializable +{ + + public: + + // ---------------------------------------------------------------------- + // Types + // ---------------------------------------------------------------------- + + //! The element type + using ElementType = U32; + + public: + + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + enum { + //! The size of the array + SIZE = 3, + //! The serialized size of each element + ELEMENT_SERIALIZED_SIZE = sizeof(U32), + //! The size of the serial representation + SERIALIZED_SIZE = SIZE * ELEMENT_SERIALIZED_SIZE + }; + + public: + + // ---------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------- + + //! Constructor (default value) + AliasType(); + + //! Constructor (user-provided value) + AliasType( + const ElementType (&a)[SIZE] //!< The array + ); + + //! Constructor (single element) + AliasType( + const ElementType& e //!< The element + ); + + //! Constructor (multiple elements) + AliasType( + const ElementType& e1, //!< Element 1 + const ElementType& e2, //!< Element 2 + const ElementType& e3 //!< Element 3 + ); + + //! Copy Constructor + AliasType( + const AliasType& obj //!< The source object + ); + + public: + + // ---------------------------------------------------------------------- + // Operators + // ---------------------------------------------------------------------- + + //! Subscript operator + ElementType& operator[]( + const U32 i //!< The subscript index + ); + + //! Const subscript operator + const ElementType& operator[]( + const U32 i //!< The subscript index + ) const; + + //! Copy assignment operator (object) + AliasType& operator=( + const AliasType& obj //!< The source object + ); + + //! Copy assignment operator (raw array) + AliasType& operator=( + const ElementType (&a)[SIZE] //!< The source array + ); + + //! Copy assignment operator (single element) + AliasType& operator=( + const ElementType& e //!< The element + ); + + //! Equality operator + bool operator==( + const AliasType& obj //!< The other object + ) const; + + //! Inequality operator + bool operator!=( + const AliasType& obj //!< The other object + ) const; + +#ifdef BUILD_UT + + //! Ostream operator + friend std::ostream& operator<<( + std::ostream& os, //!< The ostream + const AliasType& obj //!< The object + ); + +#endif + + public: + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Serialization + Fw::SerializeStatus serialize( + Fw::SerializeBufferBase& buffer //!< The serial buffer + ) const; + + //! Deserialization + Fw::SerializeStatus deserialize( + Fw::SerializeBufferBase& buffer //!< The serial buffer + ); + +#if FW_SERIALIZABLE_TO_STRING + + //! Convert array to string + void toString( + Fw::StringBase& sb //!< The StringBase object to hold the result + ) const; + +#endif + + private: + + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The array elements + ElementType elements[SIZE]; + +}; + +#endif diff --git a/compiler/tools/fpp-to-cpp/test/array/alias_type.fpp b/compiler/tools/fpp-to-cpp/test/array/alias_type.fpp new file mode 100644 index 000000000..08a8accfa --- /dev/null +++ b/compiler/tools/fpp-to-cpp/test/array/alias_type.fpp @@ -0,0 +1,4 @@ +type AT = U32 + +@ An array of abstract type +array AliasType = [3] AT default [0, 2, 3] diff --git a/compiler/tools/fpp-to-cpp/test/array/alias_type.ref.txt b/compiler/tools/fpp-to-cpp/test/array/alias_type.ref.txt new file mode 100644 index 000000000..e69de29bb diff --git a/compiler/tools/fpp-to-cpp/test/array/run.sh b/compiler/tools/fpp-to-cpp/test/array/run.sh index 004ce88ea..2d2e813e4 100644 --- a/compiler/tools/fpp-to-cpp/test/array/run.sh +++ b/compiler/tools/fpp-to-cpp/test/array/run.sh @@ -1,3 +1,43 @@ +abs_type() +{ + run_test "-p $PWD" abs_type && \ + diff_cpp AbsTypeArray +} + +alias_type() +{ + run_test "-p $PWD" alias_type && \ + diff_cpp AliasTypeArray +} + +builtin_type() +{ + run_test "-p $PWD" builtin_type && \ + diff_cpp BuiltInTypeArray +} + +component() +{ + run_test "-p $PWD" component && \ + diff_cpp C_AArray && \ + diff_cpp AArray +} + +enum() +{ + run_test "-p $PWD" enum && \ + diff_cpp E1Enum && \ + diff_cpp E2Enum && \ + diff_cpp Enum1Array && \ + diff_cpp Enum2Array +} + +header_path() +{ + run_test "-p $PWD" "include/T.fpp header_path" header_path && \ + diff_cpp HeaderPathArray +} + primitive() { run_test "-p $PWD" primitive && \ @@ -12,6 +52,12 @@ primitive() diff_cpp PrimitiveArrayArray } +single_element() +{ + run_test "-p $PWD" single_element && \ + diff_cpp SingleElementArray +} + string() { run_test "-p $PWD" string && \ @@ -20,27 +66,6 @@ string() diff_cpp StringArrayArray } -enum() -{ - run_test "-p $PWD" enum && \ - diff_cpp E1Enum && \ - diff_cpp E2Enum && \ - diff_cpp Enum1Array && \ - diff_cpp Enum2Array -} - -builtin_type() -{ - run_test "-p $PWD" builtin_type && \ - diff_cpp BuiltInTypeArray -} - -abs_type() -{ - run_test "-p $PWD" abs_type && \ - diff_cpp AbsTypeArray -} - struct() { run_test "-p $PWD" struct && \ @@ -52,21 +77,3 @@ struct() diff_cpp S3Serializable } -component() -{ - run_test "-p $PWD" component && \ - diff_cpp C_AArray && \ - diff_cpp AArray -} - -header_path() -{ - run_test "-p $PWD" "include/T.fpp header_path" header_path && \ - diff_cpp HeaderPathArray -} - -single_element() -{ - run_test "-p $PWD" single_element && \ - diff_cpp SingleElementArray -} diff --git a/compiler/tools/fpp-to-cpp/test/array/tests.sh b/compiler/tools/fpp-to-cpp/test/array/tests.sh index 6f4512f9d..91224ad41 100644 --- a/compiler/tools/fpp-to-cpp/test/array/tests.sh +++ b/compiler/tools/fpp-to-cpp/test/array/tests.sh @@ -1,12 +1,13 @@ tests=" -duplicate -primitive -string -enum -builtin_type abs_type -struct +alias_type +builtin_type component +duplicate +enum header_path +primitive single_element +string +struct " diff --git a/compiler/tools/fpp-to-cpp/test/array/update-ref.sh b/compiler/tools/fpp-to-cpp/test/array/update-ref.sh index b55d1b703..1bbd50434 100644 --- a/compiler/tools/fpp-to-cpp/test/array/update-ref.sh +++ b/compiler/tools/fpp-to-cpp/test/array/update-ref.sh @@ -1,3 +1,43 @@ +abs_type() +{ + update "-p $PWD" abs_type + move_cpp AbsTypeArray +} + +alias_type() +{ + update "-p $PWD" alias_type + move_cpp AliasTypeArray +} + +builtin_type() +{ + update "-p $PWD" builtin_type + move_cpp BuiltInTypeArray +} + +component() +{ + update "-p $PWD" component + move_cpp C_AArray + move_cpp AArray +} + +enum() +{ + update "-p $PWD" enum + move_cpp E1Enum + move_cpp E2Enum + move_cpp Enum1Array + move_cpp Enum2Array +} + +header_path() +{ + update "-p $PWD" "include/T.fpp header_path" header_path + move_cpp HeaderPathArray +} + primitive() { update "-p $PWD" primitive @@ -12,33 +52,18 @@ primitive() move_cpp PrimitiveArrayArray } -string() -{ - update "-p $PWD" string - move_cpp String1Array - move_cpp String2Array - move_cpp StringArrayArray -} - -enum() -{ - update "-p $PWD" enum - move_cpp E1Enum - move_cpp E2Enum - move_cpp Enum1Array - move_cpp Enum2Array -} - -builtin_type() +single_element() { - update "-p $PWD" builtin_type - move_cpp BuiltInTypeArray + update "-p $PWD" single_element + move_cpp SingleElementArray } -abs_type() +string() { - update "-p $PWD" abs_type - move_cpp AbsTypeArray + update "-p $PWD" string + move_cpp String1Array + move_cpp String2Array + move_cpp StringArrayArray } struct() @@ -52,21 +77,3 @@ struct() move_cpp S3Serializable } -component() -{ - update "-p $PWD" component - move_cpp C_AArray - move_cpp AArray -} - -header_path() -{ - update "-p $PWD" "include/T.fpp header_path" header_path - move_cpp HeaderPathArray -} - -single_element() -{ - update "-p $PWD" single_element - move_cpp SingleElementArray -}