take_until
for line 5 instead of many0
too
terminated(many0(is_not("*")), tag("*")),
) is usually frowned upon and rarely what you want for languages which can 'nest' features/syntax in a tree. In this case, you want to recurse back to some parser instead of consuming the bytes.
<geometry>
, but an array of geometry (ie: [4]<geometry>
) is also valid. To parse this, I have a nom parser which matches and parses the [4] thing, but then recurses to get the nested parse fragment.
use nom_parser_derive::*;
use nom_parser::Parsable;
use nom_parser::ParseResult;
use nom::combinator::{opt};
use nom::sequence::{tuple};
use nom::bytes::complete::{tag};
use nom::character::complete::{ digit1};
#[derive(Parser,PartialEq,Clone,Debug)]
pub enum BinaryExpression{
#[nom(tuple(field(0),tag(" + "),field(1)))]
Add(Number,Number),
#[nom(tuple(field(0),tag(" - "),field(1)))]
Subtract(Number,Number),
#[nom(tuple(field(0),tag(" * "),field(1)))]
Multiply(Number,Number),
#[nom(tuple(field(0),tag(" / "),field(1)))]
Divide(Number,Number)
}
impl BinaryExpression{
pub fn apply(&self)->Number{
match self {
Self::Add(one,two)=>{
return Number(one.0+two.0)
},
Self::Subtract(one,two)=>{
return Number(one.0-two.0)
},
Self::Multiply(one,two)=>{
return Number(one.0*two.0)
},
Self::Divide(one,two)=>{
return Number(one.0/two.0)
}
}
}
}
#[derive(Parser,PartialEq,Clone,Debug)]
pub struct Number(#[nom(func(parse_isize))]isize);
fn parse_isize<'a>(input:&'a str) ->ParseResult<'a,isize>{
let mut num = tuple((opt(tag("-")),digit1));
let (i,(sign,nums)) = num(input)?;
let str_num=format!("{}",nums);
let f_num=str_num.parse::<isize>().unwrap();
if let Some(_)=sign{
Ok((i,(f_num * -1)))
} else {
Ok((i,f_num))
}
}
fn main() {
let (_,expr) = BinaryExpression::parse("1 + 2").unwrap();
assert_eq!(expr,BinaryExpression::Add(Number(1),Number(2)));
assert_eq!(expr.apply(),Number(3));
let (_,expr) = BinaryExpression::parse("1 - 2").unwrap();
assert_eq!(expr,BinaryExpression::Subtract(Number(1),Number(2)));
assert_eq!(expr.apply(),Number(-1));
let (_,expr) = BinaryExpression::parse("4 * 2").unwrap();
assert_eq!(expr,BinaryExpression::Multiply(Number(4),Number(2)));
assert_eq!(expr.apply(),Number(8));
let (_,expr) = BinaryExpression::parse("4 / 3").unwrap();
assert_eq!(expr,BinaryExpression::Divide(Number(4),Number(3)));
assert_eq!(expr.apply(),Number(1));
}
use nom_parser_derive::*;
use nom_parser::Parsable;
use nom_parser::ParseResult;
use nom::sequence::{tuple};
use nom::branch::alt;
use nom::character::complete::{alpha1, alphanumeric1};
use nom::multi::many0;
use nom::bytes::complete::tag;
#[derive(Parser,PartialEq,Debug,Clone)]
#[nom(tuple(tag("fn"),field(identifier),tag("("),field(args),tag(")"),tag("{"),field(statements),tag("}")))]
pub struct Function{
identifier:Identifier,
#[nom(separated_list0(tag(","),field))]
args:Vec<Argument>,
#[nom(many0(terminated(field,tag(";"))))]
statements:Vec<Statement>
}
#[derive(Parser,PartialEq,Debug,Clone)]
#[nom(tuple(field(name),field(field_type)))]
pub struct Argument{
name:Identifier,
#[nom(opt(tuple(tag(":"),field)))]
field_type:Option<Type>
}
#[derive(Parser,PartialEq,Debug,Clone)]
pub enum Statement{
#[nom(tag("Hello"))]
Hello,
#[nom(tag("World"))]
World
}
#[derive(Parser,PartialEq,Debug,Clone)]
pub struct Identifier(#[nom(func(ident))]String);
pub fn ident<'a>(input: &'a str) -> ParseResult<'a,String> {
nom::combinator::map(tuple((
alt((alpha1,tag("_"))),
many0(alphanumeric1))),|(a,b)|{format!("{}{}",a,b.join(""))})
(input)
}
#[derive(Parser,PartialEq,Debug,Clone)]
pub enum Type{
#[nom(tag("Int"))]
Int,
#[nom(tag("String"))]
String
}
fn main() {
let (_,val) = Function::parse("fn hello( a : String , b ){ Hello; World; } ").unwrap();
assert_eq!(val,Function{
identifier:Identifier("hello".to_string()),
args:vec![Argument{
name:Identifier("a".to_string()),
field_type:Some(Type::String)
},
Argument{
name:Identifier("b".to_string()),
field_type:None
}
],
statements:vec![Statement::Hello,Statement::World]
});
}
Simple Function Parser
@CSUwangj , while doing some research I stumbled upon this. https://github.com/chipsenkbeil/vimwiki-rs. I thought you might find it helpful
thanks! I'll check it
digits1
and parse_to
FromStr
implemented for an enum. I want to be able to build up a more complex parser without a bunch of tag(...)
calls that duplicate the strings in FromStr
. Here's a small example of what I mean: https://gist.github.com/detly/1e03c0adcbdfc27eb1de9650519b923a
let result: ParseResult<Flip> = after_slash(/* what goes here? */)(input)
so I can build up more and more complex parsers with combinators. I'm aware of parse_to!()
but it requires the input right there in the macro call, so I can't see how to use it to build things up.
alpha1
and try FromStr
on it.
after_slash(<&str>::parse_to)
but because parse_to()
returns an Option
(???) and everything else in nom expects a Result
I can't just slot it in.
map_res(alpha1, |word| Flip::from_str(word))
should work
preceded(char('|', map_res(is_not(","), TypeA::from_str)))
but there's a lot of them.
use of moved value: 'item'
cond
or may be alt
with cond
Hi everyone. I'm trying to move from nom 5 to 6 and got some issues with context
. My old code which works ok with v5 is this:
fn my_number<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, MyToken, E> {
let (i, num) = context("my_number", take_while1(move |c| c >= '0' && c <= '9'))(i)?;
Compiles with the following error when I use v6:
the trait bound `E: nom::error::ContextError<&str>` is not satisfied
the trait `nom::error::ContextError<&str>` is not implemented for `E`rustc(E0277)
For now the single solution I came up with is just to remove context
. Is there a way to fix this error without removing it?
map_res
can do that, but it doesn't makes sense to use it in my case because I'm not parsing anything (I'm decompressing bytes already parsed)
Vec<u8>
buffer, decompress into it, and then pass it to the parsing function. But, all nom parsing functions return a reference to the input (the remaining input slice) so I keep getting returns a value referencing data owned by the current function
error. Is there a pattern for this that I'm missing?