use std::str::FromStr;
use crate::{
arg_err,
attribute::AttrObj,
basic_block::BasicBlock,
context::Ptr,
debug_info::set_operation_result_name,
identifier::Identifier,
location::{Located, Location},
operation::Operation,
parsable::{IntoParseResult, Parsable, ParseResult, StateStream},
result::Result,
r#type::TypeObj,
value::Value,
};
use combine::{
Parser, Stream, any, between, many, many1, none_of,
parser::char::{digit, spaces},
sep_by, token,
};
pub fn spaced<Input: Stream<Token = char>, Output>(
parser: impl Parser<Input, Output = Output>,
) -> impl Parser<Input, Output = Output> {
combine::between(spaces(), spaces(), parser)
}
pub fn location<'a>() -> Box<dyn Parser<StateStream<'a>, Output = Location, PartialState = ()> + 'a>
{
combine::parser(|parsable_state: &mut StateStream<'a>| {
combine::ParseResult::PeekOk(parsable_state.loc()).into()
})
.boxed()
}
pub fn type_parser<'a>()
-> Box<dyn Parser<StateStream<'a>, Output = Ptr<TypeObj>, PartialState = ()> + 'a> {
Ptr::<TypeObj>::parser(())
}
pub fn int_parse<'a, IntT>(state_stream: &mut StateStream<'a>, _arg: ()) -> ParseResult<'a, IntT>
where
IntT: FromStr,
IntT::Err: std::error::Error + Send + Sync + 'static,
{
many1::<String, _, _>(digit())
.and_then(|digits| digits.parse::<IntT>())
.parse_stream(state_stream)
.into()
}
pub fn int_parser<'a, IntT>()
-> Box<dyn Parser<StateStream<'a>, Output = IntT, PartialState = ()> + 'a>
where
IntT: FromStr,
IntT::Err: std::error::Error + Send + Sync + 'static,
{
combine::parser(move |parsable_state: &mut StateStream<'a>| int_parse(parsable_state, ()))
.boxed()
}
pub fn quoted_string_parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: (),
) -> ParseResult<'a, String> {
let escaped_char = combine::parser(move |parsable_state: &mut StateStream<'a>| {
let loc = parsable_state.loc();
let mut escaped_char = token('\\').with(any()).then(move |c: char| {
let loc = loc.clone();
combine::parser(move |_parsable_state: &mut StateStream<'a>| {
let result = match c {
'\\' => Ok('\\'),
'\"' => Ok('\"'),
_ => arg_err!(loc.clone(), "Unexpected escaped character \\{}", c),
};
result.into_parse_result()
})
});
escaped_char.parse_stream(parsable_state).into()
});
let quoted_string = between(
token('"'),
token('"'),
many(escaped_char.or(none_of("\"".chars()))),
);
quoted_string
.map(|chars: Vec<char>| {
chars.into_iter().collect::<String>()
})
.parse_stream(state_stream)
.into()
}
pub fn quoted_string_parser<'a>()
-> Box<dyn Parser<StateStream<'a>, Output = String, PartialState = ()> + 'a> {
combine::parser(move |parsable_state: &mut StateStream<'a>| {
quoted_string_parse(parsable_state, ())
})
.boxed()
}
pub fn attr_parser<'a>()
-> Box<dyn Parser<StateStream<'a>, Output = AttrObj, PartialState = ()> + 'a> {
AttrObj::parser(())
}
pub fn delimited_list_parser<Input: Stream<Token = char>, Output>(
open: char,
close: char,
sep: char,
parser: impl Parser<Input, Output = Output>,
) -> impl Parser<Input, Output = Vec<Output>> {
between(
token(open).skip(spaces()),
spaces().with(token(close)),
list_parser(sep, parser),
)
}
pub fn list_parser<Input: Stream<Token = char>, Output>(
sep: char,
parser: impl Parser<Input, Output = Output>,
) -> impl Parser<Input, Output = Vec<Output>> {
sep_by::<Vec<_>, _, _, _>(parser.skip(spaces()), token(sep).skip(spaces()))
}
pub fn zero_or_more_parser<Input: Stream<Token = char>, Output>(
parser: impl Parser<Input, Output = Output>,
) -> impl Parser<Input, Output = Vec<Output>> {
many::<Vec<_>, _, _>(spaces().with(parser.skip(spaces())))
}
pub fn ssa_opd_parse<'a>(state_stream: &mut StateStream<'a>, _arg: ()) -> ParseResult<'a, Value> {
Identifier::parser(())
.parse_stream(state_stream)
.map(|opd| {
state_stream
.state
.name_tracker
.ssa_use(state_stream.state.ctx, &opd)
})
.into()
}
pub fn ssa_opd_parser<'a>()
-> Box<dyn Parser<StateStream<'a>, Output = Value, PartialState = ()> + 'a> {
combine::parser(move |parsable_state: &mut StateStream<'a>| ssa_opd_parse(parsable_state, ()))
.boxed()
}
pub fn block_opd_parse<'a>(
state_stream: &mut StateStream<'a>,
_arg: (),
) -> ParseResult<'a, Ptr<BasicBlock>> {
token('^')
.with(Identifier::parser(()))
.parse_stream(state_stream)
.map(|opd| {
state_stream
.state
.name_tracker
.block_use(state_stream.state.ctx, &opd)
})
.into()
}
pub fn block_opd_parser<'a>()
-> Box<dyn Parser<StateStream<'a>, Output = Ptr<BasicBlock>, PartialState = ()> + 'a> {
combine::parser(move |parsable_state: &mut StateStream<'a>| block_opd_parse(parsable_state, ()))
.boxed()
}
pub fn process_parsed_ssa_defs(
state_stream: &mut StateStream,
results: &[(Identifier, Location)],
op: Ptr<Operation>,
) -> Result<()> {
let ctx = &mut state_stream.state.ctx;
assert!(
results.len() == op.deref(ctx).get_num_results(),
"Error processing parsed SSA definitions. Result count mismatch"
);
let name_tracker = &mut state_stream.state.name_tracker;
for (idx, name_loc) in results.iter().enumerate() {
let res = op.deref(ctx).get_result(idx);
name_tracker.ssa_def(ctx, name_loc, res)?;
set_operation_result_name(ctx, op, idx, name_loc.0.clone());
}
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
use expect_test::expect;
use crate::{
context::Context,
location,
parsable::{self, state_stream_from_iterator},
printable::Printable,
};
#[test]
fn test_parse_type() {
let mut ctx = Context::new();
let state_stream = state_stream_from_iterator(
"builtin.some".chars(),
parsable::State::new(&mut ctx, location::Source::InMemory),
);
let res = type_parser().parse(state_stream);
let err_msg = format!("{}", res.err().unwrap());
let expected_err_msg = expect![[r#"
Parse error at line: 1, column: 1
Unregistered type builtin.some
"#]];
expected_err_msg.assert_eq(&err_msg);
let state_stream = state_stream_from_iterator(
"builtin.integer a".chars(),
parsable::State::new(&mut ctx, location::Source::InMemory),
);
let res = type_parser().parse(state_stream);
let err_msg = format!("{}", res.err().unwrap());
let expected_err_msg = expect![[r#"
Parse error at line: 1, column: 17
Unexpected `a`
Expected whitespaces, si, ui or i
"#]];
expected_err_msg.assert_eq(&err_msg);
let state_stream = state_stream_from_iterator(
"builtin.integer si32".chars(),
parsable::State::new(&mut ctx, location::Source::InMemory),
);
let parsed = type_parser().parse(state_stream).unwrap().0;
assert_eq!(parsed.disp(&ctx).to_string(), "builtin.integer si32");
}
}