diff --git a/Package/JavaScript/src/bellande_parser.js b/Package/JavaScript/src/bellande_parser.js
index c86feb1..1adb24a 100644
--- a/Package/JavaScript/src/bellande_parser.js
+++ b/Package/JavaScript/src/bellande_parser.js
@@ -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 .
+
+
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;
diff --git a/Package/Python/.gitignore b/Package/Python/.gitignore
index 3e54b1f..b111f4b 100644
--- a/Package/Python/.gitignore
+++ b/Package/Python/.gitignore
@@ -2,3 +2,4 @@ publish.sh
tests
setup.py
dist
+src/bellande_format.egg-info
diff --git a/Package/Python/dist/bellande_format-0.1.1.tar.gz b/Package/Python/dist/bellande_format-0.1.1.tar.gz
new file mode 100644
index 0000000..257b0c8
Binary files /dev/null and b/Package/Python/dist/bellande_format-0.1.1.tar.gz differ
diff --git a/Package/Python/publish.sh b/Package/Python/publish.sh
new file mode 100755
index 0000000..48934a9
--- /dev/null
+++ b/Package/Python/publish.sh
@@ -0,0 +1,2 @@
+python setup.py sdist
+twine upload dist/*
diff --git a/Package/Python/setup.py b/Package/Python/setup.py
new file mode 100644
index 0000000..c15691b
--- /dev/null
+++ b/Package/Python/setup.py
@@ -0,0 +1,40 @@
+from setuptools import setup, find_packages
+
+with open("README.md", "r", encoding="utf-8") as fh:
+ long_description = fh.read()
+
+setup(
+ name="bellande_format",
+ version="0.1.1",
+ description="Bellande Format is a file format type",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ author="RonaldsonBellande",
+ author_email="ronaldsonbellande@gmail.com",
+ packages=find_packages(where="src"),
+ package_dir={"": "src"},
+ include_package_data=True,
+ install_requires=[
+ "numpy",
+ ],
+ classifiers=[
+ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+ "Programming Language :: Python",
+ ],
+ keywords=["package", "setuptools"],
+ python_requires=">=3.0",
+ extras_require={
+ "dev": ["pytest", "pytest-cov[all]", "mypy", "black"],
+ },
+ entry_points={
+ 'console_scripts': [
+ 'Bellande_Format = bellande_parser:Bellande_Format',
+ ],
+ },
+ project_urls={
+ "Home": "https://github.com/RonaldsonBellande/bellande_format",
+ "Homepage": "https://github.com/RonaldsonBellande/bellande_format",
+ "documentation": "https://github.com/RonaldsonBellande/bellande_format",
+ "repository": "https://github.com/RonaldsonBellande/bellande_format",
+ },
+)
diff --git a/Package/Rust/README.md b/Package/Rust/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/Package/Rust/publish.sh b/Package/Rust/publish.sh
new file mode 100755
index 0000000..f23334d
--- /dev/null
+++ b/Package/Rust/publish.sh
@@ -0,0 +1,2 @@
+cargo package
+cargo publish
diff --git a/Package/Rust/src/Cargo.toml b/Package/Rust/src/Cargo.toml
new file mode 100644
index 0000000..30b64e9
--- /dev/null
+++ b/Package/Rust/src/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "bellande_parser"
+version = "0.0.1"
+edition = "2021"
+authors = ["Ronaldson Bellande ronaldsonbellande@gmail.com"]
+description = "Bellande File Format"
+license = "GNU"
+
+[lib]
+path = "bellande_parser.rs"
+
+[dependencies]
+std = { version = "1.65", features = ["collections", "fs", "path"] }
diff --git a/Package/Rust/src/bellande_parser.rs b/Package/Rust/src/bellande_parser.rs
new file mode 100644
index 0000000..c3fa077
--- /dev/null
+++ b/Package/Rust/src/bellande_parser.rs
@@ -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 .
+
+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),
+ Map(HashMap),
+}
+
+struct BellandeFormat;
+
+impl BellandeFormat {
+ pub fn parse_bellande>(
+ &self,
+ file_path: P,
+ ) -> Result {
+ 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> = 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(¤t_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(¤t_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::() {
+ BellandeValue::Integer(int_value)
+ } else if let Ok(float_value) = value.parse::() {
+ BellandeValue::Float(float_value)
+ } else {
+ BellandeValue::String(value.to_string())
+ }
+ }
+
+ pub fn write_bellande>(
+ &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::>()
+ .join("\n"),
+ BellandeValue::List(list) => list
+ .iter()
+ .map(|item| {
+ format!(
+ "{}- {}",
+ " ".repeat(indent),
+ self.to_bellande_string(item, indent + 2)
+ )
+ })
+ .collect::>()
+ .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!(),
+ }
+ }
+}
diff --git a/git_scripts/fix_errors.sh b/git_scripts/fix_errors.sh
new file mode 100755
index 0000000..2ebdbee
--- /dev/null
+++ b/git_scripts/fix_errors.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Get the URL from .git/config
+git_url=$(git config --get remote.origin.url)
+
+# Check if a URL is found
+if [ -z "$git_url" ]; then
+ echo "No remote URL found in .git/config."
+ exit 1
+fi
+
+# Clone the repository into a temporary folder
+git clone "$git_url" tmp_clone
+
+# Check if the clone was successful
+if [ $? -eq 0 ]; then
+ # Remove the existing .git directory if it exists
+ if [ -d ".git" ]; then
+ rm -rf .git
+ fi
+
+ # Copy the .git directory from the clone to the current repository
+ cp -r tmp_clone/.git .
+
+ # Remove the clone directory
+ rm -rf tmp_clone
+
+ echo "Repository cloned and .git directory copied successfully."
+else
+ echo "Failed to clone the repository."
+fi
diff --git a/git_scripts/push.sh b/git_scripts/push.sh
new file mode 100755
index 0000000..0b793ae
--- /dev/null
+++ b/git_scripts/push.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Git push what is already in the repository
+git pull --no-edit; git fetch;
+
+# Exclude specific files and directories
+EXCLUDES=(".git" ".gitignore" "executable")
+
+# Find all non-hidden files and directories, excluding any hidden files and directories
+find . -type f ! -path '*/.*' -print0 | while IFS= read -r -d '' file; do
+ # Check if the file is in the exclude list
+ should_exclude=false
+ for exclude in "${EXCLUDES[@]}"; do
+ if [[ "$(basename "$file")" == "$exclude" ]]; then
+ should_exclude=true
+ break
+ fi
+ done
+
+ # Add file to staging area if it's not excluded
+ if [ "$should_exclude" = false ]; then
+ git add -f "$file"
+ fi
+done
+git commit -am "latest pushes"; git push
diff --git a/git_scripts/repository_recal.sh b/git_scripts/repository_recal.sh
new file mode 100755
index 0000000..4c7fd4f
--- /dev/null
+++ b/git_scripts/repository_recal.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+# Git push what is already in the repository
+git pull --no-edit; git fetch; git add .; git commit -am "latest pushes"; git push
+
+# Get the current directory
+current_dir=$(pwd)
+
+# Read the remote repository URL from .git/config
+remote_repo_url=$(git -C "$current_dir" config --get remote.origin.url)
+
+# Create a temporary directory for cloning the repository
+temp_dir=$(mktemp -d)
+
+# Clone the repository into the temporary directory without using local references
+git clone --no-local "$current_dir" "$temp_dir"
+
+# Switch to the temporary directory
+cd "$temp_dir"
+
+# Create a temporary file to store the file list
+tmp_file=$(mktemp)
+# Create a temporary file to store the processed commits
+processed_commits_file=$(mktemp)
+
+# Function to check if a commit has already been processed
+is_commit_processed() {
+ local commit="$1"
+
+ # Check if the commit is already processed
+ grep -Fxq "$commit" "$processed_commits_file"
+}
+
+# Function to mark a commit as processed
+mark_commit_processed() {
+ local commit="$1"
+
+ # Mark the commit as processed
+ echo "$commit" >> "$processed_commits_file"
+}
+
+# Function to check if a file or folder exists in the repository
+file_exists_in_repo() {
+ local file_path="$1"
+
+ # Check if the file or folder exists in the repository
+ git ls-tree --name-only -r HEAD | grep -Fxq "$file_path"
+}
+
+# Function to process the files and folders in each commit
+process_commit_files() {
+ local commit="$1"
+
+ # Check if the commit has already been processed
+ if is_commit_processed "$commit"; then
+ echo "Commit $commit already processed. Skipping..."
+ return
+ fi
+
+ # Get the list of files and folders in the commit (including subfolders)
+ git ls-tree --name-only -r "$commit" >> "$tmp_file"
+
+ # Process each file or folder in the commit
+ while IFS= read -r line
+ do
+ # Check if the file or folder exists in the current push
+ if file_exists_in_repo "$line"; then
+ echo "Keeping: $line"
+ else
+ echo "Deleting: $line"
+ git filter-repo --path "$line" --invert-paths
+ fi
+ done < "$tmp_file"
+
+ # Mark the commit as processed
+ mark_commit_processed "$commit"
+
+ # Clear the temporary file
+ > "$tmp_file"
+}
+
+# Iterate over each commit in the repository
+git rev-list --all | while IFS= read -r commit
+do
+ process_commit_files "$commit"
+done
+
+# Push the filtered changes to the original repository
+git remote add origin "$remote_repo_url"
+git push --force origin main
+
+# Perform a history rewrite to remove the filtered files
+git filter-repo --force
+
+# Fetch the changes from the remote repository
+git -C "$current_dir" fetch origin
+
+# Merge the remote changes into the local repository
+git -C "$current_dir" merge origin/main --no-edit
+
+# Update the local repository and reduce the size of .git if needed
+git -C "$current_dir" gc --prune=now
+git -C "$current_dir" reflog expire --expire=now --all
+git -C "$current_dir" repack -ad
+
+# Clean up temporary files and directories
+cd "$current_dir"
+rm -rf "$temp_dir"
+rm "$tmp_file"
+rm "$processed_commits_file"