Skip to content

Commit

Permalink
topsky: make parsing more robust
Browse files Browse the repository at this point in the history
  • Loading branch information
globin committed Mar 9, 2024
1 parent 439853a commit bba17f4
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 16 deletions.
18 changes: 11 additions & 7 deletions src/topsky/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,22 +258,22 @@ impl Text {

#[derive(Clone, Debug, Reflect, Serialize)]
pub enum FontSize {
Exact(i32),
Add(i32),
Subtract(i32),
Multiply(i32),
Exact(f64),
Add(f64),
Subtract(f64),
Multiply(f64),
Default,
}

impl FontSize {
fn parse(pair: Pair<Rule>) -> Self {
let mut fontsize = pair.into_inner();
if fontsize.as_str() == "0" {
let default_or_modifier = fontsize.next().unwrap();
if matches!(default_or_modifier.as_rule(), Rule::fontsize_default) {
Self::Default
} else {
let modifier = fontsize.next().unwrap().as_str();
let size = fontsize.next().unwrap().as_str().parse().unwrap();
match modifier {
match default_or_modifier.as_str() {
"=" => Self::Exact(size),
"+" => Self::Add(size),
"-" => Self::Subtract(size),
Expand Down Expand Up @@ -343,6 +343,7 @@ pub enum MapRule {
Color(String),
AsrData,
Active(Active),
Global,
ScreenSpecific,
Layer(i32),
Symbol(MapSymbol),
Expand Down Expand Up @@ -379,10 +380,13 @@ impl MapRule {
Rule::mapline => Some(MapRule::Line(MapLine::parse(pair))),
Rule::text => Some(MapRule::Text(Text::parse(pair))),
Rule::screen_specific => Some(MapRule::ScreenSpecific),
Rule::global => Some(MapRule::Global),
// TODO
Rule::circle => None,
Rule::coordline => None,
Rule::coord => None,
Rule::coordpoly => None,
Rule::fontstyle => None,
_ => {
eprintln!("unhandled {ruletype:?}");
unreachable!()
Expand Down
46 changes: 46 additions & 0 deletions src/topsky/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ fn parse_symbol_rules(pairs: Pairs<Rule>) -> Vec<SymbolRule> {
symbolrule.next().unwrap().as_str().parse::<i64>().unwrap() % 360;
SymbolRule::Arc(pos, radius, start_angle, end_angle)
}
Rule::arc_ellipse => {
let pos = parse_point(symbolrule.next().unwrap());
let radius_x = symbolrule.next().unwrap().as_str().parse().unwrap();
let radius_y = symbolrule.next().unwrap().as_str().parse().unwrap();
let start_angle =
symbolrule.next().unwrap().as_str().parse::<i64>().unwrap() % 360;
let end_angle =
symbolrule.next().unwrap().as_str().parse::<i64>().unwrap() % 360;
SymbolRule::EllipticArc(pos, radius_x, radius_y, start_angle, end_angle)
}
Rule::fillarc => {
let pos = parse_point(symbolrule.next().unwrap());
let radius = symbolrule.next().unwrap().as_str().parse().unwrap();
Expand All @@ -56,6 +66,27 @@ fn parse_symbol_rules(pairs: Pairs<Rule>) -> Vec<SymbolRule> {
symbolrule.next().unwrap().as_str().parse::<i64>().unwrap() % 360;
SymbolRule::FilledArc(pos, radius, start_angle, end_angle)
}
Rule::fillarc_ellipse => {
let pos = parse_point(symbolrule.next().unwrap());
let radius_x = symbolrule.next().unwrap().as_str().parse().unwrap();
let radius_y = symbolrule.next().unwrap().as_str().parse().unwrap();
let start_angle =
symbolrule.next().unwrap().as_str().parse::<i64>().unwrap() % 360;
let end_angle =
symbolrule.next().unwrap().as_str().parse::<i64>().unwrap() % 360;
SymbolRule::FilledEllipticArc(pos, radius_x, radius_y, start_angle, end_angle)
}
Rule::ellipse_circle => {
let pos = parse_point(symbolrule.next().unwrap());
let radius = symbolrule.next().unwrap().as_str().parse().unwrap();
SymbolRule::FilledArc(pos, radius, 0, 0)
}
Rule::ellipse => {
let pos = parse_point(symbolrule.next().unwrap());
let radius_x = symbolrule.next().unwrap().as_str().parse().unwrap();
let radius_y = symbolrule.next().unwrap().as_str().parse().unwrap();
SymbolRule::FilledEllipticArc(pos, radius_x, radius_y, 0, 0)
}
Rule::polygon => SymbolRule::Polygon(symbolrule.map(parse_point).collect()),
_ => {
unreachable!()
Expand Down Expand Up @@ -126,6 +157,10 @@ ARC:0:0:5:0:360
SYMBOL:HISTORY
FILLARC:0:0:1:0:360
SYMBOL:APPFix
ARC:0:0:2:6:0:360
ARC:0:0:6:2:0:360
SYMBOL:NODAPS_DIV
POLYGON:-4:0:0:-4:4:0:0:4
ARC:0:0:8:0:0"#;
Expand Down Expand Up @@ -170,6 +205,17 @@ ARC:0:0:8:0:0"#;
}
);

assert_eq!(
symbols.get("APPFix").unwrap(),
&SymbolDef {
name: "APPFix".to_string(),
rules: vec![
SymbolRule::EllipticArc((0.0, 0.0), 2.0, 6.0, 0, 0),
SymbolRule::EllipticArc((0.0, 0.0), 6.0, 2.0, 0, 0),
]
}
);

assert_eq!(
symbols.get("NODAPS_DIV").unwrap(),
&SymbolDef {
Expand Down
44 changes: 35 additions & 9 deletions src/topsky/topsky.pest
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ colordef = {
override_sct = { "OVERRIDE_SCT_MAP:" ~ override_folder ~ name ~ NL? }
override_folder = { ((!("\\" | NL) ~ ANY)+ ~ "\\")? }

// TODO DEFAULT_SCREEN-SPECIFIC, DEFAULT_GLOBAL

map = { "MAP:" ~ name ~ NL ~ map_setting+ }

// MAP
map_setting = _{
(" " | "\t")* ~ (
folder | color | asrdata | active | layer | mapsymbol
| fontsize | zoom | style | mapline | text | screen_specific | circle
| coordline | coordpoly | coord
folder | color | asrdata | active | layer | mapsymbol | fontstyle
| fontsize | zoom | style | mapline | text | global | screen_specific
| circle | coordline | coordpoly | coord
)
~ NL?
}
Expand All @@ -34,6 +36,7 @@ color = { "COLOR:" ~ name }
asrdata = { "ASRDATA:" ~ (wildcard | (name ~ ("," ~ name)*)) }

active = { "ACTIVE:" ~ (active_sched | active_id | active_rwy_with_excludes | active_rwy | active_always ) }
andactive = { "AND_ACTIVE:" ~ (active_sched | active_id | active_rwy_with_excludes | active_rwy | active_always ) }
active_always = { "1" }
active_id = {
"ID:" ~ (wildcard | names) ~ ":" ~ (wildcard | names) ~ ":"
Expand All @@ -54,7 +57,11 @@ layer = { "LAYER:" ~ number }
mapsymbol = { "SYMBOL" ~ ("/" ~ textalign)? ~ ":" ~ name ~ ":" ~ (coordinate | name) ~ (":" ~ mapsymbollabel)? }
mapsymbollabel = { name ~ ":" ~ point }

fontsize = { "FONTSIZE:" ~ (font_symbol ~ ":" ~ number | "0")}
fontstyle = { "FONTSTYLE:" ~ (fontstyle_set | fontstyle_default) }
fontstyle_default = { "0" }
fontstyle_set = { number ~ ":" ~ boolean ~ ":" ~ boolean ~ ":" ~ boolean }
fontsize = { "FONTSIZE:" ~ ((font_symbol ~ ":" ~ decimal) | fontsize_default)}
fontsize_default = { "0" }
font_symbol = { "=" | "+" | "-" | "*" }

zoom = { "ZOOM:" ~ decimal }
Expand All @@ -72,6 +79,7 @@ horizontalalign = { "L" | "C" | "R" }
verticalalign = { "T" | "C" | "B" }

screen_specific = { "SCREEN-SPECIFIC" }
global = { "GLOBAL" }

circle = { "CIRCLE:" ~ coordinate ~ ":" ~ decimal ~ ":" ~ decimal }

Expand All @@ -81,20 +89,35 @@ coordline = { "COORDLINE" }
coordpoly = { "COORDPOLY:" | number }

// SYMBOLDEF
symbolrule = _{ (moveto | line | fillarc | arc | polygon | pixel) ~ NL? }
symbolrule = _{ (
moveto | line | fillarc_ellipse | fillarc | arc_ellipse | arc | polygon | pixel | ellipse | ellipse_circle
) ~ NL? }
moveto = { "MOVETO:" ~ point }
line = { "LINETO:" ~ point }
fillarc = {
"FILLARC:" ~ point ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number
}
fillarc_ellipse = {
"FILLARC:" ~ point ~ ":" ~ decimal ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number
}
arc = {
"ARC:" ~ point ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number
}
arc_ellipse = {
"ARC:" ~ point ~ ":" ~ decimal ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number
}
ellipse = {
"ELLIPSE:" ~ point ~ ":" ~ decimal ~ ":" ~ decimal
}
ellipse_circle = {
"ELLIPSE:" ~ point ~ ":" ~ decimal
}
polygon = { "POLYGON" ~ (":" ~ point)+ }
pixel = { "SETPIXEL:" ~ point }

// TODO: SCTDATA

name = @{ (ASCII_ALPHA | ASCII_DIGIT | "_" | "-" | " " | "/" | "," | "." | "(" | ")" | "&")+ }
name = @{ (!(NL | ":") ~ ANY)+ }
names = { name ~ ("," ~ name)* }
wildcard = { "*" }

Expand All @@ -114,8 +137,11 @@ runway = { icao ~ rwy_designator }
icao = { ASCII_ALPHA_UPPER{4} }
rwy_designator = { ASCII_DIGIT{2} ~ ("L" | "C" | "R")? }
point = { decimal ~ ":" ~ decimal }
number = @{ "-"? ~ ("0" | (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*)) }
decimal = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
number = @{ ("-"|"+")? ~ ASCII_DIGIT+ }
decimal = @{ ("-"|"+")? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
boolean = { "0" | "1" }

NL = _{ ((" " | "\t")* ~ NEWLINE)+ }
COMMENT = _{ "//" ~ (!NL ~ ANY)* ~ NL }
// per documentation only "//" but ";" is used quite often and apparently ignored
// in the ES topsky plugin
COMMENT = _{ (" " | "\t")* ~ ("//" | ";") ~ (!NL ~ ANY)* ~ NL }

0 comments on commit bba17f4

Please sign in to comment.