Brought the documentation to an acceptable level.

This commit is contained in:
Thelie 2022-03-27 15:10:20 +02:00
parent ec7ba974da
commit 0873a407f2
5 changed files with 81 additions and 13 deletions

View file

@ -10,6 +10,7 @@ proc-macro = true
[dependencies] [dependencies]
sing_util = { path = "../sing_util" } sing_util = { path = "../sing_util" }
sing_parse = {path = "../sing_parse" }
proc-macro2 = "1.0" proc-macro2 = "1.0"
ron = "0.7" ron = "0.7"
rand = "0.7" rand = "0.7"

View file

@ -10,21 +10,49 @@ use std::{
io::{Read, Write}, io::{Read, Write},
}; };
use syn::{ use syn::{
bracketed, parenthesized, bracketed,
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
parse2, parse_macro_input, Arm, AttributeArgs, FnArg, Ident, ImplItem, ItemImpl, LitStr, Meta, parse2, parse_macro_input, Arm, AttributeArgs, FnArg, Ident, ImplItem, ItemImpl, LitStr, Meta,
NestedMeta, Path, Signature, Stmt, Token, NestedMeta, Path, Signature, Stmt, Token,
}; };
extern crate sing_parse;
extern crate proc_macro; extern crate proc_macro;
extern crate sing_util; extern crate sing_util;
mod keyword; mod keyword;
/// Add the trait in this ipml block to sings trait store. /// Add the trait in this impl block to sings trait store.
/// ///
/// The impl block needs to contain all functions as usual. /// The impl block needs to contain all functions as usual.
/// After adding a trait, it can be used by the sing_loop macro. /// After adding a trait, it can be used by the sing_loop macro.
///
/// ## Example
/// ```
/// trait FruitTree {
/// fn shake(&self, shakes: u32) -> Vec<Fruit>;
/// }
///
/// #[derive(Debug, Serialize, Deserialize)]
/// struct Fruit {
/// fruit_type: String,
/// }
///
/// struct BananaTree;
///
/// #[sing_add_trait()]
/// impl FruitTree for BananaTree {
/// fn shake(&self, shakes: u32) -> Vec<Fruit>{
/// let mut out = vec!();
///
/// for _ in 0..shakes {
/// out.push(Fruit{fruit_type: String::from("Banana")});
/// }
///
/// out
/// }
/// }
/// ```
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn sing_add_trait(annotated_item: TokenStream, input: TokenStream) -> TokenStream { pub fn sing_add_trait(annotated_item: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemImpl); let input = parse_macro_input!(input as ItemImpl);
@ -100,7 +128,38 @@ fn add_trait_inner(input: ItemImpl, annotated_item: Vec<NestedMeta>) -> TokenStr
/// Creates a main loop that parses stdin (or the given input stream), /// Creates a main loop that parses stdin (or the given input stream),
/// evaluates the called function and returns the result. /// evaluates the called function and returns the result.
/// ///
/// TODO: document syntax /// ## Usage
///
/// A call of this macro looks like:
/// ```sing_loop!(trait_object, ser_de <, msg: [msg_type, arg_type]> <, ioe: [input, output, error]>)```
/// where all items in angle brackets are optional.
///
/// with the arguments:
/// - trait_object: An instance of a struct that implements all desired traits.
/// - argument_ser_de: Serialization and deserialization functions. It either looks like `[equal, ser_fun, de_fun]` in which case both messages and arguments are serialized an deserialized by the same functions or `[different, arg_ser_fun, arg_de_fun <, msg_ser_fun, msg_de_fun>` in which case different functions are used.
/// - msg_type: A struct that implements [`sing_util::TraitCallMessage`] and should be used as the message type.
/// - arg_type: The type to which the arguments of function calls should be serialized to.
/// - input: The input Stream. Needs to implement [`std::io::BufRead`].
/// - output: The output Stream. Needs to implement [`std::io::Write`].
/// - error: The error output Stream. Needs to implement [`std::io::Write`].
///
/// `msg`, `ioe`, `equal` and `different` are keywords and need to be used literally in the call.
///
/// The optional parameters have the following defaults:
/// - msg_ser_fun: [`sing_parse::callobj_to_string`]
/// - msg_de_fun: [`sing_parse::callobj_to_string`]
/// - msg_type: [`sing_parse::CallObj`]
/// - arg_type: [`String`]
/// - input: [`std::io::StdinLock`]
/// - output: [`std::io::StdoutLock`]
/// - error: [`std::io::StderrLock`]
///
/// ## Example
/// ```
/// let tree = BananaTree {};
///
/// sing_loop!(tree, [different, ron::to_string, ron::from_str],);
/// ```
#[proc_macro] #[proc_macro]
pub fn sing_loop(input: TokenStream) -> TokenStream { pub fn sing_loop(input: TokenStream) -> TokenStream {
let span = TokenStream2::from(input.clone()).__span(); let span = TokenStream2::from(input.clone()).__span();
@ -443,9 +502,6 @@ struct LoopParams {
} }
impl Parse for LoopParams { impl Parse for LoopParams {
/// Parses a given input into a Loopparams object
/// according to the syntax outlined in the documentation
/// of the sing_loop macro
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let trait_obj = input.parse()?; let trait_obj = input.parse()?;
input.parse::<Token![,]>()?; input.parse::<Token![,]>()?;
@ -500,10 +556,9 @@ impl Parse for LoopParams {
input.parse::<keyword::msg>()?; input.parse::<keyword::msg>()?;
input.parse::<Token![:]>()?; input.parse::<Token![:]>()?;
let content; let content;
parenthesized!(content in input); bracketed!(content in input);
let m_a_type_err_generic = "The msg keyword expects two variables in the following order: (MessageType, ArgumentType),"; let m_a_type_err_generic = "The msg keyword expects two variables in the following order: [MessageType, ArgumentType],";
message_type = match content.parse() { message_type = match content.parse() {
Ok(m) => Some(m), Ok(m) => Some(m),
@ -542,9 +597,9 @@ impl Parse for LoopParams {
input.parse::<Token![:]>()?; input.parse::<Token![:]>()?;
let content; let content;
parenthesized!(content in input); bracketed!(content in input);
let lh_inner = content.lookahead1(); let lh_inner = content.lookahead1();
let ioe_err_generic = "The ioe keyword expects three variables in the following order: (Input, Output, Error),"; let ioe_err_generic = "The ioe keyword expects three variables in the following order: [Input, Output, Error],";
if lh_inner.peek(Ident) { if lh_inner.peek(Ident) {
let r = content.parse()?; let r = content.parse()?;

View file

@ -10,6 +10,7 @@ pub struct CallObj {
data: Vec<String>, data: Vec<String>,
} }
/// Default message representation for the sing_loop! macro.
impl CallObj { impl CallObj {
pub fn new((trait_string, fun_string, index): (Option<String>, String, usize), data: Vec<String>) -> Self { pub fn new((trait_string, fun_string, index): (Option<String>, String, usize), data: Vec<String>) -> Self {
Self{ Self{

View file

@ -9,10 +9,12 @@ mod callobj;
lalrpop_mod!(fun_parser); lalrpop_mod!(fun_parser);
/// Default message serialization function for the sing_loop macro.
pub fn callobj_to_string(o: CallObj) -> Result<String, Box<dyn Error>> { pub fn callobj_to_string(o: CallObj) -> Result<String, Box<dyn Error>> {
Ok(o.to_string()) Ok(o.to_string())
} }
/// Default message deserialization function for the sing_loop macro.
pub fn callobj_from_string(s: String) -> Result<CallObj, Box<dyn Error>> { pub fn callobj_from_string(s: String) -> Result<CallObj, Box<dyn Error>> {
// TODO: This should use a "?", but for some reason the error references s // TODO: This should use a "?", but for some reason the error references s
Ok(fun_parser::CallParser::new().parse(&s).unwrap()) Ok(fun_parser::CallParser::new().parse(&s).unwrap())

View file

@ -46,14 +46,23 @@ pub enum DeduplicatedFunctionProfile {
Multiple(Vec<String>), Multiple(Vec<String>),
} }
/// Needs to be implemented by all structs that are used as /// Needs to be implemented by all structs that are used to represent
/// function calls that are sent through a sing I/O stream /// function calls that are sent through a sing I/O stream
pub trait TraitCallMessage { pub trait TraitCallMessage {
/// The representation of rust data structures that is used internally to store the parameters.
/// Usually also the type used by the I/O stream.
type Representation; type Representation;
/// Returns the called functions name.
fn get_fun_name(&self) -> String; fn get_fun_name(&self) -> String;
/// Returns the name of the trait the function is called from.
fn get_trait_name(&self) -> Option<String>; fn get_trait_name(&self) -> Option<String>;
/// Returns the parameters (or arguments) of the function call.
fn get_params(&self) -> Vec<Self::Representation>; fn get_params(&self) -> Vec<Self::Representation>;
/// Replaces the parameters currently stored in this TraitCallMessage object.
fn new_params(&mut self, p: Vec<Self::Representation>); fn new_params(&mut self, p: Vec<Self::Representation>);
} }