Skip to content

Instantly share code, notes, and snippets.

@boringcactus
Created April 6, 2021 03:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boringcactus/60b852ebd9d8cdcf652d8f748c15c7df to your computer and use it in GitHub Desktop.
Save boringcactus/60b852ebd9d8cdcf652d8f748c15c7df to your computer and use it in GitHub Desktop.
rustc infinite loop
use nom::{
branch::alt,
bytes::complete::tag,
combinator::{map, opt},
multi::{fold_many1, many1},
sequence::{delimited, pair, preceded},
IResult,
};
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Token {
Text(String),
MacroExpansion {
name: Vec<Token>,
replacement: Option<(Vec<Token>, Vec<Token>)>,
},
FunctionCall {
name: Vec<Token>,
args: Vec<Vec<Token>>,
},
}
fn macro_or_function_name<'a>(
end: char,
) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Token>> + 'a {
tokens(vec![':', '#', '=', ' ', end])
}
fn macro_expansion_body<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> + 'a {
let subst = preceded(tag(":"), pair(tokens(vec!['=']), tokens(vec![end])));
map(
pair(macro_or_function_name(end), opt(subst)),
|(name, replacement)| Token::MacroExpansion { name, replacement },
)
}
fn function_call_body<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> {
map(
pair(macro_or_function_name(end), many1(tokens(vec![',', end]))),
|(name, args)| Token::FunctionCall { name, args },
)
}
fn macro_body<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> {
alt((function_call_body(end), macro_expansion_body(end)))
}
fn macro_expansion(input: &str) -> IResult<&str, Vec<Token>> {
map(macro_body(')'), |x| vec![x])(input)
}
fn nested_delimiters<'a>(ends: Vec<char>) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Token>> {
delimited(tag("("), tokens(ends), tag(")"))
}
fn single_token<'a>(ends: Vec<char>) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Token>> {
alt((macro_expansion, nested_delimiters(ends)))
}
fn fold_tokens<'a>(
parser: impl FnMut(&'a str) -> IResult<&'a str, Vec<Token>>,
) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Token>> {
fold_many1(parser, vec![], |mut acc, x| {
acc.extend(x);
acc
})
}
fn tokens<'a>(ends: Vec<char>) -> impl FnMut(&'a str) -> IResult<&'a str, Vec<Token>> {
fold_tokens(single_token(ends))
}
pub fn tokenize(input: &str) -> Vec<Token> {
let (_, result) = tokens(vec![])(input).map_err(drop).unwrap();
result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment