use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use serde_json::{Map, Value};
use crate::env::Env;
use crate::ast::{AstError, Parser};
pub trait AstNode {
fn get_env(&self) -> Rc<RefCell<Env>>;
fn apply(&self, env: &Rc<RefCell<Env>>) -> Result<Value, AstError>;
fn to_json(&self) -> Value;
fn is_symbol_named(&self, name: &str) -> bool {
false
}
}
pub struct LiteralNode {
value: Value,
env: Rc<RefCell<Env>>,
}
impl LiteralNode {
pub fn new(value: Value, env: Rc<RefCell<Env>>) -> Self {
Self { value, env }
}
}
impl AstNode for LiteralNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.env)
}
fn apply(&self, _env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
Ok(self.value.clone())
}
fn to_json(&self) -> Value {
self.value.clone()
}
}
pub struct SymbolNode {
name: String,
env: Rc<RefCell<Env>>,
}
impl SymbolNode {
pub fn new(name: String, env: Rc<RefCell<Env>>) -> Self {
Self { name, env }
}
pub fn name(&self) -> &str {
&self.name
}
}
impl AstNode for SymbolNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.env)
}
fn apply(&self, env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
env.borrow()
.resolve(&self.name)
.ok_or_else(|| AstError::SymbolNotFound(self.name.clone()))
}
fn to_json(&self) -> Value {
Value::String(self.name.clone())
}
fn is_symbol_named(&self, name: &str) -> bool {
self.name == name
}
}
pub struct ArrayNode {
elements: Vec<Box<dyn AstNode>>,
env: Rc<RefCell<Env>>,
}
impl ArrayNode {
pub fn new(elements: Vec<Box<dyn AstNode>>, env: Rc<RefCell<Env>>) -> Self {
Self { elements, env }
}
fn is_empty(&self) -> bool {
self.elements.is_empty()
}
fn first(&self) -> Option<&dyn AstNode> {
self.elements.first().map(|b| b.as_ref())
}
fn rest(&self) -> &[Box<dyn AstNode>] {
if self.elements.is_empty() {
&[]
} else {
&self.elements[1..]
}
}
}
impl AstNode for ArrayNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.env)
}
fn apply(&self, env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
if self.is_empty() {
return Ok(Value::Array(vec![]));
}
const SPECIAL_FORMS: &[&str] = &["$def", "$defn", "$lambda", "$quote"];
if let Some(first) = self.first() {
for &symbol in SPECIAL_FORMS {
if first.is_symbol_named(symbol) {
return self.apply_function_call(env, symbol);
}
}
if let Value::String(name) = first.to_json() {
if name.starts_with('$') && name != "$*" && !name.starts_with("$$") {
return self.apply_function_call(env, &name);
}
}
}
let evaluated: Result<Vec<_>, _> = self.elements
.iter()
.map(|node| node.apply(env))
.collect();
Ok(Value::Array(evaluated?))
}
fn to_json(&self) -> Value {
let arr: Vec<_> = self.elements.iter().map(|n| n.to_json()).collect();
Value::Array(arr)
}
}
impl ArrayNode {
fn apply_function_call(&self, env: &Rc<RefCell<Env>>, symbol: &str) -> Result<Value, AstError> {
const SPECIAL_FORMS: &[&str] = &["$def", "$defn", "$lambda", "$quote"];
if SPECIAL_FORMS.contains(&symbol) {
let args: Vec<&dyn AstNode> = self.rest().iter().map(|b| b.as_ref()).collect();
return env.borrow().apply_functor_node(symbol, &args);
}
let evaluated_args: Result<Vec<_>, _> = self.rest()
.iter()
.map(|node| node.apply(env))
.collect();
env.borrow().apply_functor_values(symbol, &evaluated_args?)
}
}
pub struct ObjectNode {
dict: HashMap<String, Box<dyn AstNode>>,
env: Rc<RefCell<Env>>,
}
impl ObjectNode {
pub fn new(dict: HashMap<String, Box<dyn AstNode>>, env: Rc<RefCell<Env>>) -> Self {
Self { dict, env }
}
}
impl AstNode for ObjectNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.env)
}
fn apply(&self, env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
let mut result = Map::new();
for (key, node) in &self.dict {
let value = node.apply(env)?;
result.insert(key.clone(), value);
}
Ok(Value::Object(result))
}
fn to_json(&self) -> Value {
let mut map = Map::new();
for (key, node) in &self.dict {
map.insert(key.clone(), node.to_json());
}
Value::Object(map)
}
}
pub struct ObjectExpressionNode {
operator: String,
value: Box<dyn AstNode>,
metadata: HashMap<String, Value>,
env: Rc<RefCell<Env>>,
}
impl ObjectExpressionNode {
pub fn new(
operator: String,
value: Box<dyn AstNode>,
metadata: HashMap<String, Value>,
env: Rc<RefCell<Env>>
) -> Self {
Self { operator, value, metadata, env }
}
}
impl AstNode for ObjectExpressionNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.env)
}
fn apply(&self, env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
if self.operator == "$expr" {
return self.value.apply(env);
}
{
let mut env_mut = env.borrow_mut();
env_mut.set_meta(self.metadata.clone());
}
let result = if self.operator == "$pattern" || self.operator == "$query" || self.operator == "$sql" {
let json_value = self.value.to_json();
env.borrow().apply_functor_values(&self.operator, &[json_value])
} else {
let evaluated = self.value.apply(env)?;
env.borrow().apply_functor_values(&self.operator, &[evaluated])
};
{
let mut env_mut = env.borrow_mut();
env_mut.clear_meta();
}
result
}
fn to_json(&self) -> Value {
let mut map = Map::new();
map.insert(self.operator.clone(), self.value.to_json());
for (key, value) in &self.metadata {
map.insert(key.clone(), value.clone());
}
Value::Object(map)
}
}
pub struct QuoteNode {
value: Box<dyn AstNode>,
env: Rc<RefCell<Env>>,
}
impl QuoteNode {
pub fn new(value: Box<dyn AstNode>, env: Rc<RefCell<Env>>) -> Self {
Self { value, env }
}
}
impl AstNode for QuoteNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.env)
}
fn apply(&self, _env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
Ok(self.value.to_json())
}
fn to_json(&self) -> Value {
self.value.to_json()
}
}
pub struct LambdaNode {
params: Vec<String>,
body: Box<dyn AstNode>,
closure_env: Rc<RefCell<Env>>,
}
impl LambdaNode {
pub fn new(params: Vec<String>, body: Box<dyn AstNode>, closure_env: Rc<RefCell<Env>>) -> Self {
Self { params, body, closure_env }
}
}
impl AstNode for LambdaNode {
fn get_env(&self) -> Rc<RefCell<Env>> {
Rc::clone(&self.closure_env)
}
fn apply(&self, env: &Rc<RefCell<Env>>) -> Result<Value, AstError> {
let mut lambda_obj = serde_json::Map::new();
lambda_obj.insert("__lambda__".to_string(), Value::Bool(true));
lambda_obj.insert("params".to_string(), Value::Array(
self.params.iter().cloned().map(Value::String).collect()
));
lambda_obj.insert("body".to_string(), self.body.to_json());
Ok(Value::Object(lambda_obj))
}
fn to_json(&self) -> Value {
Value::String("<lambda>".to_string())
}
}