From 443b21b89010767a8c415decfd53ebf6d051a2d4 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Thu, 2 Apr 2026 02:49:04 -0400 Subject: [PATCH] Initial Work on Compiling Function Declarations Signed-off-by: Will Hawkins --- Sources/P4Compiler/Declarations.swift | 132 ++++++++++++++++++++++---- Sources/P4Lang/Declarations.swift | 94 +++++++++++++++++- Tests/p4rseTests/Declarations.swift | 20 ++++ 3 files changed, 228 insertions(+), 18 deletions(-) diff --git a/Sources/P4Compiler/Declarations.swift b/Sources/P4Compiler/Declarations.swift index 84ac2f0..75e5718 100644 --- a/Sources/P4Compiler/Declarations.swift +++ b/Sources/P4Compiler/Declarations.swift @@ -27,49 +27,148 @@ extension Declaration: CompilableDeclaration { node: Node, withContext context: CompilerContext ) -> Result<(P4Type, CompilerContext)?> { - guard let node_type = node.nodeType, - node_type == "type_declaration" - else { + let declaration_compilers: [String: CompilableDeclaration.Type] = [ + "function_declaration": FunctionDeclaration.self, + "type_declaration": StructDeclaration.self, // Assume that type declarations are struct declarations. + ] + + guard let declaration_compiler = declaration_compilers[node.nodeType!] else { return .Ok(.none) } - // Assume that it is a struct declaration - return StructDeclaration.Compile(node: node.child(at: 0)!, withContext: context) + return declaration_compiler.Compile(node: node, withContext: context) } } -struct StructDeclaration { +extension FunctionDeclaration: CompilableDeclaration { + public static func Compile( + node: SwiftTreeSitter.Node, withContext context: CompilerContext + ) -> Common.Result<(any Common.P4Type, CompilerContext)?> { + let function_declaration_node = node + #RequireNodeType( + node: function_declaration_node, type: "function_declaration", + nice_type_name: "Function Declaration") + + var context = context + var currentChildIdx = 0 + var currentChildIdxSafe = 1 + var currentChild: Node? = .none + if function_declaration_node.childCount < currentChildIdxSafe { + return Result.Error( + ErrorOnNode( + node: function_declaration_node, withError: "Missing function declaration component")) + } + currentChild = function_declaration_node.child(at: currentChildIdx) + + let maybe_function_type = Types.CompileType(type: currentChild!, withContext: context) + guard case .Ok(let function_type) = maybe_function_type else { + return .Error(maybe_function_type.error()!) + } + + currentChildIdx += 1 + currentChildIdxSafe += 1 + if function_declaration_node.childCount < currentChildIdxSafe { + return Result.Error( + ErrorOnNode( + node: function_declaration_node, withError: "Missing function declaration component")) + } + currentChild = function_declaration_node.child(at: currentChildIdx) + + let maybe_function_name = Identifier.Compile(node: currentChild!, withContext: context) + guard case .Ok(let function_name) = maybe_function_name else { + return .Error(maybe_function_name.error()!) + } + + currentChildIdx += 1 + currentChildIdxSafe += 1 + if function_declaration_node.childCount < currentChildIdxSafe { + return Result.Error( + ErrorOnNode( + node: function_declaration_node, withError: "Missing function declaration component")) + } + currentChild = function_declaration_node.child(at: currentChildIdx) + + let maybe_function_parameters = ParameterList.Compile(node: currentChild!, withContext: context) + guard case .Ok((let function_parameters, let updated_context)) = maybe_function_parameters + else { + return .Error(maybe_function_parameters.error()!) + } + context = updated_context + + currentChildIdx += 1 + currentChildIdxSafe += 1 + if function_declaration_node.childCount < currentChildIdxSafe { + return Result.Error( + ErrorOnNode( + node: function_declaration_node, withError: "Missing function declaration component")) + } + currentChild = function_declaration_node.child(at: currentChildIdx) + + // Add the parameters into scope. + var function_scope = context.instances.enter() + for parameter in function_parameters.parameters { + function_scope = function_scope.declare(identifier: parameter.name, withValue: parameter.type) + } + + let maybe_function_body = Parser.Statement.Compile( + node: currentChild!, withContext: context.update(newInstances: function_scope)) + guard case .Ok((let function_body, _)) = maybe_function_body else { + return .Error(maybe_function_body.error()!) + } + + let function_declaration = FunctionDeclaration( + named: function_name, ofType: function_type, withParameters: function_parameters, + withBody: function_body) + + // Do not use the updated context returned by parsing the body + // and do not use the function_scope, either. + return .Ok( + ( + function_declaration, + context.update( + newTypes: context.types.declare( + identifier: function_name, withValue: function_declaration)) + )) + } +} + +struct StructDeclaration {} + +extension StructDeclaration: CompilableDeclaration { static func Compile( node: Node, withContext context: CompilerContext ) -> Result<(P4Type, CompilerContext)?> { + let struct_declaration_node = node.child(at: 0)! var currentChildIdx = 0 var currentChildIdxSafe = 1 var currentChild: Node? = .none - guard let node_type = node.nodeType, + guard let node_type = struct_declaration_node.nodeType, node_type == "struct_declaration" else { return Result.Error( - ErrorOnNode(node: node, withError: "Did not find a struct declaration")) + ErrorOnNode(node: struct_declaration_node, withError: "Did not find a struct declaration")) } - if node.childCount < currentChildIdxSafe { + if struct_declaration_node.childCount < currentChildIdxSafe { return Result.Error( - ErrorOnNode(node: node, withError: "Missing elements in struct declaration")) + ErrorOnNode( + node: struct_declaration_node, withError: "Missing elements in struct declaration")) } // Skip the keyword struct currentChildIdx += 1 currentChildIdxSafe += 1 - if node.childCount < currentChildIdxSafe { + if struct_declaration_node.childCount < currentChildIdxSafe { return Result.Error( - ErrorOnNode(node: node, withError: "Missing elements in struct declaration")) + ErrorOnNode( + node: struct_declaration_node, withError: "Missing elements in struct declaration")) } // The name of the struct type. - currentChild = node.child(at: currentChildIdx) + currentChild = struct_declaration_node.child(at: currentChildIdx) let maybe_struct_identifier = Identifier.Compile( node: currentChild!, withContext: context) guard case Result.Ok(let struct_identifier) = maybe_struct_identifier else { @@ -82,12 +181,13 @@ struct StructDeclaration { // Skip the '{' currentChildIdx += 1 currentChildIdxSafe += 1 - if node.childCount < currentChildIdxSafe { + if struct_declaration_node.childCount < currentChildIdxSafe { return Result.Error( - ErrorOnNode(node: node, withError: "Missing element of struct declaration")) + ErrorOnNode( + node: struct_declaration_node, withError: "Missing element of struct declaration")) } - currentChild = node.child(at: currentChildIdx) + currentChild = struct_declaration_node.child(at: currentChildIdx) // If there are no fields, it will be a "}" if currentChild!.nodeType == "}" { diff --git a/Sources/P4Lang/Declarations.swift b/Sources/P4Lang/Declarations.swift index ed29b58..92b78bf 100644 --- a/Sources/P4Lang/Declarations.swift +++ b/Sources/P4Lang/Declarations.swift @@ -19,7 +19,11 @@ import Common public struct Declaration {} -public struct Parameter: CustomStringConvertible { +public struct Parameter: CustomStringConvertible, Equatable { + public static func == (lhs: Parameter, rhs: Parameter) -> Bool { + return lhs.name == rhs.name && lhs.type.eq(rhs: rhs.type) + } + public var name: Identifier public var type: P4Type @@ -35,7 +39,18 @@ public struct Parameter: CustomStringConvertible { } } -public struct ParameterList: CustomStringConvertible { +public struct ParameterList: CustomStringConvertible, Equatable { + public static func == (lhs: ParameterList, rhs: ParameterList) -> Bool { + if lhs.parameters.count != rhs.parameters.count { + return false + } + + return 0 + == zip(lhs.parameters, rhs.parameters).count { (lparam, rparam) in + return lparam != rparam + } + } + public var parameters: [Parameter] public init() { @@ -57,3 +72,78 @@ public struct ParameterList: CustomStringConvertible { return "Parameter list: \(parameters)" } } + +public struct FunctionDeclaration: P4Type, P4Value { + public func type() -> any Common.P4Type { + return self + } + + public func eq(rhs: any Common.P4Type) -> Bool { + switch rhs { + case let frhs as FunctionDeclaration: + return frhs.tipe.eq(rhs: self.tipe) && frhs.params == self.params + default: return false + } + } + + public func eq(rhs: any Common.P4Value) -> Bool { + switch rhs { + case let frhs as FunctionDeclaration: return self.eq(rhs: frhs as P4Type) + default: return false + } + } + + public func lt(rhs: any Common.P4Value) -> Bool { + switch rhs { + case let frhs as FunctionDeclaration: return self.name < frhs.name + default: return false + } + } + + public func lte(rhs: any Common.P4Value) -> Bool { + switch rhs { + case let frhs as FunctionDeclaration: return self.name <= frhs.name + default: return false + } + + } + + public func gt(rhs: any Common.P4Value) -> Bool { + switch rhs { + case let frhs as FunctionDeclaration: return self.name > frhs.name + default: return false + } + } + + public func gte(rhs: any Common.P4Value) -> Bool { + switch rhs { + case let frhs as FunctionDeclaration: return self.name >= frhs.name + default: return false + } + } + + public func def() -> any Common.P4Value { + return FunctionDeclaration( + named: Identifier(name: ""), ofType: P4Boolean(), withParameters: ParameterList([]), + withBody: .none) + } + + public var description: String { + return "Function named \(self.name) that returns \(self.tipe) with parameters \(self.params)" + } + + public var body: EvaluatableStatement? + public var params: ParameterList + public var name: Identifier + public var tipe: P4Type + + public init( + named name: Identifier, ofType type: P4Type, withParameters parameters: ParameterList, + withBody body: EvaluatableStatement? + ) { + self.name = name + self.tipe = type + self.params = parameters + self.body = body + } +} diff --git a/Tests/p4rseTests/Declarations.swift b/Tests/p4rseTests/Declarations.swift index 3669c8c..331aff0 100644 --- a/Tests/p4rseTests/Declarations.swift +++ b/Tests/p4rseTests/Declarations.swift @@ -146,3 +146,23 @@ import TreeSitterP4 let (state_result, _) = try! #UseOkResult(runtime.run()) #expect(AsInstantiatedParserState(state_result) == P4Lang.reject) } + +@Test func test_function_declaration() async throws { + let simple_parser_declaration = """ + bool functionb() { + int count; + }; + """ + #expect(#RequireOkResult(Program.Compile(simple_parser_declaration))) +} + + +@Test func test_function_declaration_with_parameters() async throws { + let simple_parser_declaration = """ + bool functionb(bool x) { + x = true; + }; + """ + #expect(#RequireOkResult(Program.Compile(simple_parser_declaration))) +} +