armake2 0.3.0

Arma 3 modding tools
Documentation
use std::str;
use armake::config::{Config, ConfigClass, ConfigEntry, ConfigArray, ConfigArrayElement};

#![arguments(warnings: &mut Vec<(usize, String, Option<&'static str>)>)]

whitespace = #quiet<[ \r\n\t]+>

float -> f32 = f:$([-+]? [0-9]* "." [0-9]+) {
    if f.chars().filter(|c| c == &'.').count() == 0 {
        println!("{}", f);
    }
    f.parse().unwrap()
}

integer -> i32 = i:$([-+]? (("0x" [0-9a-fA-F]+) / [0-9]+)) {
    if i.contains("0x") {
        i32::from_str_radix(&i.replace("0x", ""), 16).unwrap()
    } else {
        i32::from_str_radix(i, 10).unwrap()
    }
}

doublequoted_string -> String = "\""s:$(("\"\"" / [^\"])*)"\"" {
    s.to_string().replace("\"\"", "\"")
}

singlequoted_string -> String = "'"s:$(("''" / [^'])*)"'" {
    s.to_string().replace("\'\'", "\'")
}

unquoted_string -> String = pos:#position s:$([^;}]*) {
    let result = s.to_string().trim().to_string();
    warnings.push((pos, format!("String value \"{}\" is not quoted properly.", result), Some("unquoted-string")));
    result
}

unquoted_string_array -> String = pos:#position s:$([^,} \t][^,}]*) {
    let result = s.to_string().trim().to_string();
    warnings.push((pos, format!("String array element \"{}\" is not quoted properly.", result), Some("unquoted-string")));
    result
}

string -> String = doublequoted_string / singlequoted_string

array_element -> ConfigArrayElement =
    f:float   &(whitespace? [,}]) { ConfigArrayElement::FloatElement(f) } /
    i:integer &(whitespace? [,}]) { ConfigArrayElement::IntElement(i) } /
    a:array   &(whitespace? [,}]) { ConfigArrayElement::ArrayElement(a) } /
    s:string  &(whitespace? [,}]) { ConfigArrayElement::StringElement(s) } /
    s:unquoted_string_array &(whitespace? [,}]) { ConfigArrayElement::StringElement(s) }

array_elements -> Vec<ConfigArrayElement> = array_element ** (whitespace? "," whitespace?)

array -> ConfigArray = "{" whitespace? elems:array_elements whitespace? ","? whitespace? "}" {
    ConfigArray {
        is_expansion: false,
        elements: elems
    }
}

var -> ConfigEntry =
    f:float   { ConfigEntry::FloatEntry(f) } /
    i:integer { ConfigEntry::IntEntry(i) } /
    s:string  { ConfigEntry::StringEntry(s) }

var_entry -> (String, ConfigEntry) = n:name whitespace? "=" whitespace? ce:var {
    (n, ce)
}

unquoted_string_entry -> (String, ConfigEntry) = n:name whitespace? "=" whitespace? s:unquoted_string {
    (n, ConfigEntry::StringEntry(s))
}

array_entry -> (String, ConfigEntry) = n:name whitespace? "[" whitespace? "]" whitespace? "=" whitespace? a:array {
    (n, ConfigEntry::ArrayEntry(a))
}

array_expansion_entry -> (String, ConfigEntry) = n:name whitespace? "[" whitespace? "]" whitespace? "+=" whitespace? a:array {
    (n, ConfigEntry::ArrayEntry(ConfigArray {
        is_expansion: true,
        ..a
    }))
}

entry -> (String, ConfigEntry) =
    e:(class / array_entry / array_expansion_entry / var_entry) whitespace? (";" / &"}") { e } /
    e:unquoted_string_entry whitespace? (";" / &"}") { e }

entries -> Vec<(String, ConfigEntry)> = entry ** (whitespace?)

name -> String = n:$([a-zA-Z0-9_]+) {
    n.to_string()
}

parent -> String = whitespace? ":" whitespace? n:name {
    n
}

regular_class -> (String, ConfigEntry) = "class" whitespace+ n:name p:parent? whitespace? "{" whitespace? e:entries whitespace? "}" {
    let parent = match p {
        Some(p) => p,
        None => String::from("")
    };
    (n, ConfigEntry::ClassEntry(ConfigClass {
        parent: parent,
        is_external: false,
        is_deletion: false,
        entries: Some(e)
    }))
}

external_class -> (String, ConfigEntry) = "class" whitespace+ n:name {
    (n, ConfigEntry::ClassEntry(ConfigClass {
        parent: String::from(""),
        is_external: true,
        is_deletion: false,
        entries: None
    }))
}

deleted_class -> (String, ConfigEntry) = "delete" whitespace+ n:name {
    (n, ConfigEntry::ClassEntry(ConfigClass {
        parent: String::from(""),
        is_external: false,
        is_deletion: true,
        entries: None
    }))
}

class -> (String, ConfigEntry) = regular_class / external_class / deleted_class

pub config -> Config = whitespace? e:entries whitespace? !. {
    Config {
        root_body: ConfigClass {
            parent: String::from(""),
            is_external: false,
            is_deletion: false,
            entries: Some(e)
        }
    }
}