Skip to content

Commit

Permalink
Add enum type to daml-lf (digital-asset#1397)
Browse files Browse the repository at this point in the history
* add enum type to daml-lf dev

* Address Francesco's comments

* Address Martin's comments

* fix daml-lf proto version history
  • Loading branch information
remyhaemmerle-da authored and mergify[bot] committed May 29, 2019
1 parent 9a0e1ac commit f84e7d7
Show file tree
Hide file tree
Showing 55 changed files with 493 additions and 166 deletions.
6 changes: 6 additions & 0 deletions compiler/daml-lf-proto/src/DA/Daml/LF/Proto3/DecodeV1.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ decodeDataCons = \case
DataRecord <$> mapM (decodeFieldWithType FieldName) (V.toList fs)
LF1.DefDataTypeDataConsVariant (LF1.DefDataType_Fields fs) ->
DataVariant <$> mapM (decodeFieldWithType VariantConName) (V.toList fs)
LF1.DefDataTypeDataConsEnum _ ->
-- FixMe (RH) https://github.com/digital-asset/daml/issues/105
Left (ParseError "Enum type not supported")

decodeDefValueNameWithType :: LF1.DefValue_NameWithType -> Decode (ExprValName, Type)
decodeDefValueNameWithType LF1.DefValue_NameWithType{..} = (,)
Expand Down Expand Up @@ -289,6 +292,9 @@ decodeExprSum exprSum = mayDecode "exprSum" exprSum $ \case
<$> mayDecode "Expr_VariantConTycon" mbTycon decodeTypeConApp
<*> decodeName VariantConName variant
<*> mayDecode "Expr_VariantConVariantArg" mbArg decodeExpr
LF1.ExprSumEnumCon _ ->
-- FixMe (RH) https://github.com/digital-asset/daml/issues/105
Left (ParseError "Enum types not supported")
LF1.ExprSumTupleCon (LF1.Expr_TupleCon fields) ->
ETupleCon
<$> mapM decodeFieldWithExpr (V.toList fields)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,8 @@ prettyValue' showRecordType prec world (Value (Just vsum)) = case vsum of
ValueSumVariant (Variant mbVariantId ctor mbValue) ->
prettyMay "" (\v -> prettyDefName world v <> ":") mbVariantId <> ltext ctor
<-> prettyMay "<missing value>" (prettyValue' True precHighest world) mbValue
ValueSumEnum (Enum mbEnumId constructor) ->
prettyMay "" (\x -> prettyDefName world x <> ":") mbEnumId <> ltext constructor
ValueSumList (List elems) ->
brackets (fcommasep (mapV (prettyValue' True prec world) elems))
ValueSumContractId coid -> prettyContractId coid
Expand Down
6 changes: 6 additions & 0 deletions compiler/scenario-service/protos/scenario_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@ message Variant {
Value value = 3;
}

message Enum {
Identifier enum_id = 1;
string constructor = 2;
}

message List {
repeated Value elements = 1;
}
Expand Down Expand Up @@ -298,6 +303,7 @@ message Value {
int32 date = 13;
Optional optional = 15;
Map map = 16;
Enum enum = 17;

// An unserializable value, e.g. closure. Contains a description of the value.
string unserializable = 14;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -590,13 +590,17 @@ case class Conversions(homePackageId: Ref.PackageId) {
)
case V.ValueVariant(tycon, variant, value) =>
val vbuilder = Variant.newBuilder
tycon.map(x => vbuilder.setVariantId(convertIdentifier(x)))
tycon.foreach(x => vbuilder.setVariantId(convertIdentifier(x)))
builder.setVariant(
vbuilder
.setConstructor(variant)
.setValue(convertValue(value))
.build
)
case V.ValueEnum(tycon, constructor) =>
val eBuilder = Enum.newBuilder.setConstructor(constructor)
tycon.foreach(x => eBuilder.setEnumId(convertIdentifier(x)))
builder.setEnum(eBuilder.build)
case V.ValueContractId(coid) =>
coid match {
case V.AbsoluteContractId(acoid) =>
Expand Down
38 changes: 36 additions & 2 deletions daml-lf/archive/da/daml_lf_1.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
// * 5 -- 2019-05-22: Relax serializability constraints for contract ids
// 2019-05-23: Add BuiltinFunction.COERCE_CONTRACT_ID
// 2019-05-24: Make actors in exercise optional
// * dev (special staging area for the next version to be released)
// 2019-05-27: Add enum type.


syntax = "proto3";
Expand Down Expand Up @@ -530,6 +532,17 @@ message Expr {
Expr variant_arg = 3;
}

// Enum construction ('ExpEnumCon')
message EnumCon {

// Name of the type constructor name
TypeConName tycon = 1;

// name of the enum constructor
// *Must be a valid identifier*
string enum_con = 2;
}

// Tuple Construction ('ExpTupleCon')
message TupleCon {
// Field names and their associated values.
Expand Down Expand Up @@ -680,6 +693,9 @@ message Expr {
// Variant construction ('ExpVariantCon')
VariantCon variant_con = 8;

// Enum construction ('ExpEnumCon')
EnumCon enum_con = 28;

// Tuple construction ('ExpTupleCon')
TupleCon tuple_con = 9;

Expand Down Expand Up @@ -750,6 +766,17 @@ message CaseAlt {
string binder = 3;
}

// Enum pattern
message Enum {

// name of the type constructor
TypeConName con = 1;

// name of the variant constructor
// *Must be a valid identifier*
string constructors = 2;
}

// Non empty list pattern
message Cons {
// name of the binder for the head
Expand Down Expand Up @@ -818,7 +845,8 @@ message Update {
string choice = 2;
// contract id
Expr cid = 3;
// actors, optional since DAML-LF 1.5
// actors
// *optional since DAML-LF 1.5*
Expr actor = 4;
// argument
Expr arg = 5;
Expand Down Expand Up @@ -1018,18 +1046,24 @@ message DefTemplate {
// Data type definition
message DefDataType {
message Fields {
repeated FieldWithType fields = 1; // *must be non-empty*
repeated FieldWithType fields = 1;
}

message EnumConstructor {
repeated string constructors = 1;
}

// name of the defined data type
DottedName name = 1;

// type parameters
// *Must be empty if enum field is set*
repeated TypeVarWithKind params = 2;

oneof DataCons {
Fields record = 3; // Records without fields are explicitly allowed.
Fields variant = 4; // Variants without constructors are explicitly allowed.
EnumConstructor enum = 7; // *available since version dev*
}

// If true, this data type preserves serializability in the sense that when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ object PackageLookup {
Right((dataTyp.params, rec))
case _: DataVariant =>
Left(Error(s"Expecting record for identifier $identifier, got variant"))
case _: DataEnum =>
Left(Error(s"Expecting record for identifier $identifier, got enum"))
}
}

Expand All @@ -42,6 +44,21 @@ object PackageLookup {
Right((dataTyp.params, v))
case _: DataRecord =>
Left(Error(s"Expecting variant for identifier $identifier, got record"))
case _: DataEnum =>
Left(Error(s"Expecting variant for identifier $identifier, got enum"))
}
}

def lookupEnum(pkg: Package, identifier: QualifiedName): Either[Error, DataEnum] =
lookupDataType(pkg, identifier).flatMap { dataTyp =>
dataTyp.cons match {
case v: DataEnum =>
Right(v)
case _: DataVariant =>
Left(Error(s"Expecting enum for identifier $identifier, got variant"))
case _: DataRecord =>
Left(Error(s"Expecting enum for identifier $identifier, got record"))

}
}

Expand All @@ -53,7 +70,9 @@ object PackageLookup {
case DataRecord(_, None) =>
Left(Error(s"Got record with no template when looking up $identifier"))
case _: DataVariant =>
Left(Error(s"Got variant when looking up $identifier -- variants can't be templates"))
Left(Error(s"Expecting template for identifier $identifier, got variant"))
case _: DataEnum =>
Left(Error(s"Expecting template for identifier $identifier, got enum"))
}
} yield tpl
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ object DefDataType {
sealed trait DataType[+RT, +VT] extends Product with Serializable {
def bimap[C, D](f: RT => C, g: VT => D): DataType[C, D] =
Bifunctor[DataType].bimap(this)(f, g)

def fold[Z](record: Record[RT] => Z, variant: Variant[VT] => Z): Z = this match {
case r @ Record(_) => record(r)
case v @ Variant(_) => variant(v)
}
}

object DataType {
Expand All @@ -71,6 +66,8 @@ object DataType {
Traverse[Record].traverse(r)(f).widen
case v @ Variant(_) =>
Traverse[Variant].traverse(v)(g).widen
case Enum(vs) =>
Applicative[G].pure(Enum(vs))
}
}

Expand Down Expand Up @@ -116,6 +113,12 @@ object Variant extends FWTLike[Variant] {
}
}

final case class Enum(values: ImmArraySeq[Ref.Name]) extends DataType[Nothing, Nothing] {

/** Widen to DataType, in Java. */
def asDataType[RT, PVT]: DataType[RT, PVT] = this
}

final case class DefTemplate[+Ty](choices: Map[Ref.Name, TemplateChoice[Ty]]) {
def map[B](f: Ty => B): DefTemplate[B] = Functor[DefTemplate].map(this)(f)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ case class Partitions(
templates: List[DamlLf1.DefTemplate] = List.empty,
records: Map[DottedName, DamlLf1.DefDataType] = Map.empty,
variants: Map[DottedName, DamlLf1.DefDataType] = Map.empty,
enums: Map[DottedName, DamlLf1.DefDataType] = Map.empty,
errors: List[(String, InterfaceReaderError)] = List.empty
) {
def errorTree[Loc: Order](implicit kloc: String => Loc): Errors[Loc, InterfaceReaderError] =
Expand All @@ -32,21 +33,30 @@ object Partitions {
val templates = m.getTemplatesList.asScala.toList
val dataTypes = m.getDataTypesList.asScala.filter(_.getSerializable)
val (errors, recsVars) = partitionEithers(dataTypes map (partitionDDT(_)))
val (variants, records) = recsVars partition (_._1)
val partitions = recsVars.groupBy(_._1)
Partitions(
templates = templates,
records = records.map { case (_, n, t) => (n, t) }(breakOut),
variants = variants.map { case (_, n, t) => (n, t) }(breakOut),
records = partitions.getOrElse(DDT.RECORD, List.empty).map(_._2)(breakOut),
variants = partitions.getOrElse(DDT.VARIANT, List.empty).map(_._2)(breakOut),
enums = partitions.getOrElse(DDT.ENUM, List.empty).map(_._2)(breakOut),
errors = errors.toList
)
}

private sealed trait DDT
private object DDT {
case object RECORD extends DDT
case object VARIANT extends DDT
case object ENUM extends DDT
}

private def partitionDDT(a: DamlLf1.DefDataType)
: (String, InterfaceReaderError) Either (Boolean, DottedName, DamlLf1.DefDataType) = {
: (String, InterfaceReaderError) Either (DDT, (DottedName, DamlLf1.DefDataType)) = {
import DamlLf1.DefDataType.{DataConsCase => DCC}
(a.getDataConsCase match {
case DCC.RECORD => dottedName(a.getName) map ((false, _, a))
case DCC.VARIANT => dottedName(a.getName) map ((true, _, a))
case DCC.RECORD => dottedName(a.getName) map (x => (DDT.RECORD, (x, a)))
case DCC.VARIANT => dottedName(a.getName) map (x => (DDT.VARIANT, (x, a)))
case DCC.ENUM => dottedName(a.getName) map (x => (DDT.ENUM, (x, a)))
case DCC.DATACONS_NOT_SET =>
-\/(invalidDataTypeDefinition(a, "DamlLf1.DefDataType.DataConsCase.DATACONS_NOT_SET"))
}).leftMap((a.toString, _)).toEither
Expand Down
Loading

0 comments on commit f84e7d7

Please sign in to comment.