feat(bin): Add a binary, that helps in showing the generated code

This commit is contained in:
Benedikt Peetz 2024-03-26 10:51:11 +01:00
parent eb7a901d09
commit ec929dabe5
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
5 changed files with 270 additions and 1 deletions

View File

@ -41,12 +41,19 @@ libc ={ version = "0.2.153", optional = true}
log = { version = "0.4.21", optional = true}
[dev-dependencies]
anyhow = "1.0.81"
# parser
pretty_assertions = "1.4.0"
[features]
default = ["parser", "types", "macros"]
default = ["parser", "types", "macros", "build-binary"]
# default = ["parser", "types", "macros"]
build-binary = ["clap", "parser", "types", "macros"]
parser = [ "regex", "thiserror", "convert_case" ]
types = [ "parser", "libc", "log", "proc-macro2", "quote", "syn", "thiserror", "convert_case" ]
macros = [ "parser", "types", "prettyplease", "proc-macro2", "quote", "syn", "convert_case" ]
[[bin]]
name = "trixy"
required-features = ["build-binary"]

120
src/bin/trixy/cli.rs Normal file
View File

@ -0,0 +1,120 @@
#![deny(missing_docs)]
//! Wonderful command line interface
use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Parser)]
#[command(version, about, long_about = None)]
#[command(propagate_version = true)]
#[command(disable_colored_help = false)]
#[command(color = clap::ColorChoice::Auto)]
/// A helper CLI to work with Trixy files
pub struct Cli {
/// The Trixy API file to use
#[arg(/* short = 'f', long, */value_name = "FILE")]
pub api_file: PathBuf,
#[command(subcommand)]
/// The mode in which to work with the file
pub mode: Mode,
}
#[derive(Subcommand)]
/// A way to work with a Trixy file
pub enum Mode {
/// Perform operations on the Trixy file, without involving the code gen
Parse {
#[command(subcommand)]
/// How to parse the file
parse_command: ParseCommand,
},
/// Involving the code gen, when working with a trixy file
Generate {
/// The languages to generate for
#[arg(
short,
long,
value_name = "LANGUAGE",
value_enum,
default_value = "all",
global = true
)]
language: Language,
#[command(subcommand)]
/// What to generate from the file
gen_command: GenCommand,
},
}
#[derive(Subcommand, Clone, Copy)]
/// Specify what to parse
pub enum ParseCommand {
/// Only replace the regex replacements in the file
Replace,
/// Only try to tokenize the file
#[command(visible_alias = "lex")]
Tokenize,
/// Check syntax, without type checking
Parse,
/// Check syntax and perform a type check
Process,
/// Act on the file as the `trixy-parser` crate would do it
Library,
}
#[derive(Subcommand, Clone, Copy)]
/// Specify what to generate
pub enum GenCommand {
/// Generate host code for a language
Host,
/// Generate auxiliary code for a language
Auxiliary,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
/// Which language to generate the code in
///
/// If you, for example, specified to generate auxiliary files, than setting this to c means, that we generate c
/// header files.
pub enum Language {
/// c
C,
/// Rust
Rust,
/// lua
Lua,
/// All supported languages
All,
}
impl From<trixy::macros::config::trixy::Language> for Language {
fn from(value: trixy::macros::config::trixy::Language) -> Self {
match value {
trixy::macros::config::trixy::Language::Rust => Self::Rust,
trixy::macros::config::trixy::Language::C => Self::C,
trixy::macros::config::trixy::Language::Lua => Self::Lua,
trixy::macros::config::trixy::Language::All => Self::All,
}
}
}
impl From<Language> for trixy::macros::config::trixy::Language {
fn from(value: Language) -> Self {
match value {
Language::C => Self::C,
Language::Rust => Self::Rust,
Language::Lua => Self::Lua,
Language::All => Self::All,
}
}
}

20
src/bin/trixy/generate.rs Normal file
View File

@ -0,0 +1,20 @@
use std::path::Path;
use trixy::macros::config::trixy::TrixyConfig;
use crate::cli::{GenCommand, Language};
pub fn handle(gen_command: GenCommand, language: Language, api_file: &Path) {
let base_config = TrixyConfig::new("callback_function")
.trixy_path(api_file.to_owned())
.dist_dir_path("dist")
.out_dir("out/dir");
match gen_command {
GenCommand::Host => {
let file_tree = base_config.generate();
println!("{}", file_tree);
}
GenCommand::Auxiliary => todo!(),
}
}

46
src/bin/trixy/main.rs Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2023 - 2024:
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
*
* This file is part of the Trixy crate for Trinitrix.
*
* Trixy is free software: you can redistribute it and/or modify
* it under the terms of the Lesser 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
* and the Lesser GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/
use clap::Parser;
use crate::cli::Cli;
pub mod generate;
pub mod parse;
pub mod cli;
pub fn main() {
let args = Cli::parse();
match args.mode {
cli::Mode::Parse { parse_command } => parse::handle(parse_command, &args.api_file),
cli::Mode::Generate {
language,
gen_command,
} => generate::handle(gen_command, language, &args.api_file),
}
}
#[test]
fn verify_cli() {
use clap::CommandFactory;
Cli::command().debug_assert()
}

76
src/bin/trixy/parse.rs Normal file
View File

@ -0,0 +1,76 @@
use std::{fs, path::Path, process};
use trixy::parser::{
command_spec::{checked, unchecked},
lexing::TokenStream,
parse_trixy_lang,
};
use crate::cli::ParseCommand;
pub fn handle(parse_command: ParseCommand, api_file: &Path) {
let input = fs::read_to_string(api_file).unwrap();
let input_tokens = tokenize(&input);
let parsed = parse_unchecked(input_tokens.clone());
let processed = process(parsed.clone(), input.clone());
match parse_command {
// These also map the path the file undergoes when it is put into the [`parse_trixy_lang`]
// function.
ParseCommand::Replace => {
let parsed = TokenStream::replace(&input);
println!("{}", parsed);
}
ParseCommand::Tokenize => {
println!("{:#?}", input_tokens);
}
ParseCommand::Parse => {
println!("{:#?}", parsed);
}
ParseCommand::Process => {
println!("{:#?}", processed);
}
ParseCommand::Library => {
let parsed = parse_trixy_lang(&input).unwrap_or_else(|err| {
eprintln!("{}", err);
process::exit(1);
});
println!("{:#?}", parsed);
}
}
}
fn tokenize(input: &str) -> TokenStream {
match TokenStream::lex(&input) {
Ok(ok) => ok,
Err(err) => {
eprintln!("Error while tokenizing:");
eprintln!("{}", err);
process::exit(1);
}
}
}
fn parse_unchecked(token_stream: TokenStream) -> unchecked::CommandSpec {
match token_stream.parse_unchecked() {
Ok(ok) => ok,
Err(err) => {
eprintln!("Error while doing the first (unchecked) parsing run:");
eprintln!("{}", err);
process::exit(1);
}
}
}
fn process(command_spec: unchecked::CommandSpec, input: String) -> checked::CommandSpec {
match command_spec.process(input) {
Ok(ok) => ok,
Err(err) => {
eprintln!("Error while doing the second (checked) parsing run:");
eprintln!("{}", err);
process::exit(1);
}
}
}