Skip to content

Instantly share code, notes, and snippets.

@hsk
Last active July 31, 2021 01:01
Show Gist options
  • Save hsk/87b235cd37f152c727c36559f426a981 to your computer and use it in GitHub Desktop.
Save hsk/87b235cd37f152c727c36559f426a981 to your computer and use it in GitHub Desktop.
use nom;
use nom::{
bytes::complete::{tag, take_until, take_while1},
branch::alt,
character::complete::{char, multispace0},
combinator::{map, cut},
error::VerboseError,
multi::{many1,separated_list0},
sequence::{preceded, terminated, tuple, separated_pair},
IResult,
};
fn spaces(s: &str) -> IResult<&str, (), VerboseError<&str>> {
alt((
map(
many1(tuple((
multispace0,
preceded(char(';'), terminated(take_until("\n"), char('\n'))),
multispace0,
))),
|_| (),
),
map(multispace0, |_| ()),
))(s)
}
fn string_literal(s: &str) -> IResult<&str, &str, VerboseError<&str>> {
preceded(char('\"'), cut(terminated(take_until("\""), char('\"'))))(s)
}
fn identifier(s: &str) -> IResult<&str, &str, VerboseError<&str>> {
take_while1(|c: char| c.is_alphanumeric() || c == '.' || c == '_')(s)
}
#[test]
fn identifier_test() {
assert_eq!(identifier("llvm.module.flags"),Ok(("","llvm.module.flags")));
assert_eq!(identifier("0"),Ok(("","0")));
}
fn parse_metadata(s: &str) -> IResult<&str, (&str, Vec<(&str,&str)>), VerboseError<&str>> {
fn mid(s: &str) -> IResult<&str, &str, VerboseError<&str>> {
preceded(spaces,preceded(char('!'), identifier))(s)
}
fn mtids(s: &str) -> IResult<&str, Vec<(&str,&str)>, VerboseError<&str>> {
map(tuple((spaces,char('!'),spaces,char('{'),
separated_list0(preceded(spaces,tag(",")), mtid),spaces,char('}'))),
|(_,_,_,_,r,_,_)| r)(s)
}
fn mtid(s: &str) -> IResult<&str, (&str,&str), VerboseError<&str>> {
preceded(spaces,tuple((alt((tag("!"),identifier)),value)))(s)
}
fn value(s: &str) -> IResult<&str, &str, VerboseError<&str>> {
preceded(spaces,alt((identifier,string_literal)))(s)
}
separated_pair(mid, preceded(spaces,tag("=")), mtids)(s)
}
#[test]
fn parse_metadata_test() {
let s = "
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !\"wchar_size\", i32 4}
!1 = !{!\"clang version 10.0.0-4ubuntu1 \"}
!llvm.module.flags = !{!0, !1, !2}
!0 = !{i32 7, !\"PIC Level\", i32 2}
!1 = !{i32 7, !\"PIE Level\", i32 2}
!2 = !{i32 2, !\"RtLibUseGOT\", i32 1}
!3 = !{}
!4 = !{i32 2849348}
!4 = !{i32 2849319}
!4 = !{i32 2849383}";
assert_eq!(many1(parse_metadata)(s),Ok(("",vec![
("llvm.module.flags", vec![("!", "0")]),
("llvm.ident", vec![("!", "1")]),
("0", vec![("i32", "1"), ("!", "wchar_size"), ("i32", "4")]),
("1", vec![("!", "clang version 10.0.0-4ubuntu1 ")]),
("llvm.module.flags", vec![("!", "0"), ("!", "1"), ("!", "2")]),
("0", vec![("i32", "7"), ("!", "PIC Level"), ("i32", "2")]),
("1", vec![("i32", "7"), ("!", "PIE Level"), ("i32", "2")]),
("2", vec![("i32", "2"), ("!", "RtLibUseGOT"), ("i32", "1")]),
("3", vec![]),
("4", vec![("i32", "2849348")]),
("4", vec![("i32", "2849319")]),
("4", vec![("i32", "2849383")])
])));
}
fn main() {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment