rusty_pkl/
lib.rs

1use std::collections::HashMap;
2use std::fs;
3
4// Define a data structure to represent Pkl values
5#[derive(Debug, Clone)]
6pub enum PklValue {
7    String(String),
8    Integer(i64),
9    Float(f64),
10    Boolean(bool),
11    Object(HashMap<String, PklValue>),
12    Array(Vec<PklValue>),
13}
14
15// Parse Pkl file into a PklValue
16// Parse Pkl file into a PklValue
17pub fn parse_pkl(filename: &str) -> Result<PklValue, String> {
18    let content = fs::read_to_string(filename)
19        .map_err(|err| format!("Error reading file: {}", err))?;
20    let mut lines = content.lines();
21
22    let root_object = parse_object(&mut lines)?;
23
24    Ok(root_object)
25}
26
27// Parse an object from Pkl file
28pub fn parse_object<'a, I>(lines: &mut I) -> Result<PklValue, String>
29where
30    I: Iterator<Item = &'a str>,
31{
32    let mut object = HashMap::new();
33
34    while let Some(line) = lines.next() {
35        let line = line.trim();
36
37        // Skip empty lines or comments
38        if line.is_empty() || line.starts_with("#") {
39            continue;
40        }
41
42        // Check for nested object
43        if line.ends_with('{') {
44            let key = line.trim_end_matches('{').trim();
45            let nested_object = parse_object(lines)?;
46            object.insert(key.to_string(), nested_object);
47        } else if line.ends_with('}') {
48            // End of object
49            break;
50        } else {
51            // Key-value pair
52            let parts: Vec<&str> = line.splitn(2, '=').collect();
53            if parts.len() != 2 {
54                return Err("Invalid syntax".to_string());
55            }
56
57            let key = parts[0].trim();
58            let value = parts[1].trim();
59            let parsed_value = parse_value(value)?;
60
61            object.insert(key.to_string(), parsed_value);
62        }
63    }
64
65    Ok(PklValue::Object(object))
66}
67
68
69
70// Parse a value string into its appropriate PklValue
71pub fn parse_value(value: &str) -> Result<PklValue, String> {
72    if value.starts_with('"') && value.ends_with('"') {
73        Ok(PklValue::String(value[1..value.len() - 1].to_string()))
74    } else if let Ok(integer) = value.parse::<i64>() {
75        Ok(PklValue::Integer(integer))
76    } else if let Ok(float) = value.parse::<f64>() {
77        Ok(PklValue::Float(float))
78    } else if value == "true" {
79        Ok(PklValue::Boolean(true))
80    } else if value == "false" {
81        Ok(PklValue::Boolean(false))
82    } else if value.starts_with('{') && value.ends_with('}') {
83        // Parse nested object
84        let inner_object_content = &value[1..value.len() - 1];
85        let inner_object = parse_pkl_inner_object(inner_object_content)?;
86        Ok(inner_object)
87    } else {
88        Err("Unsupported value type".to_string())
89    }
90}
91
92// Parse a nested object
93pub fn parse_pkl_inner_object(content: &str) -> Result<PklValue, String> {
94    let mut lines = content.lines();
95    let mut object = HashMap::new();
96
97    while let Some(line) = lines.next() {
98        let line = line.trim();
99
100        // Skip empty lines or comments
101        if line.is_empty() || line.starts_with("#") {
102            continue;
103        }
104
105        let parts: Vec<&str> = line.splitn(2, '=').collect();
106        if parts.len() != 2 {
107            return Err("Invalid syntax".to_string());
108        }
109
110        let key = parts[0].trim();
111        let value = parts[1].trim();
112        let parsed_value = parse_value(value)?;
113
114        object.insert(key.to_string(), parsed_value);
115    }
116
117    Ok(PklValue::Object(object))
118}
119
120// Function to recursively print specific parameters from PklValue
121pub fn print_parameter(pkl_value: &PklValue, parameter: &str) {
122    match pkl_value {
123        PklValue::Object(object) => {
124            // Check if the parameter exists in the current object
125            if let Some(value) = object.get(parameter) {
126                println!("{}: {:?}", parameter, value);
127            } else {
128                // If not found, recursively search through nested objects
129                for (_, nested_value) in object {
130                    print_parameter(nested_value, parameter);
131                }
132            }
133        }
134        _ => {
135            println!("Parameter '{}' not found.", parameter);
136        }
137    }
138}
139
140// Function to recursively find and return specific parameters from PklValue
141pub fn find_parameter(pkl_value: &PklValue, parameter: &str) -> Option<PklValue> {
142    match pkl_value {
143        PklValue::Object(object) => {
144            // Check if the parameter exists in the current object
145            if let Some(value) = object.get(parameter) {
146                Some(value.clone())
147            } else {
148                // If not found, recursively search through nested objects
149                for (_, nested_value) in object {
150                    if let Some(found_value) = find_parameter(nested_value, parameter) {
151                        return Some(found_value);
152                    }
153                }
154                None
155            }
156        }
157        _ => None,
158    }
159}