use std::error::Error;
use std::fmt::{ Display, Write };
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use std::collections::{HashMap, HashSet};
mod built_ins;
pub mod stack;
use stack::{Stack, StackError};
use built_ins::BuiltInError;
use crate::ast::{self, join, Assignable, Expression, InfixOp, Literal, PrefixOp, Statement};
#[derive(Debug)]
pub enum RuntimeError {
StackError(StackError),
BuiltInError(BuiltInError),
InvalidArrayIndex,
InvalidObjectIndex,
InvalidIndexTarget,
InvalidPropTarget,
InvalidPrefixTarget,
InvalidInfixTarget,
InvalidFunctionCallTarget,
}
impl From<StackError> for RuntimeError {
fn from(err: StackError) -> Self {
Self::StackError(err)
}
}
impl From<BuiltInError> for RuntimeError {
fn from(err: BuiltInError) -> Self {
Self::BuiltInError(err)
}
}
impl Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Runtime Error: ")?;
match self {
Self::StackError(err) => write!(f, "Stack Error: {}", err),
Self::BuiltInError(err) => write!(f, "BuiltInError: {}", err),
Self::InvalidArrayIndex => f.write_str("Invalid Array Index"),
Self::InvalidPropTarget => f.write_str("Invalid Object Property Target"),
Self::InvalidObjectIndex => f.write_str("Invalid Object Index"),
Self::InvalidIndexTarget => f.write_str("Invalid Index Target"),
Self::InvalidInfixTarget => f.write_str("Invalid Infix Target"),
Self::InvalidPrefixTarget => f.write_str("Invalid Prefix Target"),
Self::InvalidFunctionCallTarget => f.write_str("Invalid Function Call Target")
}
}
}
impl Error for RuntimeError {}
pub type RuntimeResult<T> = Result<T, RuntimeError>;
pub struct Runtime {
global_stack: Stack,
loaded_stack: Option<Stack>,
built_ins: HashMap<String, Rc<dyn built_ins::BuiltIn>>,
}
impl Runtime {
pub fn new() -> Self {
let built_ins = built_ins::load_built_ins();
let global_stack = Stack::new();
let loaded_stack = None;
Self { built_ins, loaded_stack, global_stack }
}
pub fn reset_stack(&mut self) {
self.global_stack = Stack::new();
}
pub fn run_program(&mut self, program: &Vec<ast::Statement>) -> RuntimeResult<GabrValue> {
self.eval_program(program)
}
fn eval_program_with_new_scope(&mut self, program: &Vec<ast::Statement>) -> RuntimeResult<GabrValue> {
let mut result = GabrValue::new(ObjectInner::NULL.as_object(), false);
self.current_context().push_scope();
for statement in program.iter() {
result = self.eval_statement(statement)?;
if result.returning {
self.current_context().pop_scope()?;
return Ok(result)
}
}
self.current_context().pop_scope()?;
Ok(result)
}
fn eval_program(&mut self, program: &Vec<ast::Statement>) -> RuntimeResult<GabrValue> {
let mut result = GabrValue::new(ObjectInner::NULL.as_object(), false);
for statement in program.iter() {
result = self.eval_statement(statement)?;
if result.returning {
return Ok(result)
}
}
Ok(result)
}
fn get_built_in(&self, name: String) -> Option<Rc<dyn built_ins::BuiltIn>> {
self.built_ins.get(&name).map(|bi| bi.clone())
}
fn load_params(&mut self, params: Vec<(String, Object)>) -> RuntimeResult<()> {
for (name, val) in params {
self.current_context().create_var(name, val)?;
}
Ok(())
}
fn get_assignable(&mut self, assignable: &Assignable) -> RuntimeResult<Object> {
match assignable {
Assignable::Var(var) => Ok(self.current_context().get_var(&var)?),
Assignable::PropIndex { obj, index } => {
let index = self.eval_expression(index)?;
let index: &ObjectInner = &index.inner();
match &mut self.get_assignable(obj)?.inner() as &mut ObjectInner {
ObjectInner::ARRAY(arr) => {
if let ObjectInner::NUMBER(num) = index {
if *num < 0 {
return Err(RuntimeError::InvalidArrayIndex);
}
let num = *num as usize;
if (num) < arr.len() {
Ok(arr[num].clone())
} else {
Err(RuntimeError::InvalidArrayIndex)
}
} else {
Err(RuntimeError::InvalidArrayIndex)
}
},
ObjectInner::OBJECT(obj) => {
if let ObjectInner::STRING(prop) = index {
Ok(obj.get(prop).map(|obj| obj.clone()).unwrap_or(ObjectInner::NULL.as_object()))
} else {
Err(RuntimeError::InvalidObjectIndex)
}
},
_ => Err(RuntimeError::InvalidIndexTarget)
}
},
Assignable::ObjectProp { obj, prop } => {
let obj = self.get_assignable(obj)?;
let obj: &ObjectInner = &obj.inner();
if let ObjectInner::OBJECT(obj) = obj {
Ok(obj.get(prop).map(|obj| obj.clone()).unwrap_or(ObjectInner::NULL.as_object()))
} else {
Err(RuntimeError::InvalidPropTarget)
}
}
}
}
fn set_assignable(&mut self, assignable: &Assignable, val: Object) -> RuntimeResult<()> {
match assignable {
Assignable::Var(var) => {
Ok(self.current_context().set_var(&var, val)?)
},
Assignable::PropIndex { obj, index } => {
let index = self.eval_expression(index)?;
let index: &ObjectInner = &index.inner();
match &mut self.get_assignable(obj)?.inner() as &mut ObjectInner {
ObjectInner::ARRAY(arr) => {
if let ObjectInner::NUMBER(num) = index {
if *num < 0 {
return Err(RuntimeError::InvalidArrayIndex);
}
let num = *num as usize;
if (num as usize) < arr.len() {
arr[num] = val;
Ok(())
} else if (num) == arr.len() {
arr.push(val);
Ok(())
} else {
Err(RuntimeError::InvalidArrayIndex)
}
} else {
Err(RuntimeError::InvalidArrayIndex)
}
},
ObjectInner::OBJECT(obj) => {
if let ObjectInner::STRING(prop) = index {
obj.insert(prop.clone(), val);
Ok(())
} else {
Err(RuntimeError::InvalidObjectIndex)
}
},
_ => Err(RuntimeError::InvalidIndexTarget)
}
}
Assignable::ObjectProp { obj, prop } => {
let obj = self.get_assignable(obj)?;
let obj_mut: &mut ObjectInner = &mut obj.inner();
if let ObjectInner::OBJECT(obj) = obj_mut {
obj.insert(prop.clone(), val);
Ok(())
} else {
Err(RuntimeError::InvalidPropTarget)
}
}
}
}
fn eval_statement(&mut self, statement: &Statement) -> RuntimeResult<GabrValue> {
match statement {
Statement::Expression(expression) => {
Ok(GabrValue::new(self.eval_expression(expression)?, true))
},
Statement::Let { ident, expression } => {
let val = self.eval_expression(expression)?;
self.current_context().create_var(ident.clone(), val)?;
Ok(GabrValue::new(ObjectInner::NULL.as_object(), false))
},
Statement::Assign { assignable, expression } => {
let val = self.eval_expression(expression)?;
self.set_assignable(assignable, val)?;
Ok(GabrValue::new(ObjectInner::NULL.as_object(), false))
},
Statement::Return(val) => {
match val.as_ref() {
Some(value) => {
Ok(GabrValue::new(self.eval_expression(value)?, true))
},
None => Ok(GabrValue::new(ObjectInner::NULL.as_object(), true))
}
},
Statement::If { cond, body, r#else } => {
let condition_result = self.eval_expression(cond)?.inner().is_truthy();
if condition_result {
self.eval_program_with_new_scope(body)
} else {
match r#else.as_ref() {
Some(else_block) => self.eval_program_with_new_scope(else_block),
None => Ok(GabrValue::new(ObjectInner::NULL.as_object(), false))
}
}
},
Statement::DoWhile { body, cond } => {
let mut result;
loop {
result = self.eval_program_with_new_scope(body)?;
if result.returning ||
!self.eval_expression(cond)?.inner().is_truthy() {
break
}
}
Ok(result)
},
Statement::While { cond, body } => {
let mut result = GabrValue::new(ObjectInner::NULL.as_object(), false);
while self.eval_expression(cond)?.inner().is_truthy() {
result = self.eval_program_with_new_scope(body)?;
if result.returning {
break;
}
}
Ok(result)
},
Statement::For { init, cond, update, body } => {
let mut result = GabrValue::new(ObjectInner::NULL.as_object(), false);
self.current_context().push_scope();
self.eval_statement(init)?;
while self.eval_expression(cond)?.inner().is_truthy() {
result = self.eval_program_with_new_scope(body)?;
self.eval_statement(update)?;
if result.returning {
break;
}
}
self.current_context().pop_scope()?;
Ok(result)
}
Statement::FuncDecl(func) => {
self.current_context().create_func(func.ident.clone(), func.clone())?;
Ok(GabrValue::new(ObjectInner::NULL.as_object(), false))
},
}
}
fn eval_expression(&mut self, expression: &Expression) -> RuntimeResult<Object> {
match expression {
Expression::Prefix { op, expression } => {
self.eval_prefix(*op, expression)
},
Expression::Infix { op, left, right } => {
self.eval_infix(*op, left, right)
},
Expression::Group(expression) => {
self.eval_expression(expression)
},
Expression::FuncCall { func, params } => {
self.eval_function_call(func, params)
},
Expression::Assignable(assignable) => {
Ok(self.get_assignable(assignable)?.inner().clone().as_object())
},
Expression::Literal(lit) => {
match lit {
Literal::NumberLit(num) => Ok(ObjectInner::NUMBER(num.clone()).as_object()),
Literal::StringLit(string) => Ok(ObjectInner::STRING(string.clone()).as_object()),
Literal::Bool(bool) => Ok(ObjectInner::BOOL(*bool).as_object()),
Literal::ArrayLit(arr) => {
let arr: RuntimeResult<Vec<Object>> = arr.iter()
.map(|v| self.eval_expression(v))
.collect();
Ok(ObjectInner::ARRAY(arr?).as_object())
},
Literal::ObjectLit(obj) => {
let fields: RuntimeResult<HashMap<String, Object>> = obj.iter()
.map(|(ident, expression)| Ok((ident.clone(), self.eval_expression(expression)?)))
.collect();
Ok(ObjectInner::OBJECT(fields?).as_object())
}
}
}
}
}
fn eval_prefix(&mut self, op: PrefixOp, expression: &Expression) -> RuntimeResult<Object> {
let expression = self.eval_expression(expression)?;
match op {
PrefixOp::Bang => {
Ok(ObjectInner::BOOL(!expression.inner().is_truthy()).as_object())
},
PrefixOp::Neg => {
if let ObjectInner::NUMBER(val) = *expression.inner() {
Ok(ObjectInner::NUMBER(-val).as_object())
} else {
Err(RuntimeError::InvalidPrefixTarget)
}
}
}
}
fn eval_infix(&mut self, op: InfixOp, left: &Expression, right: &Expression) -> RuntimeResult<Object> {
let op1 = self.eval_expression(left)?.inner().clone();
let op2 = self.eval_expression(right)?.inner().clone();
let op1 = match op1 {
ObjectInner::NUMBER(num) => num,
ObjectInner::BOOL(bool) => bool as i64,
ObjectInner::STRING(string1) => {
if let ObjectInner::STRING(string2) = op2 {
return Ok(ObjectInner::STRING(string1 + &string2).as_object());
} else {
return Err(RuntimeError::InvalidInfixTarget)
}
}
_ => return Err(RuntimeError::InvalidInfixTarget)
};
let op2 = match op2 {
ObjectInner::NUMBER(num) => num,
ObjectInner::BOOL(bool) => bool as i64,
_ => return Err(RuntimeError::InvalidInfixTarget)
};
let val = match op {
InfixOp::Add => op1 + op2,
InfixOp::Sub => op1 - op2,
InfixOp::Mult => op1 * op2,
InfixOp::Div => op1 / op2,
InfixOp::Eq => {
if op1 == op2 {
1
} else {
0
}
},
InfixOp::NotEq => {
if op1 != op2 {
1
} else {
0
}
}
InfixOp::Gt => {
if op1 > op2 {
1
} else {
0
}
},
InfixOp::Lt => {
if op1 < op2 {
1
} else {
0
}
}
};
Ok(ObjectInner::NUMBER(val).as_object())
}
fn eval_function_call(&mut self, func_locator: &Assignable, params: &Vec<Expression>) -> RuntimeResult<Object> {
let func = self.get_assignable(func_locator).ok();
if let Some(func) = func {
let func = &mut *func.inner();
let func = match func {
ObjectInner::FUNCTION(func) => func.clone(),
_ => return Err(RuntimeError::InvalidFunctionCallTarget)
};
let params: RuntimeResult<Vec<(String, Object)>> = func.ast.params.iter()
.map(|param| param.clone())
.zip(params.iter())
.map(|(name, param)| Ok((name, self.eval_expression(param)?)))
.collect();
let loaded_stack = self.loaded_stack.clone();
self.loaded_stack = Some(func.context.clone());
self.current_context().push_scope();
self.load_params(params?)?;
let result = self.eval_program(&func.ast.body)?;
self.current_context().pop_scope()?;
self.loaded_stack = loaded_stack;
Ok(result.gabr_object)
} else {
let func_name = match func_locator {
Assignable::Var(ident) => ident,
_ => return Err(StackError::VariableNotInScope.into()),
};
if let Some(built_in) = self.get_built_in(func_name.clone()) {
let params: RuntimeResult<Vec<(String, Object)>> = built_in.get_params().iter()
.map(|param| param.clone())
.zip(params.iter())
.map(|(name, param)| Ok((name, self.eval_expression(param)?)))
.collect();
self.current_context().push_scope();
self.load_params(params?)?;
let result = built_in.eval(self)?;
self.current_context().pop_scope()?;
Ok(result)
} else {
Err(StackError::VariableNotInScope.into())
}
}
}
pub fn current_context(&mut self) -> &mut Stack {
return self.loaded_stack.as_mut().unwrap_or(&mut self.global_stack)
}
}
#[derive(Clone)]
pub struct GabrValue {
gabr_object: Object,
returning: bool,
}
impl GabrValue {
fn new(gabr_object: Object, returning: bool) -> Self {
Self { gabr_object, returning }
}
pub fn is_some(&self) -> bool {
if let ObjectInner::NULL = *self.gabr_object.inner() {
false
} else {
true
}
}
}
impl Display for GabrValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.gabr_object)
}
}
#[derive(Clone, Debug)]
pub struct Object(Rc<RefCell<ObjectInner>>);
impl Object {
fn inner(&self) -> RefMut<ObjectInner> {
self.0.borrow_mut()
}
}
impl PartialEq for Object {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
impl Eq for Object {}
impl Hash for Object {
fn hash<H: Hasher>(&self, state: &mut H) {
let pointer = Rc::as_ptr(&self.0) as usize;
pointer.hash(state);
}
}
impl Display for Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
thread_local! {
static PRINTING: RefCell<HashSet<usize>> = RefCell::new(HashSet::new())
}
let ptr = Rc::as_ptr(&self.0) as usize;
if PRINTING.with(|printing| printing.borrow().contains(&ptr)) {
return f.write_str("Cycle");
}
PRINTING.with(|printing| printing.borrow_mut().insert(ptr));
let res = write!(f, "{}", self.0.borrow());
PRINTING.with(|printing| printing.borrow_mut().remove(&ptr));
res
}
}
#[derive(Clone, Debug)]
enum ObjectInner {
NUMBER(i64),
STRING(String),
ARRAY(Vec<Object>),
FUNCTION(FunctionInner),
OBJECT(HashMap<String, Object>),
BOOL(bool),
NULL
}
impl ObjectInner {
fn is_truthy(&self) -> bool {
match self {
Self::NUMBER(val) => *val != 0,
Self::NULL => false,
Self::BOOL(b) if !*b => false,
_ => true
}
}
fn as_object(self) -> Object {
Object(Rc::new(RefCell::new(self)))
}
}
impl Display for ObjectInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NUMBER(val) => write!(f, "{val}"),
Self::STRING(string) => f.write_str(string),
Self::ARRAY(vals) => {
write!(f, "[{}]", join(vals, ", "))
},
Self::OBJECT(obj) => {
let properties = obj.iter().map(|(key, val)| {
let mut output = String::new();
write!(output, "\t{key}: {val}").unwrap();
output
}).collect::<Vec<String>>();
write!(f, "{{\n{}\n}}", join(&properties, "\n"))
},
Self::FUNCTION(func) => write!(f, "{func}"),
Self::BOOL(bool) => write!(f, "{}", bool),
Self::NULL => f.write_str("null")
}
}
}
#[derive(Debug, Clone)]
struct FunctionInner {
ast: ast::Function,
context: Stack
}
impl Display for FunctionInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "(Function: {})", self.ast)
}
}