From 3afaf03e74a7930280c6b682d42b8d53785617a4 Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 25 Mar 2021 13:06:07 +0530 Subject: add checked downcast methods to LispExpr --- src/lisp/expr.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs index 40b39eb..acd3365 100644 --- a/src/lisp/expr.rs +++ b/src/lisp/expr.rs @@ -1,7 +1,10 @@ -use std::fmt; +use std::{convert::TryFrom, fmt}; use crate::app::AppState; -use crate::lisp::{error::LispError, number::LispNumber}; +use crate::lisp::{ + error::{EvalError, LispError}, + number::LispNumber, +}; #[derive(Clone)] pub struct PrimitiveFunc { @@ -13,13 +16,16 @@ impl PrimitiveFunc { pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result { if let Some(arity) = self.arity { if args.len() < arity { - return Err(LispError::EvalError); + return Err(EvalError::ArgumentCount(self.arity.map(|u| u as u32)).into()); } } (self.closure)(args, app) } } +pub type Ident = String; +pub type BoolLit = bool; + #[derive(Clone)] pub struct LispFunction { pub params: Vec, @@ -33,7 +39,7 @@ pub enum LispExpr { List(Vec), StringLit(String), BoolLit(bool), - Ident(String), + Ident(Ident), PrimitiveFunc(PrimitiveFunc), Function(LispFunction), @@ -110,3 +116,51 @@ impl fmt::Display for LispExpr { Ok(()) } } + +impl TryFrom for LispNumber { + type Error = LispError; + fn try_from(value: LispExpr) -> Result { + match value { + LispExpr::Number(i) => Ok(i), + _ => Err(LispError::Eval(EvalError::TypeMismatch)), + } + } +} + +impl<'a> TryFrom<&'a LispExpr> for &'a LispNumber { + type Error = LispError; + fn try_from(value: &'a LispExpr) -> Result { + match value { + LispExpr::Number(i) => Ok(i), + _ => Err(LispError::Eval(EvalError::TypeMismatch)), + } + } +} + +impl TryFrom for Ident { + type Error = LispError; + fn try_from(value: LispExpr) -> Result { + match value { + LispExpr::Ident(i) => Ok(i), + _ => Err(LispError::Eval(EvalError::TypeMismatch)), + } + } +} + +impl TryFrom for BoolLit { + type Error = LispError; + fn try_from(value: LispExpr) -> Result { + match value { + LispExpr::BoolLit(i) => Ok(i), + _ => Err(LispError::Eval(EvalError::TypeMismatch)), + } + } +} + +pub fn is_ident>(expr: E) -> bool { + matches!(expr.as_ref(), LispExpr::Ident(_)) +} + +pub fn is_number>(expr: E) -> bool { + matches!(expr.as_ref(), LispExpr::Number(_)) +} -- cgit v1.2.3