aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parse/parsetree.rs12
-rw-r--r--src/sexp/display.rs12
-rw-r--r--src/sexp/mod.rs18
-rw-r--r--src/sexp/step.rs114
-rw-r--r--src/type/check.rs31
-rw-r--r--src/type/display.rs6
-rw-r--r--src/type/mod.rs7
-rw-r--r--src/type/subst.rs2
8 files changed, 196 insertions, 6 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs
index 5507b0b..3cdc6fe 100644
--- a/src/parse/parsetree.rs
+++ b/src/parse/parsetree.rs
@@ -99,6 +99,18 @@ fn tokens_to_ast_inner(
Some(Sym(s)) if s == "*" => Ok(Atom(Mul)),
Some(Sym(s)) if s == "/" => Ok(Atom(Div)),
Some(Sym(s)) if s == "-" => Ok(Atom(Sub)),
+ Some(Sym(s)) if s == ">" => Ok(Atom(Gt)),
+ Some(Sym(s)) if s == "<" => Ok(Atom(Lt)),
+ Some(Sym(s)) if s == ">=" => Ok(Atom(Ge)),
+ Some(Sym(s)) if s == "<=" => Ok(Atom(Le)),
+ Some(Sym(s)) if s == "=" => Ok(Atom(Eq)),
+ Some(Sym(s)) if s == "!=" => Ok(Atom(Neq)),
+ Some(Sym(s)) if s == "and" => Ok(Atom(And)),
+ Some(Sym(s)) if s == "or" => Ok(Atom(Or)),
+ Some(Sym(s)) if s == "not" => Ok(Atom(Not)),
+ Some(Sym(s)) if s == "xor" => Ok(Atom(Xor)),
+ Some(Sym(s)) if s == "true" => Ok(Atom(True)),
+ Some(Sym(s)) if s == "false" => Ok(Atom(False)),
Some(Sym(s)) if s == "quote" => Ok(Atom(Quote)),
Some(Sym(s)) => Ok(Atom(Var(s))),
Some(ParClose) => break,
diff --git a/src/sexp/display.rs b/src/sexp/display.rs
index 238e8d4..96ce435 100644
--- a/src/sexp/display.rs
+++ b/src/sexp/display.rs
@@ -11,6 +11,18 @@ impl fmt::Display for SLeaf {
Sub => "-".to_string(),
Mul => "*".to_string(),
Div => "/".to_string(),
+ Gt => ">".to_string(),
+ Lt => "<".to_string(),
+ Ge => ">=".to_string(),
+ Le => "<=".to_string(),
+ Eq => "=".to_string(),
+ Neq => "!=".to_string(),
+ And => "and".to_string(),
+ Or => "or".to_string(),
+ Not => "not".to_string(),
+ Xor => "xor".to_string(),
+ True => "true".to_string(),
+ False => "false".to_string(),
Int(x) => x.to_string(),
Var(s) => s.to_string(),
Quote => "quote".to_string(),
diff --git a/src/sexp/mod.rs b/src/sexp/mod.rs
index 0fb5e25..60dd3b0 100644
--- a/src/sexp/mod.rs
+++ b/src/sexp/mod.rs
@@ -12,13 +12,29 @@ pub mod display;
#[derive(PartialEq)]
#[derive(Clone)]
pub enum SLeaf {
+
Add,
Sub,
Mul,
Div,
+ Eq,
+ Neq,
+ Gt,
+ Lt,
+ Ge,
+ Le,
+ And,
+ Or,
+ Not,
+ Xor,
+ Quote,
+
Int(i32),
+ True,
+ False,
+
Var(String),
- Quote,
+
Nil,
}
diff --git a/src/sexp/step.rs b/src/sexp/step.rs
index ee76ebf..bb3ada5 100644
--- a/src/sexp/step.rs
+++ b/src/sexp/step.rs
@@ -44,6 +44,7 @@ impl SExp {
/// ```
///
/// Also, addition and multiplication can take more than two arguments:
+ /// (as of 2025-08-05 not allowed by the type system, might change)
/// ```rust
/// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
///
@@ -84,6 +85,119 @@ impl SExp {
///
/// ```
///
+ /// **Integer comparisons**
+ ///
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ ///
+ /// assert_eq!(
+ /// scons(Lt, scons(1, scons(2, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Lt, scons(2, scons(2, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Gt, scons(2, scons(1, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Lt, scons(1, scons(1, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Le, scons(1, scons(2, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Le, scons(2, scons(2, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Lt, scons(2, scons(1, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Ge, scons(2, scons(1, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Ge, scons(1, scons(1, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Lt, scons(1, scons(2, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Eq, scons(1, scons(2, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ /// assert_eq!(
+ /// scons(Eq, scons(2, scons(2, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Neq, scons(1, scons(2, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Neq, scons(2, scons(2, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ /// ```
+ ///
+ /// **Boolean expressions**
+ ///
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// assert_eq!(
+ /// scons(And, scons(True, scons(True, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(And, scons(False, scons(True, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Or, scons(False, scons(True, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Or, scons(False, scons(False, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Xor, scons(False, scons(True, Nil))).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// assert_eq!(
+ /// scons(Xor, scons(False, scons(False, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ /// assert_eq!(
+ /// scons(Xor, scons(True, scons(True, Nil))).step(),
+ /// Ok(Atom(False))
+ /// );
+ ///
+ /// assert_eq!(
+ /// scons(Not, scons(True, Nil)).step(),
+ /// Ok(Atom(False))
+ /// );
+ /// assert_eq!(
+ /// scons(Not, scons(False, Nil)).step(),
+ /// Ok(Atom(True))
+ /// );
+ /// ```
+ ///
/// **Quotes**
/// If an s-expression should not be evaluated
/// as a function, but it is instead to be treated
diff --git a/src/type/check.rs b/src/type/check.rs
index 9369d97..e9917c7 100644
--- a/src/type/check.rs
+++ b/src/type/check.rs
@@ -16,6 +16,7 @@ impl SExp {
/// };
///
/// assert_eq!(Atom(Int(1)).type_check(), Ok(Integer));
+ /// assert_eq!(Atom(False).type_check(), Ok(Boolean));
/// ```
///
/// Quotes are given list types:
@@ -26,8 +27,8 @@ impl SExp {
/// };
///
/// assert_eq!(
- /// scons(Quote, scons(1, scons(2, Nil))).type_check(),
- /// Ok(List(vec![Integer, Integer]))
+ /// scons(Quote, scons(1, scons(False, Nil))).type_check(),
+ /// Ok(List(vec![Integer, Boolean]))
/// );
/// ```
/// Though so is Nil given too:
@@ -54,6 +55,16 @@ impl SExp {
/// assert_eq!(Atom(Mul).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer)));
/// assert_eq!(Atom(Sub).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer)));
/// assert_eq!(Atom(Div).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer)));
+ /// assert_eq!(Atom(Eq) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean)));
+ /// assert_eq!(Atom(Neq).type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean)));
+ /// assert_eq!(Atom(Gt) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean)));
+ /// assert_eq!(Atom(Lt) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean)));
+ /// assert_eq!(Atom(Ge) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean)));
+ /// assert_eq!(Atom(Le) .type_check(), Ok(arr(List(vec![Integer, Integer]), Boolean)));
+ /// assert_eq!(Atom(And).type_check(), Ok(arr(List(vec![Boolean, Boolean]), Boolean)));
+ /// assert_eq!(Atom(Or) .type_check(), Ok(arr(List(vec![Boolean, Boolean]), Boolean)));
+ /// assert_eq!(Atom(Xor).type_check(), Ok(arr(List(vec![Boolean, Boolean]), Boolean)));
+ /// assert_eq!(Atom(Not).type_check(), Ok(arr(Boolean, Boolean)));
/// ```
///
/// Though perhaps the most important task of the type system
@@ -94,6 +105,10 @@ impl SExp {
/// "passing '-' as an argument to '+' should return in InvalidArgList error"
/// ),
/// };
+ ///
+ /// assert!(scons(And, scons(1, scons(Atom(True), Nil))).type_check().is_err());
+ /// assert!(scons(Mul, scons(1, scons(Atom(True), Nil))).type_check().is_err());
+ /// assert!(scons(Not, scons(1, Nil)).type_check().is_err());
/// ```
///
/// Also, free variables should result in an error
@@ -121,6 +136,8 @@ impl SExp {
match self {
Atom(Int(_)) => Ok(Integer),
+ Atom(True) => todo!(),
+ Atom(False) => todo!(),
Atom(Var(name)) => ctx.get(name)
.ok_or(UndefinedVariable(name.to_string()))
.cloned(),
@@ -128,6 +145,16 @@ impl SExp {
Atom(Mul) => Ok(arr(List(vec![Integer, Integer]), Integer)), // TODO varlen
Atom(Sub) => Ok(arr(List(vec![Integer, Integer]), Integer)),
Atom(Div) => Ok(arr(List(vec![Integer, Integer]), Integer)),
+ Atom(Eq) => todo!(),
+ Atom(Neq) => todo!(),
+ Atom(Lt) => todo!(),
+ Atom(Gt) => todo!(),
+ Atom(Le) => todo!(),
+ Atom(Ge) => todo!(),
+ Atom(Or) => todo!(),
+ Atom(And) => todo!(),
+ Atom(Xor) => todo!(),
+ Atom(Not) => todo!(),
Atom(Nil) => Ok(List(vec![])),
Atom(Quote) => Ok(arr(
VarType("T".to_string()),
diff --git a/src/type/display.rs b/src/type/display.rs
index 2fca5f9..832b289 100644
--- a/src/type/display.rs
+++ b/src/type/display.rs
@@ -11,8 +11,9 @@ impl fmt::Display for Type {
/// ```rust
/// use myslip::r#type::{Type::*, util::*};
/// assert_eq!(Integer.to_string(), "Int".to_string());
- /// assert_eq!(arr(Integer, Integer).to_string(), "(Int -> Int)".to_string());
- /// assert_eq!(List(vec![Integer, Integer, Integer]).to_string(), "(Int Int Int)".to_string());
+ /// assert_eq!(Boolean.to_string(), "Bool".to_string());
+ /// assert_eq!(arr(Integer, Boolean).to_string(), "(Int -> Bool)".to_string());
+ /// assert_eq!(List(vec![Integer, Boolean, Integer]).to_string(), "(Int Bool Int)".to_string());
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@@ -27,6 +28,7 @@ impl fmt::Display for Type {
.join(" ")
),
VarType(name) => write!(f, "{}", name),
+ Boolean => todo!(),
}
}
}
diff --git a/src/type/mod.rs b/src/type/mod.rs
index 8761cee..8977d85 100644
--- a/src/type/mod.rs
+++ b/src/type/mod.rs
@@ -14,6 +14,8 @@ pub enum Type {
Integer,
+ Boolean,
+
Arrow(Box<Type>, Box<Type>),
List(Vec<Type>),
@@ -63,19 +65,21 @@ impl Type {
/// use myslip::r#type::{*, Type::*, TypeError::*, util::*};
///
/// assert_eq!(Integer.is_concrete(), Ok(()));
+ /// assert_eq!(Boolean.is_concrete(), Ok(()));
/// assert_eq!(
/// VarType("a".to_string()).is_concrete(),
/// Err("a".to_string())
/// );
///
/// assert_eq!(arr(Integer, Integer).is_concrete(), Ok(()));
+ /// assert_eq!(arr(Integer, Boolean).is_concrete(), Ok(()));
/// assert_eq!(
/// arr(VarType("b".to_string()), Integer).is_concrete(),
/// Err("b".to_string())
/// );
///
/// assert_eq!(
- /// List(vec![Integer, Integer, arr(Integer, Integer)]).is_concrete(),
+ /// List(vec![Integer, Boolean, arr(Integer, Integer)]).is_concrete(),
/// Ok(())
/// );
/// assert_eq!(
@@ -87,6 +91,7 @@ impl Type {
pub fn is_concrete(&self) -> Result<(), String> {
match self {
Integer => Ok(()),
+ Boolean => todo!(),
Arrow(a, b) => b.is_concrete().and_then(|_ok| a.is_concrete()),
List(v) => {
let mut res = Ok(());
diff --git a/src/type/subst.rs b/src/type/subst.rs
index 1774770..79c5fe1 100644
--- a/src/type/subst.rs
+++ b/src/type/subst.rs
@@ -39,6 +39,8 @@ impl Type {
Integer => Integer,
+ Boolean => Boolean,
+
}
}
}