verified-network-toolchain / petr4

Petr4: Formal Semantics for P4
Apache License 2.0
74 stars 20 forks source link

enum type declaration #383

Open pataei opened 1 year ago

pataei commented 1 year ago

Petr4 code

type_serializable_enum env ctx tags annotations underlying_type (name: P4String.t) (members: (P4String.t * Expression.t) list) =
  let expr_ctx = ExprContext.of_decl_context ctx in
  let underlying_type =
    underlying_type
    |> translate_type env []
    |> saturate_type env
  in
  let underlying_type =
    match underlying_type with
    | Int _ | Bit _ -> underlying_type
    | _ -> raise_mismatch tags "fixed width numeric type for enum" underlying_type
  in
  let member_names = List.map ~f:(fun member -> (fst member).string) members in
  let enum_type: Typed.Type.t =
    Enum { name = name.string; typ = Some underlying_type; members = member_names }
  in
  let add_member (env, members_typed) ((member: P4String.t) , expr) =
    let member_name = QualifiedName {prefix = []; tags = member.tags; name={tags = name.tags; string = name.string ^ "." ^ member.string}} in
    let expr_typed = cast_expression env expr_ctx underlying_type expr in
    match compile_time_eval_expr env expr_typed with
    | Some value ->
       env
       |> CheckerEnv.insert_type_of member_name enum_type
       |> CheckerEnv.insert_const member_name
            (VEnumField { typ_name = name.string;
                          enum_name = member.string }),
       members_typed @ [ member, expr_typed ]
    | None -> failwith "could not evaluate enum member"
  in
  let env = CheckerEnv.insert_type (QualifiedName {prefix=[]; name; tags = name.tags}) enum_type env in
  let env, member_names = List.fold_left ~f:add_member ~init:(env, []) members in
  let enum_typed =
    Prog.Declaration.SerializableEnum { annotations; typ=enum_type; name; members = member_names; tags } in
  enum_typed, env

P4 spec (v1.2.3)

enum bit<8> FailingExample {
  first           = 1,
  second          = 2,
  third           = 3,
  unrepresentable = 300
}

Fixes

Side note on serializable enums

Note that Petr4 checks that the fixed-width integers have constant size by translating the underlying type from types.type.t to typed.type.t.

pataei commented 1 year ago

added to the casting issue on P4 spec repo.

pataei commented 1 year ago

Neither P4 spec nor Petr4 checks for enum fields to be distinct but I'd imagine a well-formed enum type must have distinct fields.

hackedy commented 1 year ago

I think petr4 rejects enum field dups. E.g. running petr4 typecheck on this program

enum A {
  X,
  X
}

fails with a "constant already defined!" error about A.X. But if it's missing from the definition of type well-formedness we should probably add it to that.

pataei commented 1 year ago

Ahh! Then it must be checked where the constants are inserted. Checked and in fact, it was in insert_const helper function. Thanks Ryan!