use std::collections::HashMap;
pub mod generators;
pub mod parser;
pub mod rules;
pub mod types;
use crate::generators::get_generator;
use crate::parser::{
ApplyStatement, EdgeDeclaration, Expression, ForStatement, GenerateStatement, LetStatement,
NodeDeclaration, RuleDefinition, Statement,
};
use crate::parser::parse_ggl;
use crate::types::{Edge, Graph, Node};
use serde_json::Value;
pub struct GGLEngine {
pub graph: Graph,
rules: HashMap<String, rules::Rule>,
context: HashMap<String, Value>,
}
impl Default for GGLEngine {
fn default() -> Self {
Self::new()
}
}
impl GGLEngine {
pub fn new() -> Self {
GGLEngine {
graph: Graph::new(),
rules: HashMap::new(),
context: HashMap::new(),
}
}
pub fn generate_from_ggl(&mut self, ggl_code: &str) -> Result<String, String> {
let ast = parse_ggl(ggl_code).map_err(|e| format!("Parse error: {e}"))?;
self.graph = Graph::new();
self.rules.clear();
self.context.clear();
self.execute_statements(&ast.statements)?;
serde_json::to_string_pretty(&self.graph).map_err(|e| format!("Serialization error: {e}"))
}
fn execute_statements(&mut self, statements: &[Statement]) -> Result<(), String> {
for stmt in statements {
self.execute_statement(stmt)?;
}
Ok(())
}
fn execute_statement(&mut self, statement: &Statement) -> Result<(), String> {
match statement {
Statement::Let(stmt) => self.handle_let(stmt),
Statement::For(stmt) => self.handle_for(stmt),
Statement::Node(stmt) => self.handle_node(stmt),
Statement::Edge(stmt) => self.handle_edge(stmt),
Statement::Generate(stmt) => self.handle_generate(stmt),
Statement::RuleDef(stmt) => self.handle_rule_def(stmt),
Statement::Apply(stmt) => self.handle_apply(stmt),
}
}
fn handle_let(&mut self, stmt: &LetStatement) -> Result<(), String> {
let value = self.evaluate_expression(&stmt.value)?;
self.context.insert(stmt.name.clone(), value);
Ok(())
}
fn handle_for(&mut self, stmt: &ForStatement) -> Result<(), String> {
let start = self.evaluate_expression(&stmt.start)?.as_i64().ok_or("For loop start must be an integer")? as isize;
let end = self.evaluate_expression(&stmt.end)?.as_i64().ok_or("For loop end must be an integer")? as isize;
for i in start..end {
self.context
.insert(stmt.variable.clone(), Value::Number(serde_json::Number::from(i as i64)));
self.execute_statements(&stmt.body)?;
}
self.context.remove(&stmt.variable);
Ok(())
}
fn handle_node(&mut self, stmt: &NodeDeclaration) -> Result<(), String> {
let id = self.evaluate_expression(&stmt.id)?.to_string().replace('"', "");
let node_type = match &stmt.node_type {
Some(expr) => self.evaluate_expression(expr)?.to_string().replace('"', ""),
None => String::new(),
};
let mut metadata = HashMap::new();
for (key, expr) in &stmt.attributes {
metadata.insert(key.clone(), self.evaluate_expression(expr)?);
}
self.graph
.add_node(id, Node::new().with_type(node_type).with_metadata_map(metadata));
Ok(())
}
fn handle_edge(&mut self, stmt: &EdgeDeclaration) -> Result<(), String> {
let id = match &stmt.id {
Some(expr) => self.evaluate_expression(expr)?.to_string().replace('"', ""),
None => self.graph.generate_unique_edge_id("edge"),
};
let source = self.evaluate_expression(&stmt.source)?.to_string().replace('"', "");
let target = self.evaluate_expression(&stmt.target)?.to_string().replace('"', "");
let mut metadata = HashMap::new();
for (key, expr) in &stmt.attributes {
metadata.insert(key.clone(), self.evaluate_expression(expr)?);
}
self.graph.add_edge(
id,
Edge::new(source, target, stmt.directed).with_metadata_map(metadata),
);
Ok(())
}
fn handle_generate(&mut self, stmt: &GenerateStatement) -> Result<(), String> {
let generator_name = &stmt.name;
if let Some(generator) = get_generator(generator_name) {
let mut params = HashMap::new();
for (key, expr) in &stmt.params {
params.insert(key.clone(), self.evaluate_expression(expr)?);
}
let generated_graph =
generator(¶ms).map_err(|e| format!("Generator '{generator_name}' error: {e}"))?;
for (id, node) in generated_graph.nodes {
self.graph.add_node(id, node);
}
for (id, edge) in generated_graph.edges {
self.graph.add_edge(id, edge);
}
} else {
return Err(format!("Unknown generator: {generator_name}"));
}
Ok(())
}
fn handle_rule_def(&mut self, stmt: &RuleDefinition) -> Result<(), String> {
let rule = rules::Rule {
name: stmt.name.clone(),
lhs: stmt.lhs.clone(),
rhs: stmt.rhs.clone(),
};
self.rules.insert(stmt.name.clone(), rule);
Ok(())
}
fn handle_apply(&mut self, stmt: &ApplyStatement) -> Result<(), String> {
let iterations = self.evaluate_expression(&stmt.iterations)?.as_i64().ok_or("Apply iterations must be an integer")? as usize;
if let Some(rule) = self.rules.get(&stmt.rule_name).cloned() {
rule.apply(&mut self.graph, iterations)
.map_err(|e| format!("Rule '{}' application error: {e}", stmt.rule_name))?;
} else {
return Err(format!("Unknown rule: {}", stmt.rule_name));
}
Ok(())
}
pub fn get_graph(&self) -> &Graph {
&self.graph
}
fn evaluate_expression(&self, expr: &Expression) -> Result<Value, String> {
match expr {
Expression::StringLiteral(s) => Ok(Value::String(s.clone())),
Expression::Integer(i) => Ok(Value::Number(serde_json::Number::from(*i))),
Expression::Float(f) => Ok(Value::Number(serde_json::Number::from_f64(*f).unwrap())),
Expression::Boolean(b) => Ok(Value::Bool(*b)),
Expression::Identifier(name) => {
Ok(self.context
.get(name)
.cloned()
.unwrap_or_else(|| Value::String(name.clone())))
}
Expression::FormattedString(parts) => {
let mut result = String::new();
for part in parts {
match part {
parser::StringPart::Literal(s) => result.push_str(s),
parser::StringPart::Variable(var) => {
let value = self.context.get(var).ok_or(format!("Undefined variable: '{var}'"))?;
result.push_str(&value.to_string().replace('"', ""));
}
}
}
Ok(Value::String(result))
}
}
}
}