// 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 . import ArgumentParser import Common import P4Compiler import P4Runtime import SystemPackage @main struct Cli: ParsableCommand { @Flag(help: "Disable ANSI-stylized output.") var plain: Int static let configuration = CommandConfiguration( abstract: "P4CE compiler, interpreter and debugger.", subcommands: [Compile.self, CodeGen.self]) } struct CliOptions: ParsableArguments { @ArgumentParser.Argument(help: "File to compile.") // Have to be explicit because Common has an Argument, too! var path: String @Option(name: [.customShort("I")], help: "Search paths.") var search: [String] = [] } extension Cli { struct Compile: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Compile P4CE code.") @ParentCommand var parent: Cli @OptionGroup var options: CliOptions mutating func run() { let sm = SourceManager(options.search.map { FilePath($0) }) let prep = SourceCodePreprocessor(sm) let file = FilePath(options.path) let formatter: any Formattable = if parent.plain != 0 { FormatterPlain() } else { FormatterAnsi() } let maybe_source = prep.preprocess(file) guard case .Ok(let source) = maybe_source else { print(ErrorWithLabel("Preprocessor Error", maybe_source.error()!).format(formatter)) return } let maybe_program = Program.Compile(source.getSource()) guard case .Ok(_) = maybe_program else { print(ErrorWithLabel("Compiler Error", maybe_source.error()!).format(formatter)) return } print( formatter.formatWithStyle( "Success", Style(StyleColor.Green, [StyleFormat.Underline]))) } } } extension Cli { struct CodeGen: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Generate P4CE code.") @ParentCommand var parent: Cli @OptionGroup var options: CliOptions mutating func run() { let sm = SourceManager(options.search.map { FilePath($0) }) let prep = SourceCodePreprocessor(sm) let file = FilePath(options.path) let formatter: any Formattable = if parent.plain != 0 { FormatterPlain() } else { FormatterAnsi() } let maybe_source = prep.preprocess(file) guard case .Ok(let source) = maybe_source else { print(ErrorWithLabel("Preprocessor Error", maybe_source.error()!).format(formatter)) return } let maybe_program = Program.Compile(source.getSource()) guard case .Ok(let program) = maybe_program else { print(ErrorWithLabel("Compiler Error", maybe_source.error()!).format(formatter)) return } let maybe_codegen = P4Runtime.CodeGenerator().codeGen(program) guard case .Ok(let codegen) = maybe_codegen else { let formatter = FormatterAnsi() print(ErrorWithLabel("Code Generation Error", maybe_codegen.error()!).format(formatter)) return } print("\(codegen.getGeneratedCode())") } } }