35b2537754
Add support for directions on parameters and attributed types. The latter is necessary to support the former, but is not limited to the direction use case. An attributed type is a P4 type with attributes (like its direction, whether it is read only, etc.) Other attributes will be added in the future. Changes necessary to support attributed types include: 1. Global instances tracked during compilation are not attributed types and not simply types. 2. (future) Type checking will have to make sure that a types attributes do not affect type compatibility. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
858 lines
20 KiB
Swift
858 lines
20 KiB
Swift
// p4rse, Copyright 2026, Will Hawkins
|
|
//
|
|
// This file is part of p4rse.
|
|
//
|
|
// This file is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
/// A P4 identifier
|
|
public class Identifier: CustomStringConvertible, Comparable, Hashable {
|
|
public func hash(into hasher: inout Hasher) {
|
|
hasher.combine(self.name)
|
|
}
|
|
|
|
var name: String
|
|
|
|
public init(name: String) {
|
|
self.name = name
|
|
}
|
|
|
|
public init(id: Identifier) {
|
|
self.name = id.name
|
|
}
|
|
|
|
public var description: String {
|
|
return "\(name)"
|
|
}
|
|
|
|
public static func == (lhs: Identifier, rhs: Identifier) -> Bool {
|
|
return lhs.name == rhs.name
|
|
}
|
|
|
|
public static func == (lhs: Identifier, rhs: String) -> Bool {
|
|
return Identifier(name: rhs) == lhs
|
|
}
|
|
|
|
public static func < (lhs: Identifier, rhs: Identifier) -> Bool {
|
|
return lhs.name < rhs.name
|
|
}
|
|
}
|
|
|
|
/// A P4 identifier
|
|
public class TypedIdentifier: Identifier {
|
|
public var type: P4Type
|
|
|
|
public init(name: String, withType type: P4Type) {
|
|
self.type = type
|
|
super.init(name: name)
|
|
}
|
|
|
|
public init(id: Identifier, withType type: P4Type) {
|
|
self.type = type
|
|
super.init(id: id)
|
|
}
|
|
|
|
public override var description: String {
|
|
return "\(name)"
|
|
}
|
|
}
|
|
|
|
/// A P4 variable
|
|
public class Variable: TypedIdentifier {
|
|
var constant: Bool
|
|
var value: P4Value?
|
|
|
|
public init(
|
|
name: String, withType type: P4Type, withValue value: P4Value?, isConstant constant: Bool
|
|
) {
|
|
self.constant = constant
|
|
self.value = value
|
|
super.init(name: name, withType: type)
|
|
}
|
|
|
|
public override var description: String {
|
|
return
|
|
"\(super.description) = \(value?.description ?? "Missing Value") \(constant ? "(constant)" : "")"
|
|
}
|
|
|
|
public var value_type: P4Value? {
|
|
value
|
|
}
|
|
}
|
|
|
|
public typealias P4StructFieldIdentifier = TypedIdentifier
|
|
|
|
public struct P4StructFields: Sequence, CustomStringConvertible, Equatable {
|
|
public typealias Element = [P4StructFieldIdentifier].Iterator.Element
|
|
|
|
public typealias Iterator = [P4StructFieldIdentifier].Iterator
|
|
|
|
public func makeIterator() -> Iterator {
|
|
return self.fields.makeIterator()
|
|
}
|
|
|
|
let fields: [P4StructFieldIdentifier]
|
|
|
|
public init(_ fields: [P4StructFieldIdentifier]) {
|
|
self.fields = fields
|
|
}
|
|
|
|
public var description: String {
|
|
return self.fields.map { field in
|
|
field.name
|
|
}.joined(separator: ",")
|
|
}
|
|
|
|
public func get_field_type(_ field: Identifier) -> P4Type? {
|
|
if let found_field = self.fields.makeIterator().first(where: { current in
|
|
return current.name == field.name
|
|
}) {
|
|
return found_field.type
|
|
}
|
|
return .none
|
|
}
|
|
|
|
public func count() -> Int {
|
|
return self.fields.count
|
|
}
|
|
|
|
public func describe_with_values(values: [P4Value?]) -> String {
|
|
assert(values.count == self.count())
|
|
return zip(self.fields, values).map { (field, value) in
|
|
let actual_value =
|
|
if let v = value {
|
|
v.description
|
|
} else {
|
|
"Unset"
|
|
}
|
|
return String("\(field): \(actual_value)")
|
|
}.joined(separator: "; ")
|
|
}
|
|
}
|
|
|
|
/// The type for a P4 struct
|
|
public struct P4Struct: P4Type {
|
|
|
|
public let name: Identifier
|
|
public let fields: P4StructFields
|
|
|
|
public init(withName name: Identifier, andFields fields: P4StructFields) {
|
|
self.name = name
|
|
self.fields = fields
|
|
}
|
|
|
|
public init() {
|
|
self.name = Identifier(name: "")
|
|
self.fields = P4StructFields([])
|
|
}
|
|
|
|
public var description: String {
|
|
return "Struct \(self.name) with fields: \(self.fields)"
|
|
}
|
|
|
|
public func eq(rhs: P4Type) -> Bool {
|
|
return if let struct_rhs = rhs as? P4Struct {
|
|
struct_rhs.name == self.name
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
public func def() -> any P4Value {
|
|
return P4StructValue(withType: self)
|
|
}
|
|
}
|
|
|
|
/// An instance of a P4 struct
|
|
public class P4StructValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return self.stype
|
|
}
|
|
|
|
func bin_op_impl(lhs: P4StructValue, rhs: P4StructValue, op: (P4Value?, P4Value?) -> Bool) -> Bool
|
|
{
|
|
if lhs.stype.fields.count() != rhs.stype.fields.count() {
|
|
// If there are a different number of fields, then we cannot
|
|
// possibly be equal.
|
|
return false
|
|
}
|
|
|
|
// Note: Because the number of values _always_ matches the number of fields, there
|
|
// is no need to check there!
|
|
|
|
for fields_to_compare in zip(
|
|
zip(lhs.stype.fields, lhs.values), zip(rhs.stype.fields, rhs.values))
|
|
{
|
|
let left_field_and_value = fields_to_compare.0
|
|
let right_field_and_value = fields_to_compare.1
|
|
|
|
let left_field_name = left_field_and_value.0
|
|
let left_field_value = left_field_and_value.1
|
|
|
|
let right_field_name = right_field_and_value.0
|
|
let right_field_value = right_field_and_value.1
|
|
|
|
// If the field names do not match, then there is a problem.
|
|
if left_field_name != right_field_name {
|
|
return false
|
|
}
|
|
|
|
// Now that we know that the field names match, do the values match?
|
|
if !op(left_field_value, right_field_value) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
public func eq(rhs: any P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4StructValue else {
|
|
return false
|
|
}
|
|
return bin_op_impl(lhs: self, rhs: rrhs) { ilhs, irhs in
|
|
if ilhs == nil && irhs == nil {
|
|
return true
|
|
}
|
|
guard let llhs = ilhs,
|
|
let rrhs = irhs
|
|
else {
|
|
return false
|
|
}
|
|
return llhs.eq(rhs: rrhs)
|
|
}
|
|
}
|
|
public func lt(rhs: any P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4StructValue else {
|
|
return false
|
|
}
|
|
return bin_op_impl(lhs: self, rhs: rrhs) { ilhs, irhs in
|
|
if ilhs == nil && irhs == nil {
|
|
return true
|
|
}
|
|
guard let llhs = ilhs,
|
|
let rrhs = irhs
|
|
else {
|
|
return false
|
|
}
|
|
return llhs.lt(rhs: rrhs)
|
|
}
|
|
}
|
|
public func lte(rhs: any P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4StructValue else {
|
|
return false
|
|
}
|
|
return bin_op_impl(lhs: self, rhs: rrhs) { ilhs, irhs in
|
|
if ilhs == nil && irhs == nil {
|
|
return true
|
|
}
|
|
guard let llhs = ilhs,
|
|
let rrhs = irhs
|
|
else {
|
|
return false
|
|
}
|
|
return llhs.lte(rhs: rrhs)
|
|
}
|
|
}
|
|
public func gt(rhs: any P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4StructValue else {
|
|
return false
|
|
}
|
|
return bin_op_impl(lhs: self, rhs: rrhs) { ilhs, irhs in
|
|
if ilhs == nil && irhs == nil {
|
|
return true
|
|
}
|
|
guard let llhs = ilhs,
|
|
let rrhs = irhs
|
|
else {
|
|
return false
|
|
}
|
|
return llhs.gt(rhs: rrhs)
|
|
}
|
|
}
|
|
|
|
public func gte(rhs: any P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4StructValue else {
|
|
return false
|
|
}
|
|
return bin_op_impl(lhs: self, rhs: rrhs) { ilhs, irhs in
|
|
if ilhs == nil && irhs == nil {
|
|
return true
|
|
}
|
|
guard let llhs = ilhs,
|
|
let rrhs = irhs
|
|
else {
|
|
return false
|
|
}
|
|
return llhs.gte(rhs: rrhs)
|
|
}
|
|
}
|
|
|
|
public var description: String {
|
|
return "Struct: \(self.stype.fields.describe_with_values(values: self.values))"
|
|
}
|
|
|
|
public let stype: P4Struct
|
|
public let values: [P4Value]
|
|
|
|
public convenience init(withType type: P4Struct) {
|
|
self.init(withType: type, andInitializers: [])
|
|
}
|
|
|
|
public init(withType type: P4Struct, andInitializers initializers: [P4Value?]) {
|
|
let values = zip(0..<type.fields.count(), type.fields.fields).map { (index, field) in
|
|
// If there is an initializer for the field, then use it.
|
|
if index < initializers.count, let initializer = initializers[index] {
|
|
initializer
|
|
} else {
|
|
// Otherwise, set a default!
|
|
field.type.def()
|
|
}
|
|
}
|
|
|
|
self.values = values
|
|
self.stype = type
|
|
}
|
|
|
|
public func get(field: P4StructFieldIdentifier) -> P4Value? {
|
|
for field_idx in 0..<stype.fields.count() {
|
|
if stype.fields.fields[field_idx] == field {
|
|
return values[field_idx]
|
|
}
|
|
}
|
|
return .none
|
|
}
|
|
|
|
public func set(field: P4StructFieldIdentifier, to: P4Value) -> Result<P4StructValue> {
|
|
var updated_values = self.values
|
|
|
|
for field_idx in 0..<stype.fields.count() {
|
|
if stype.fields.fields[field_idx] == field {
|
|
if !stype.fields.fields[field_idx].type.eq(rhs: to.type()) {
|
|
return .Error(
|
|
Error(
|
|
withMessage:
|
|
"Cannot assign value with type \(to.type()) to field with type \(stype.fields.fields[field_idx].type))"
|
|
))
|
|
}
|
|
updated_values[field_idx] = to
|
|
break
|
|
}
|
|
}
|
|
|
|
return .Ok(P4StructValue(withType: self.stype, andInitializers: updated_values))
|
|
}
|
|
|
|
}
|
|
|
|
/// A P4 boolean type
|
|
public struct P4Boolean: P4Type {
|
|
public init() {}
|
|
public var description: String {
|
|
return "Boolean"
|
|
}
|
|
public func eq(rhs: P4Type) -> Bool {
|
|
return switch rhs {
|
|
case is P4Boolean: true
|
|
default: false
|
|
}
|
|
}
|
|
public func def() -> any P4Value {
|
|
return P4BooleanValue(withValue: false)
|
|
}
|
|
}
|
|
|
|
/// An instance of a P4 boolean
|
|
public class P4BooleanValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return P4Boolean()
|
|
}
|
|
|
|
let value: Bool
|
|
|
|
public func access() -> Bool {
|
|
return self.value
|
|
}
|
|
|
|
public init(withValue value: Bool) {
|
|
self.value = value
|
|
}
|
|
public func eq(rhs: P4Value) -> Bool {
|
|
guard let bool_rhs = rhs as? P4BooleanValue else {
|
|
return false
|
|
}
|
|
return self.value == bool_rhs.value
|
|
}
|
|
|
|
public func lt(rhs: P4Value) -> Bool {
|
|
guard let bool_rhs = rhs as? P4BooleanValue else {
|
|
return false
|
|
}
|
|
return (self.value ? 1 : 0) < (bool_rhs.value ? 1 : 0)
|
|
}
|
|
|
|
public func lte(rhs: P4Value) -> Bool {
|
|
guard let bool_rhs = rhs as? P4BooleanValue else {
|
|
return false
|
|
}
|
|
return (self.value ? 1 : 0) <= (bool_rhs.value ? 1 : 0)
|
|
}
|
|
|
|
public func gt(rhs: P4Value) -> Bool {
|
|
guard let bool_rhs = rhs as? P4BooleanValue else {
|
|
return false
|
|
}
|
|
return (self.value ? 1 : 0) > (bool_rhs.value ? 1 : 0)
|
|
}
|
|
|
|
public func gte(rhs: P4Value) -> Bool {
|
|
guard let bool_rhs = rhs as? P4BooleanValue else {
|
|
return false
|
|
}
|
|
return (self.value ? 1 : 0) >= (bool_rhs.value ? 1 : 0)
|
|
}
|
|
|
|
public var description: String {
|
|
"\(self.value ? "true" : "false") of \(self.type()) type"
|
|
}
|
|
}
|
|
|
|
/// A P4 int type
|
|
public struct P4Int: P4Type {
|
|
public init() {}
|
|
|
|
public var description: String {
|
|
return "Int"
|
|
}
|
|
public func eq(rhs: P4Type) -> Bool {
|
|
return switch rhs {
|
|
case is P4Int: true
|
|
default: false
|
|
}
|
|
}
|
|
public func def() -> any P4Value {
|
|
return P4IntValue(withValue: 0)
|
|
}
|
|
}
|
|
|
|
/// An instance of a P4 integer
|
|
public class P4IntValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return P4Int()
|
|
}
|
|
|
|
let value: Int
|
|
public init(withValue value: Int) {
|
|
self.value = value
|
|
}
|
|
|
|
public func access() -> Int {
|
|
return self.value
|
|
}
|
|
|
|
public func eq(rhs: P4Value) -> Bool {
|
|
guard let int_rhs = rhs as? P4IntValue else {
|
|
return false
|
|
}
|
|
return self.value == int_rhs.value
|
|
}
|
|
|
|
public func lt(rhs: P4Value) -> Bool {
|
|
guard let int_rhs = rhs as? P4IntValue else {
|
|
return false
|
|
}
|
|
return self.value < int_rhs.value
|
|
}
|
|
|
|
public func lte(rhs: P4Value) -> Bool {
|
|
guard let int_rhs = rhs as? P4IntValue else {
|
|
return false
|
|
}
|
|
return self.value <= int_rhs.value
|
|
}
|
|
|
|
public func gt(rhs: P4Value) -> Bool {
|
|
guard let int_rhs = rhs as? P4IntValue else {
|
|
return false
|
|
}
|
|
return self.value > int_rhs.value
|
|
}
|
|
|
|
public func gte(rhs: P4Value) -> Bool {
|
|
guard let int_rhs = rhs as? P4IntValue else {
|
|
return false
|
|
}
|
|
return self.value >= int_rhs.value
|
|
}
|
|
|
|
public var description: String {
|
|
"\(self.value) of \(self.type()) type"
|
|
}
|
|
}
|
|
|
|
/// A P4 string type
|
|
public struct P4String: P4Type {
|
|
public init() {}
|
|
public var description: String {
|
|
return "String"
|
|
}
|
|
public func eq(rhs: any P4Type) -> Bool {
|
|
return switch rhs {
|
|
case is P4String: true
|
|
default: false
|
|
}
|
|
}
|
|
public func def() -> any P4Value {
|
|
return P4StringValue(withValue: "")
|
|
}
|
|
}
|
|
/// An instance of a P4 string
|
|
public class P4StringValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return P4String()
|
|
}
|
|
|
|
let value: String
|
|
public init(withValue value: String) {
|
|
self.value = value
|
|
}
|
|
public func eq(rhs: P4Value) -> Bool {
|
|
guard let string_rhs = rhs as? P4StringValue else {
|
|
return false
|
|
}
|
|
return self.value == string_rhs.value
|
|
}
|
|
|
|
public func lt(rhs: P4Value) -> Bool {
|
|
guard let string_rhs = rhs as? P4StringValue else {
|
|
return false
|
|
}
|
|
return self.value < string_rhs.value
|
|
}
|
|
|
|
public func lte(rhs: P4Value) -> Bool {
|
|
guard let string_rhs = rhs as? P4StringValue else {
|
|
return false
|
|
}
|
|
return self.value <= string_rhs.value
|
|
}
|
|
|
|
public func gt(rhs: P4Value) -> Bool {
|
|
guard let string_rhs = rhs as? P4StringValue else {
|
|
return false
|
|
}
|
|
return self.value > string_rhs.value
|
|
}
|
|
|
|
public func gte(rhs: P4Value) -> Bool {
|
|
guard let string_rhs = rhs as? P4StringValue else {
|
|
return false
|
|
}
|
|
return self.value >= string_rhs.value
|
|
}
|
|
|
|
public var description: String {
|
|
"\(self.value) of \(self.type()) type"
|
|
}
|
|
}
|
|
|
|
public class Packet {
|
|
public init() {}
|
|
}
|
|
|
|
/// A P4 array type
|
|
public struct P4Array: P4Type {
|
|
public init(withValueType vtype: P4Type) {
|
|
self.vtype = vtype
|
|
}
|
|
|
|
let vtype: P4Type
|
|
|
|
public func value_type() -> P4Type {
|
|
return self.vtype
|
|
}
|
|
|
|
public var description: String {
|
|
return "Array"
|
|
}
|
|
|
|
public func eq(rhs: any P4Type) -> Bool {
|
|
return switch rhs {
|
|
case is P4Array: true
|
|
default: false
|
|
}
|
|
}
|
|
|
|
public func def() -> P4Value {
|
|
return P4ArrayValue(withType: self, withValue: [])
|
|
}
|
|
}
|
|
|
|
/// An instance of a P4 array
|
|
public class P4ArrayValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return P4Array(withValueType: self.vtype)
|
|
}
|
|
|
|
let value: [P4Value]
|
|
let vtype: P4Type
|
|
|
|
public init(withType type: P4Type, withValue value: [P4Value]) {
|
|
self.vtype = type
|
|
self.value = value
|
|
}
|
|
|
|
public func access(_ index: Int) -> P4Value {
|
|
return self.value[index]
|
|
}
|
|
|
|
public func set(index: Int, to: P4Value) -> Result<P4ArrayValue> {
|
|
// TODO: Check for OOB
|
|
var updated_values = self.value
|
|
updated_values[index] = to
|
|
return Result.Ok(P4ArrayValue(withType: self.vtype, withValue: updated_values))
|
|
}
|
|
|
|
public func eq(rhs: P4Value) -> Bool {
|
|
guard rhs as? P4ArrayValue != nil else {
|
|
return false
|
|
}
|
|
// TODO!!
|
|
return true
|
|
}
|
|
|
|
public func lt(rhs: P4Value) -> Bool {
|
|
guard rhs as? P4ArrayValue != nil else {
|
|
return false
|
|
}
|
|
// TODO!!
|
|
return true
|
|
}
|
|
|
|
public func lte(rhs: P4Value) -> Bool {
|
|
guard rhs as? P4ArrayValue != nil else {
|
|
return false
|
|
}
|
|
// TODO!!
|
|
return true
|
|
}
|
|
|
|
public func gt(rhs: P4Value) -> Bool {
|
|
guard rhs as? P4ArrayValue != nil else {
|
|
return false
|
|
}
|
|
// TODO!!
|
|
return true
|
|
}
|
|
|
|
public func gte(rhs: P4Value) -> Bool {
|
|
guard rhs as? P4ArrayValue != nil else {
|
|
return false
|
|
}
|
|
// TODO!!
|
|
return true
|
|
}
|
|
|
|
public var description: String {
|
|
"\(self.value) of \(self.type()) type"
|
|
}
|
|
}
|
|
|
|
/// A P4 set type
|
|
public struct P4Set: P4Type {
|
|
public init(withSetType stype: P4Type) {
|
|
self.stype = stype
|
|
}
|
|
|
|
let stype: P4Type
|
|
|
|
public func set_type() -> P4Type {
|
|
return self.stype
|
|
}
|
|
|
|
public var description: String {
|
|
return "P4Set"
|
|
}
|
|
|
|
public func eq(rhs: any P4Type) -> Bool {
|
|
return switch rhs {
|
|
// If rhs is a set type, then they are the same if the types in the set are the same.
|
|
case let srhs as P4Set: srhs.eq(rhs: self.stype)
|
|
default: false
|
|
}
|
|
}
|
|
|
|
public func def() -> P4Value {
|
|
return P4ArrayValue(withType: self, withValue: [])
|
|
}
|
|
}
|
|
|
|
/// An instance of a P4 set
|
|
public class P4SetValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return P4Set(withSetType: self.stype)
|
|
}
|
|
|
|
let value: P4Value
|
|
let stype: P4Type
|
|
|
|
public init(withType type: P4Type, withValue value: P4Value) {
|
|
self.stype = type
|
|
self.value = value
|
|
}
|
|
|
|
public func access() -> P4Value {
|
|
return self.value
|
|
}
|
|
|
|
public func eq(rhs: P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4SetValue else {
|
|
return false
|
|
}
|
|
return rrhs.access().eq(rhs: self.value)
|
|
}
|
|
public func lt(rhs: P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4SetValue else {
|
|
return false
|
|
}
|
|
return rrhs.access().lt(rhs: self.value)
|
|
}
|
|
public func lte(rhs: P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4SetValue else {
|
|
return false
|
|
}
|
|
return rrhs.access().lte(rhs: self.value)
|
|
}
|
|
public func gt(rhs: P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4SetValue else {
|
|
return false
|
|
}
|
|
return rrhs.access().gt(rhs: self.value)
|
|
}
|
|
public func gte(rhs: P4Value) -> Bool {
|
|
guard let rrhs = rhs as? P4SetValue else {
|
|
return false
|
|
}
|
|
return rrhs.access().gte(rhs: self.value)
|
|
}
|
|
|
|
public var description: String {
|
|
"P4Set with \(self.value) of \(self.type()) type"
|
|
}
|
|
}
|
|
|
|
public class P4SetDefaultValue: P4Value {
|
|
public func type() -> any P4Type {
|
|
return P4Set(withSetType: self.stype)
|
|
}
|
|
|
|
let stype: P4Type
|
|
|
|
public init(withType type: P4Type) {
|
|
self.stype = type
|
|
}
|
|
|
|
// Snarf up everything!
|
|
public func eq(rhs: P4Value) -> Bool {
|
|
return true
|
|
}
|
|
public func lt(rhs: P4Value) -> Bool {
|
|
return true
|
|
}
|
|
public func lte(rhs: P4Value) -> Bool {
|
|
return true
|
|
}
|
|
public func gt(rhs: P4Value) -> Bool {
|
|
return true
|
|
}
|
|
public func gte(rhs: P4Value) -> Bool {
|
|
return true
|
|
}
|
|
|
|
public var description: String {
|
|
"Default of P4Set of \(self.type()) type"
|
|
}
|
|
}
|
|
|
|
public enum Direction: Equatable, CustomStringConvertible {
|
|
case In
|
|
case Out
|
|
case InOut
|
|
|
|
public var description: String {
|
|
return switch self {
|
|
case Direction.In: "In"
|
|
case Direction.Out: "Out"
|
|
case Direction.InOut: "InOut"
|
|
}
|
|
}
|
|
|
|
/// Compare two optional ``Direction``s
|
|
static public func eqopt(_ lhs: Direction?, _ rhs: Direction?) -> Bool {
|
|
// If both are empty, they are the same.
|
|
if lhs == .none && rhs == .none {
|
|
return true
|
|
}
|
|
|
|
// If one is empty, they are different
|
|
if lhs == .none || rhs == .none {
|
|
return false
|
|
}
|
|
|
|
// Both have values -- compare them natively.
|
|
return lhs! == rhs!
|
|
}
|
|
}
|
|
|
|
public enum P4TypeAttribute {
|
|
case Direction(Direction)
|
|
case Readonly // Not yet used -- here to keep Swift warnings at bay
|
|
}
|
|
|
|
public struct P4TypeAttributed {
|
|
let attributes: [P4TypeAttribute]
|
|
public let type: P4Type
|
|
|
|
public init(_ type: P4Type, _ attributes: [P4TypeAttribute]) {
|
|
self.attributes = attributes
|
|
self.type = type
|
|
}
|
|
|
|
public func direction() -> Direction? {
|
|
let result = attributes.firstIndex { attribute in
|
|
return switch attribute {
|
|
case .Direction(_): true
|
|
default: false
|
|
}
|
|
}
|
|
return result.flatMap { index in
|
|
return switch attributes[index] {
|
|
case .Direction(let d): d
|
|
default: Optional<Direction>.none
|
|
}
|
|
}
|
|
}
|
|
|
|
public func readOnly() -> Bool {
|
|
return attributes.contains { attribute in
|
|
return switch attribute {
|
|
case .Readonly: true
|
|
default: false
|
|
}
|
|
}
|
|
}
|
|
|
|
public static func Attributeless(_ type: P4Type) -> P4TypeAttributed {
|
|
return P4TypeAttributed(type, [])
|
|
}
|
|
}
|