latest pushes

This commit is contained in:
2024-09-12 02:38:49 -04:00
parent 1ecf0b936d
commit 2fde3ecc4a
4 changed files with 272 additions and 21 deletions

View File

@@ -1,45 +1,73 @@
// Copyright (C) 2024 Bellande Algorithm Model Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const fs = require('fs');
class BellandeFormat {
parseBellande(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
const lines = content.split('\n');
return this.parseLines(lines);
const parsedData = this.parseLines(lines);
return this.toStringRepresentation(parsedData);
}
parseLines(lines) {
const result = {};
const stack = [[-1, result]];
let currentKey = null;
let currentList = null;
const indentStack = [[-1, result]];
for (const line of lines) {
const stripped = line.trim();
if (!stripped || stripped.startsWith('#')) continue;
const indent = line.length - line.trimLeft().length;
while (stack.length && indent <= stack[stack.length - 1][0]) {
stack.pop();
}
const parent = stack[stack.length - 1][1];
while (indentStack.length && indent <= indentStack[indentStack.length - 1][0]) {
const popped = indentStack.pop();
if (Array.isArray(popped[1])) {
currentList = null;
}
}
if (stripped.includes(':')) {
const [key, value] = stripped.split(':').map(s => s.trim());
currentKey = key;
if (value) {
parent[key] = this.parseValue(value);
result[key] = this.parseValue(value);
} else {
const newDict = {};
parent[key] = newDict;
stack.push([indent, newDict]);
result[key] = [];
currentList = result[key];
indentStack.push([indent, currentList]);
}
} else if (stripped.startsWith('-')) {
const value = stripped.slice(1).trim();
if (Array.isArray(parent)) {
parent.push(this.parseValue(value));
const parsedValue = this.parseValue(value);
if (currentList !== null) {
currentList.push(parsedValue);
} else {
const newList = [this.parseValue(value)];
const lastKey = Object.keys(parent).pop();
parent[lastKey] = newList;
stack.push([indent, newList]);
if (Object.keys(result).length === 0) {
result = [parsedValue];
currentList = result;
indentStack = [[-1, result]];
} else {
result[currentKey] = [parsedValue];
currentList = result[currentKey];
indentStack.push([indent, currentList]);
}
}
}
}
@@ -57,9 +85,30 @@ class BellandeFormat {
return value;
}
toStringRepresentation(data) {
if (typeof data === 'object' && data !== null) {
if (Array.isArray(data)) {
const items = data.map(item => this.toStringRepresentation(item));
return '[' + items.join(', ') + ']';
} else {
const items = Object.entries(data).map(([k, v]) => `"${k}": ${this.toStringRepresentation(v)}`);
return '{' + items.join(', ') + '}';
}
} else if (typeof data === 'string') {
return `"${data}"`;
} else if (typeof data === 'number') {
return data.toString();
} else if (data === null) {
return 'null';
} else if (typeof data === 'boolean') {
return data.toString().toLowerCase();
} else {
return String(data);
}
}
writeBellande(data, filePath) {
const content = this.toBellandeString(data);
fs.writeFileSync(filePath, content);
fs.writeFileSync(filePath, this.toBellandeString(data));
}
toBellandeString(data, indent = 0) {
@@ -84,14 +133,19 @@ class BellandeFormat {
formatValue(value) {
if (typeof value === 'string') {
return value.includes(' ') || value.includes(':') ? `"${value}"` : value;
if (value.includes(' ') || value.includes(':') || ['true', 'false', 'null'].includes(value.toLowerCase())) {
return `"${value}"`;
}
return value;
}
if (typeof value === 'boolean') {
return value.toString();
return value.toString().toLowerCase();
}
if (value === null) {
return 'null';
}
return value.toString();
return String(value);
}
}
module.exports = BellandeFormat;

View File

@@ -2,3 +2,4 @@ publish.sh
tests
setup.py
dist
src/bellande_format.egg-info

0
Package/Rust/README.md Normal file
View File

View File

@@ -0,0 +1,196 @@
// Copyright (C) 2024 Bellande Algorithm Model Research Innovation Center, Ronaldson Bellande
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[derive(Debug, Clone)]
enum BellandeValue {
String(String),
Integer(i64),
Float(f64),
Boolean(bool),
Null,
List(Vec<BellandeValue>),
Map(HashMap<String, BellandeValue>),
}
struct BellandeFormat;
impl BellandeFormat {
pub fn parse_bellande<P: AsRef<Path>>(
&self,
file_path: P,
) -> Result<BellandeValue, std::io::Error> {
let content = fs::read_to_string(file_path)?;
let lines: Vec<&str> = content.lines().collect();
let parsed_data = self.parse_lines(&lines);
Ok(parsed_data)
}
fn parse_lines(&self, lines: &[&str]) -> BellandeValue {
let mut result = HashMap::new();
let mut current_key = String::new();
let mut current_list: Option<Vec<BellandeValue>> = None;
let mut indent_stack = vec![(0, &mut result)];
for line in lines {
let stripped = line.trim();
if stripped.is_empty() || stripped.starts_with('#') {
continue;
}
let indent = line.len() - line.trim_start().len();
while indent_stack.last().map_or(false, |&(i, _)| indent <= i) {
indent_stack.pop();
current_list = None;
}
if let Some(colon_pos) = stripped.find(':') {
let (key, value) = stripped.split_at(colon_pos);
let key = key.trim().to_string();
let value = value[1..].trim();
current_key = key.clone();
if !value.is_empty() {
let parsed_value = self.parse_value(value);
indent_stack.last_mut().unwrap().1.insert(key, parsed_value);
} else {
let new_list = Vec::new();
indent_stack
.last_mut()
.unwrap()
.1
.insert(key, BellandeValue::List(new_list));
if let BellandeValue::List(list) = indent_stack
.last_mut()
.unwrap()
.1
.get_mut(&current_key)
.unwrap()
{
current_list = Some(list);
indent_stack.push((indent, list));
}
}
} else if stripped.starts_with('-') {
let value = stripped[1..].trim();
let parsed_value = self.parse_value(value);
if let Some(list) = &mut current_list {
list.push(parsed_value);
} else {
let mut new_list = Vec::new();
new_list.push(parsed_value);
indent_stack
.last_mut()
.unwrap()
.1
.insert(current_key.clone(), BellandeValue::List(new_list));
if let BellandeValue::List(list) = indent_stack
.last_mut()
.unwrap()
.1
.get_mut(&current_key)
.unwrap()
{
current_list = Some(list);
indent_stack.push((indent, list));
}
}
}
}
BellandeValue::Map(result)
}
fn parse_value(&self, value: &str) -> BellandeValue {
if value.eq_ignore_ascii_case("true") {
BellandeValue::Boolean(true)
} else if value.eq_ignore_ascii_case("false") {
BellandeValue::Boolean(false)
} else if value.eq_ignore_ascii_case("null") {
BellandeValue::Null
} else if value.starts_with('"') && value.ends_with('"') {
BellandeValue::String(value[1..value.len() - 1].to_string())
} else if let Ok(int_value) = value.parse::<i64>() {
BellandeValue::Integer(int_value)
} else if let Ok(float_value) = value.parse::<f64>() {
BellandeValue::Float(float_value)
} else {
BellandeValue::String(value.to_string())
}
}
pub fn write_bellande<P: AsRef<Path>>(
&self,
data: &BellandeValue,
file_path: P,
) -> Result<(), std::io::Error> {
let content = self.to_bellande_string(data, 0);
fs::write(file_path, content)
}
fn to_bellande_string(&self, data: &BellandeValue, indent: usize) -> String {
match data {
BellandeValue::Map(map) => map
.iter()
.map(|(key, value)| {
let value_str = match value {
BellandeValue::Map(_) | BellandeValue::List(_) => {
format!("\n{}", self.to_bellande_string(value, indent + 2))
}
_ => format!(" {}", self.format_value(value)),
};
format!("{}{}: {}", " ".repeat(indent), key, value_str)
})
.collect::<Vec<_>>()
.join("\n"),
BellandeValue::List(list) => list
.iter()
.map(|item| {
format!(
"{}- {}",
" ".repeat(indent),
self.to_bellande_string(item, indent + 2)
)
})
.collect::<Vec<_>>()
.join("\n"),
_ => self.format_value(data),
}
}
fn format_value(&self, value: &BellandeValue) -> String {
match value {
BellandeValue::String(s) => {
if s.contains(' ')
|| s.contains(':')
|| ["true", "false", "null"].contains(&s.to_lowercase().as_str())
{
format!("\"{}\"", s)
} else {
s.clone()
}
}
BellandeValue::Integer(i) => i.to_string(),
BellandeValue::Float(f) => f.to_string(),
BellandeValue::Boolean(b) => b.to_string().to_lowercase(),
BellandeValue::Null => "null".to_string(),
BellandeValue::List(_) | BellandeValue::Map(_) => unreachable!(),
}
}
}