grammar,compiler: Add Support For Fixed-Width Integers
Distinguishing between signed and unsigned fixed-width integer types must still be done. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -424,19 +424,30 @@ public class P4BooleanValue: P4DataValue {
|
||||
}
|
||||
}
|
||||
|
||||
public enum BitWidth: Equatable {
|
||||
case Infinite
|
||||
case Width(Int)
|
||||
}
|
||||
|
||||
/// A P4 int type
|
||||
public struct P4Int: P4Type {
|
||||
public init() {}
|
||||
let width: BitWidth
|
||||
|
||||
public init(_ width: BitWidth = BitWidth.Infinite) {
|
||||
self.width = width
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return "Int"
|
||||
return "Int (width: \(self.width))"
|
||||
}
|
||||
|
||||
public func eq(rhs: P4Type) -> Bool {
|
||||
return switch rhs {
|
||||
case is P4Int: true
|
||||
case let rrhs as P4Int: rrhs.width == self.width
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
public func def() -> P4DataValue? {
|
||||
return P4IntValue(withValue: 0)
|
||||
}
|
||||
@@ -444,12 +455,16 @@ public struct P4Int: P4Type {
|
||||
|
||||
/// An instance of a P4 integer
|
||||
public class P4IntValue: P4DataValue {
|
||||
|
||||
let int_type: P4Int
|
||||
|
||||
public func type() -> P4Type {
|
||||
return P4Int()
|
||||
return int_type
|
||||
}
|
||||
|
||||
let value: Int
|
||||
public init(withValue value: Int) {
|
||||
public init(withValue value: Int, andWidth width: BitWidth = BitWidth.Infinite) {
|
||||
self.int_type = P4Int(width)
|
||||
self.value = value
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,8 @@ public func Fold<T, A>(input: [T], initial: A, block: (T, A) -> A) -> A {
|
||||
#externalMacro(module: "Macros", type: "RequireNodesType")
|
||||
@freestanding(codeItem) public macro SkipUnlessNodeType<N>(node: N, type: String) =
|
||||
#externalMacro(module: "Macros", type: "SkipUnlessNodeType")
|
||||
@freestanding(codeItem) public macro SkipUnlessNodesTypes<N>(node: N, types: [String]) =
|
||||
#externalMacro(module: "Macros", type: "SkipUnlessNodesTypes")
|
||||
|
||||
@freestanding(codeItem) public macro MustOr<E, N>(result: E, thing: E?, or: N) =
|
||||
#externalMacro(module: "Macros", type: "MustOr")
|
||||
|
||||
@@ -229,6 +229,38 @@ public struct SkipUnlessNodeType: CodeItemMacro {
|
||||
}
|
||||
}
|
||||
|
||||
public struct SkipUnlessNodesTypes: CodeItemMacro {
|
||||
public static func expansion(
|
||||
of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext
|
||||
) throws -> [CodeBlockItemSyntax] {
|
||||
|
||||
let arguments = node.arguments.indices
|
||||
var arg_index = arguments.startIndex
|
||||
|
||||
let node_to_check = node.arguments[arg_index].expression
|
||||
|
||||
arg_index = arguments.index(after: arg_index)
|
||||
guard let expected_types = node.arguments[arg_index].expression.as(ArrayExprSyntax.self) else {
|
||||
throw MacroError(withMessage: "Node(s) to check must be in an array")
|
||||
}
|
||||
|
||||
arg_index = arguments.index(after: arg_index)
|
||||
|
||||
let ifs = expected_types.elements.map { l in
|
||||
"\(node_to_check).nodeType != \(l.expression)"
|
||||
}.joined(separator: " && ")
|
||||
|
||||
return [
|
||||
CodeBlockItemSyntax(
|
||||
"""
|
||||
if \(raw: ifs) {
|
||||
return Result.Ok(.none)
|
||||
}
|
||||
""")
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public struct MustOr: CodeItemMacro {
|
||||
public static func expansion(
|
||||
of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext
|
||||
@@ -261,6 +293,7 @@ public struct MustOr: CodeItemMacro {
|
||||
struct P4Macros: CompilerPlugin {
|
||||
var providingMacros: [Macro.Type] = [
|
||||
RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self,
|
||||
RequireNodeType.self, SkipUnlessNodeType.self, RequireNodesType.self, MustOr.self,
|
||||
RequireNodeType.self, SkipUnlessNodeType.self, SkipUnlessNodesTypes.self, RequireNodesType.self,
|
||||
MustOr.self,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -101,9 +101,41 @@ extension P4IntValue: CompilableExpression {
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<EvaluatableExpression?> {
|
||||
let node = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(node: node, type: "integer")
|
||||
if let parsed_int = Int(node.text!) {
|
||||
return .Ok(P4Value(P4IntValue(withValue: parsed_int)))
|
||||
|
||||
#SkipUnlessNodesTypes<SwiftTreeSitter.Node>(
|
||||
node: node, types: ["integer", "integer_elaborated"])
|
||||
|
||||
var bit_width: BitWidth = BitWidth.Infinite
|
||||
let value_source: String
|
||||
if node.nodeType == "integer_elaborated" {
|
||||
let re = /([0-9]+)([ws])([\-0-9]+)/
|
||||
let integer_components = node.text!.matches(of: re)
|
||||
|
||||
if integer_components.isEmpty || integer_components.count > 1 {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Failed to parse elaborated integer: \(node.text!)"))
|
||||
}
|
||||
|
||||
let width_source = "\(integer_components[0].1)"
|
||||
guard let width = Int(width_source) else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Failed to parse width from elaborated integer: \(width_source)"))
|
||||
}
|
||||
|
||||
/// TODO: Handle signed vs. unsigned.
|
||||
|
||||
bit_width = BitWidth.Width(width)
|
||||
value_source = "\(integer_components[0].3)"
|
||||
} else {
|
||||
value_source = node.text!
|
||||
}
|
||||
|
||||
if let parsed_int = Int(value_source) {
|
||||
return .Ok(P4Value(P4IntValue(withValue: parsed_int, andWidth: bit_width)))
|
||||
} else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
|
||||
@@ -34,7 +34,42 @@ extension P4Int: CompilableType {
|
||||
public static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: CompilerContext
|
||||
) -> Common.Result<(any Common.P4Type)?> {
|
||||
return type.text == "int" ? .Ok(P4Int()) : .Ok(.none)
|
||||
|
||||
// Drill down, as appropriate.
|
||||
let base_type_node = type.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
|
||||
node: base_type_node, type: "baseType")
|
||||
|
||||
let type_node = base_type_node.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
|
||||
node: type_node, type: "int_type")
|
||||
|
||||
var walker = Walker(node: type_node)
|
||||
|
||||
var int_node: Node? = .none
|
||||
|
||||
#MustOr(
|
||||
result: int_node, thing: walker.getNext(),
|
||||
or: Result<P4Type?>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: type_node.toSourceLocation(),
|
||||
withError: "Missing elements in int type declaration")))
|
||||
|
||||
// Move passed the keyword.
|
||||
walker.next()
|
||||
|
||||
if let bit_width_node = walker.getNext() {
|
||||
guard let bit_width = Int(bit_width_node.child(at: 1)!.text!),
|
||||
bit_width != 0
|
||||
else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: bit_width_node.toSourceLocation(),
|
||||
withError: "Could not parse \(bit_width_node.text!) into integer"))
|
||||
}
|
||||
return .Ok(P4Int(BitWidth.Width(bit_width)))
|
||||
}
|
||||
return .Ok(P4Int())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Protos
|
||||
|
||||
public struct Generated {
|
||||
let gen: String
|
||||
@@ -48,13 +49,12 @@ public struct CodeGenerator: LanguageVisitor {
|
||||
return visitor.start(node, context: generated)
|
||||
}
|
||||
|
||||
/// TODO: Can we generate these implementations somehow?
|
||||
|
||||
public typealias Context = Generated
|
||||
|
||||
public func visit(
|
||||
_ v: Program, _ c: VisitorContext<Generated>
|
||||
) -> Result<VisitorContext<Generated>> {
|
||||
|
||||
var result: Result<VisitorContext<Generated>> = Fold(
|
||||
input: v.types, initial: .Ok(c.next(uc: c.getUserContext().append("[")))
|
||||
) { (current, acc) in
|
||||
|
||||
Reference in New Issue
Block a user