use crate::pest::*;
use pest::iterators::Pair;
use std::fs;
use vek::geom::repr_c::Aabr;
use vek::Vec2;
#[derive(Parser)]
#[grammar = "xvi.pest"]
pub struct XVIParser;
#[derive(Debug)]
pub struct Station {
pub pos: Vec2<f64>,
pub name: String,
}
#[derive(Debug)]
pub struct Shot {
pub start: Vec2<f64>,
pub end: Vec2<f64>,
}
#[derive(Debug)]
pub struct Sketchline {
pub color: String,
pub points: Vec<Vec2<f64>>,
}
#[derive(Debug)]
pub struct Xvi {
pub stations: Vec<Station>,
pub shots: Vec<Shot>,
pub sketchlines: Vec<Sketchline>,
pub bounds: Aabr<f64>,
}
pub fn parse_string(unparsed_file: String) -> Xvi {
let file = XVIParser::parse(Rule::file, &unparsed_file)
.expect("unsuccessful parse") .next()
.unwrap();
fn parse_coordinates<R>(pair: Pair<R>) -> Vec2<f64>
where
R: RuleType,
{
let mut inner_rules = pair.into_inner();
{
Vec2 {
x: inner_rules.next().unwrap().as_str().parse().unwrap(),
y: inner_rules.next().unwrap().as_str().parse().unwrap(),
}
}
}
let mut stations: Vec<Station> = Vec::new();
let mut shots: Vec<Shot> = Vec::new();
let mut sketchlines: Vec<Sketchline> = Vec::new();
let mut boundlist: Vec<Vec2<f64>> = Vec::new();
for line in file.into_inner() {
match line.as_rule() {
Rule::xvigrids => {
let mut inner_rules = line.into_inner(); let gridsval = inner_rules.next().unwrap().as_str();
let gridsunit = inner_rules.next();
println!("xvigrids {:#?} {:#?}", gridsval, gridsunit);
}
Rule::xvigrid => {
let mut inner_rules = line.into_inner();
let origin = parse_coordinates(inner_rules.next().unwrap());
let gridsize1: f64 = inner_rules.next().unwrap().as_str().parse().unwrap();
let unknown1: f64 = inner_rules.next().unwrap().as_str().parse().unwrap();
let unknown2: f64 = inner_rules.next().unwrap().as_str().parse().unwrap();
let gridsize2: f64 = inner_rules.next().unwrap().as_str().parse().unwrap();
let gridextendx: i32 = inner_rules.next().unwrap().as_str().parse().unwrap();
let gridextendy: i32 = inner_rules.next().unwrap().as_str().parse().unwrap();
println!(
"{:?} {:#?} {:#?} {:#?} {:#?} {:#?} {:#?}",
origin, gridsize1, unknown1, unknown2, gridsize2, gridextendx, gridextendy
);
}
Rule::xvistations => {
for station in line.into_inner() {
let mut inner_rules = station.into_inner();
let station = {
Station {
pos: parse_coordinates(inner_rules.next().unwrap()),
name: inner_rules.next().unwrap().to_string(),
}
};
boundlist.push(station.pos);
stations.push(station);
}
}
Rule::xvishots => {
for shot in line.into_inner() {
let mut inner_rules = shot.into_inner();
let shot = {
Shot {
start: parse_coordinates(inner_rules.next().unwrap()),
end: parse_coordinates(inner_rules.next().unwrap()),
}
};
boundlist.push(shot.start);
boundlist.push(shot.end);
shots.push(shot);
}
}
Rule::xvisketchlines => {
for shot in line.into_inner() {
let mut inner_rules = shot.into_inner();
let color = inner_rules.next().unwrap().as_str().to_string(); let mut points: Vec<Vec2<f64>> = Vec::new();
for coords in inner_rules {
let coords = parse_coordinates(coords);
boundlist.push(coords);
points.push(coords)
}
sketchlines.push( Sketchline { color, points } );
}
}
Rule::EOI => (),
_ => unreachable!("no handler for {:#?}", line.as_rule()),
}
}
let mut biter = boundlist.into_iter();
let mut bounds: Aabr<f64> = Aabr::new_empty(biter.next().unwrap());
for coords in biter {
bounds.expand_to_contain_point(coords);
}
bounds.make_valid();
{
Xvi {
stations,
shots,
sketchlines,
bounds,
}
}
}
pub fn parse_file(filename: String) -> Xvi {
parse_string(fs::read_to_string(filename).expect("cannot read file"))
}
#[cfg(test)]
mod test {
use super::Rule;
use super::XVIParser;
use crate::pest::*;
#[test]
fn successful_parse() {
parses_to! {
parser: XVIParser,
input: "1.0",
rule: Rule::NUMBER,
tokens: [NUMBER( 0, 3)]
};
parses_to! {
parser: XVIParser,
input: "XVIgrids {1.0 m}\n",
rule: Rule::xvigrids,
tokens: [xvigrids(0, 16, [NUMBER(10, 13), ])]
};
parses_to! {
parser: XVIParser,
input: "XVIgrids {1.0 m}",
rule: Rule::xvigrids,
tokens: [xvigrids(0, 16, [NUMBER(10, 13), ])]
};
parses_to! {
parser: XVIParser,
input: "{1111.22 1533.50 2.75}",
rule: Rule::station,
tokens: [station(0, 22, [COORDINATE(1, 16, [NUMBER(1, 8), NUMBER(9, 16)]), NAME(17, 21)])]
};
parses_to! {
parser: XVIParser,
input: "XVIstations {\n {1037.95 236.26 2.54}\n {1107.91 337.68 2.55}\n}",
rule: Rule::xvistations,
tokens: [
xvistations( 0, 67,[
station( 18, 39,
[COORDINATE(19, 33, [NUMBER(19, 26), NUMBER(27, 33)]), NAME(34, 38)]
),
station( 44, 65,
[COORDINATE(45, 59, [NUMBER(45, 52), NUMBER(53, 59)]), NAME(60, 64)]
),
])]
};
parses_to! {
parser: XVIParser,
input: "{3032.80 830.51 3033.19 841.42}",
rule: Rule::shot,
tokens: [
shot(0, 31, [
COORDINATE(1, 15, [NUMBER(1, 8),
NUMBER(9, 15)]),
COORDINATE(16, 30, [NUMBER(16, 23),
NUMBER(24, 30)])
])]
};
parses_to! {
parser: XVIParser,
input: "XVIshots {\n {3032.80 830.51 3033.19 841.42}\n {3033.19 841.42 2974.53 894.33}\n}",
rule: Rule::xvishots,
tokens: [xvishots(0, 84,[
shot(15, 46, [
COORDINATE(16, 30, [ NUMBER(16, 23),
NUMBER(24, 30)]),
COORDINATE(31, 45, [NUMBER(31, 38),
NUMBER(39, 45)])
]),
shot(51, 82, [
COORDINATE(52, 66, [NUMBER(52, 59),
NUMBER(60, 66)]),
COORDINATE(67, 81, [NUMBER(67, 74),
NUMBER(75, 81)])
])
])
]
};
parses_to! {
parser: XVIParser,
input: "{brown 2932.87 685.63 2928.15 686.22}",
rule: Rule::scetchline,
tokens: [
scetchline(0,39, [
COLOR(1, 6),
COORDINATE(8, 22, [NUMBER(8, 15), NUMBER(16, 22)]),
COORDINATE(24, 38, [NUMBER(24, 31), NUMBER(32, 38)])
])]
};
parses_to! {
parser: XVIParser,
input: "XVIsketchlines {\n {brown 2.3 2.6 7 3 1.81 4.17}\n {black 39.37 6.61}\n}",
rule: Rule::xvisketchlines,
tokens: [xvisketchlines(0, 79, [
scetchline(21,53, [
COLOR(22, 27),
COORDINATE(29, 36, [NUMBER(29, 32), NUMBER(33, 36)]),
COORDINATE(38, 41, [NUMBER(38, 39), NUMBER(40, 41)]),
COORDINATE(43, 52, [NUMBER(43, 47), NUMBER(48, 52)]),
]),
scetchline(58,77, [
COLOR(59, 64),
COORDINATE(66, 76, [NUMBER(66, 71), NUMBER(72, 76)]),
])
])]
}
}
}