Add simple tests
This commit is contained in:
parent
2f0744d5ee
commit
a39914bc35
5 changed files with 336 additions and 96 deletions
219
src/executor.rs
219
src/executor.rs
|
@ -1,16 +1,88 @@
|
|||
use std::{collections::HashMap, fmt};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{parse, LispState, LispValue, Tokenizer, TokenizerError};
|
||||
|
||||
use super::add_function;
|
||||
|
||||
fn get_exec_result(source: &str) -> Result<Vec<LispValue>, TokenizerError> {
|
||||
let mut state = LispState::new();
|
||||
|
||||
state.table.insert(String::from("output"), LispValue::List(vec![], false));
|
||||
add_function(&mut state.table, "print", |st, args| {
|
||||
if let LispValue::List(v, _) = st.table.get_mut("output").unwrap() {
|
||||
v.push(LispValue::List(args, false))
|
||||
}
|
||||
|
||||
vec![LispValue::Nil]
|
||||
});
|
||||
|
||||
let mut tokenizer = Tokenizer::new(String::from(source));
|
||||
let instructions = parse(tokenizer.tokenize()?);
|
||||
|
||||
state.execute(instructions);
|
||||
|
||||
let mut out = Vec::new();
|
||||
if let LispValue::List(outerlist, _) = &state.table["output"] {
|
||||
for list in outerlist {
|
||||
if let LispValue::List(innerlist, _) = list {
|
||||
for innervalue in innerlist {
|
||||
out.push(innervalue.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hello_world() -> Result<(), TokenizerError> {
|
||||
assert_eq!(
|
||||
vec![
|
||||
LispValue::String(String::from("Hello, World!"))
|
||||
],
|
||||
get_exec_result("
|
||||
(print \"Hello, World!\")
|
||||
")?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_math() -> Result<(), TokenizerError> {
|
||||
assert_eq!(
|
||||
vec![
|
||||
LispValue::Float(16.05)
|
||||
],
|
||||
get_exec_result("
|
||||
(print
|
||||
(add
|
||||
(div
|
||||
4.5
|
||||
(sub 0.5 0.2)
|
||||
)
|
||||
(mul 21 0.05)
|
||||
)
|
||||
)
|
||||
")?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
use crate::PreLispValue;
|
||||
|
||||
pub struct LispState {
|
||||
table: HashMap<String, LispValue>,
|
||||
}
|
||||
|
||||
fn add_function<T: Into<String> + Clone>(table: &mut HashMap<String, LispValue>, name: T, func: fn(Vec<LispValue>) -> Vec<LispValue>) {
|
||||
fn add_function<T: Into<String> + Clone>(table: &mut HashMap<String, LispValue>, name: T, func: fn(&mut LispState, Vec<LispValue>) -> Vec<LispValue>) {
|
||||
table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func));
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum LispValue {
|
||||
Nil,
|
||||
String(String),
|
||||
|
@ -18,11 +90,12 @@ pub enum LispValue {
|
|||
Float(f32),
|
||||
List(Vec<LispValue>, bool),
|
||||
LispFunction(String, Vec<LispValue>),
|
||||
RustFunction(String, fn(Vec<LispValue>) -> Vec<LispValue>),
|
||||
RustFunction(String, fn(&mut LispState, Vec<LispValue>) -> Vec<LispValue>),
|
||||
}
|
||||
|
||||
impl fmt::Display for LispValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[allow(unreachable_patterns)]
|
||||
match self {
|
||||
LispValue::Nil => write!(f, "nil"),
|
||||
LispValue::String(str) => write!(f, "\"{}\"", str),
|
||||
|
@ -38,9 +111,9 @@ impl fmt::Display for LispValue {
|
|||
}
|
||||
|
||||
if *quoted {
|
||||
write!(f, "'({})", strs.join(", "))
|
||||
write!(f, "'({})", strs.join(" "))
|
||||
} else {
|
||||
write!(f, "({})", strs.join(", "))
|
||||
write!(f, "({})", strs.join(" "))
|
||||
}
|
||||
},
|
||||
val => {
|
||||
|
@ -75,9 +148,9 @@ impl LispState {
|
|||
pub fn new() -> LispState {
|
||||
let mut table = HashMap::new();
|
||||
|
||||
add_function(&mut table, "print", |x| {
|
||||
add_function(&mut table, "print", |_, args| {
|
||||
let mut strings = Vec::new();
|
||||
for val in x {
|
||||
for val in args {
|
||||
strings.push(val.to_string());
|
||||
}
|
||||
|
||||
|
@ -87,9 +160,9 @@ impl LispState {
|
|||
vec![LispValue::Nil]
|
||||
});
|
||||
|
||||
add_function(&mut table, "concat", |x| {
|
||||
add_function(&mut table, "concat", |_, args| {
|
||||
let mut strings = Vec::new();
|
||||
for val in x {
|
||||
for val in args {
|
||||
strings.push(val.to_string());
|
||||
}
|
||||
|
||||
|
@ -97,15 +170,15 @@ impl LispState {
|
|||
vec![LispValue::String(str)]
|
||||
});
|
||||
|
||||
add_function(&mut table, "add", |x| {
|
||||
if x.len() < 1 {
|
||||
add_function(&mut table, "add", |_, args| {
|
||||
if args.len() < 1 {
|
||||
return vec![LispValue::Nil]
|
||||
} else if x.len() == 1 {
|
||||
return vec![x[0].clone()];
|
||||
} else if args.len() == 1 {
|
||||
return vec![args[0].clone()];
|
||||
}
|
||||
|
||||
let mut t = "int";
|
||||
for v in &x {
|
||||
for v in &args {
|
||||
match v {
|
||||
LispValue::Float(_) => t = "float",
|
||||
LispValue::Integer(_) => (),
|
||||
|
@ -116,7 +189,7 @@ impl LispState {
|
|||
match t {
|
||||
"int" => {
|
||||
let mut sum = 0;
|
||||
for v in &x {
|
||||
for v in &args {
|
||||
if let LispValue::Integer(n) = v {
|
||||
sum += n;
|
||||
} else {
|
||||
|
@ -127,7 +200,7 @@ impl LispState {
|
|||
},
|
||||
"float" => {
|
||||
let mut sum = 0.0 as f32;
|
||||
for v in &x {
|
||||
for v in &args {
|
||||
if let LispValue::Float(n) = v {
|
||||
sum += n;
|
||||
} else if let LispValue::Integer(n) = v{
|
||||
|
@ -142,15 +215,15 @@ impl LispState {
|
|||
}
|
||||
});
|
||||
|
||||
add_function(&mut table, "sub", |x| {
|
||||
if x.len() < 1 {
|
||||
add_function(&mut table, "sub", |_, args| {
|
||||
if args.len() < 1 {
|
||||
return vec![LispValue::Nil]
|
||||
} else if x.len() == 1 {
|
||||
return vec![x[0].clone()];
|
||||
} else if args.len() == 1 {
|
||||
return vec![args[0].clone()];
|
||||
}
|
||||
|
||||
let mut t = "int";
|
||||
for v in &x {
|
||||
for v in &args {
|
||||
match v {
|
||||
LispValue::Float(_) => t = "float",
|
||||
LispValue::Integer(_) => (),
|
||||
|
@ -160,10 +233,10 @@ impl LispState {
|
|||
|
||||
match t {
|
||||
"int" => {
|
||||
if let LispValue::Integer(n) = x[0] {
|
||||
if let LispValue::Integer(n) = args[0] {
|
||||
let mut sum = n;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Integer(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Integer(n) = &args[i] {
|
||||
sum -= n;
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -175,24 +248,24 @@ impl LispState {
|
|||
}
|
||||
},
|
||||
"float" => {
|
||||
if let LispValue::Float(n) = x[0] {
|
||||
if let LispValue::Float(n) = args[0] {
|
||||
let mut sum = n;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Float(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Float(n) = &args[i] {
|
||||
sum -= *n;
|
||||
} else if let LispValue::Integer(n) = &x[i] {
|
||||
} else if let LispValue::Integer(n) = &args[i] {
|
||||
sum -= *n as f32;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
return vec![LispValue::Float(sum)];
|
||||
} else if let LispValue::Integer(n) = x[0] {
|
||||
} else if let LispValue::Integer(n) = args[0] {
|
||||
let mut sum = n as f32;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Float(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Float(n) = &args[i] {
|
||||
sum -= *n;
|
||||
} else if let LispValue::Integer(n) = &x[i] {
|
||||
} else if let LispValue::Integer(n) = &args[i] {
|
||||
sum -= *n as f32;
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -207,15 +280,15 @@ impl LispState {
|
|||
}
|
||||
});
|
||||
|
||||
add_function(&mut table, "mul", |x| {
|
||||
if x.len() < 1 {
|
||||
add_function(&mut table, "mul", |_, args| {
|
||||
if args.len() < 1 {
|
||||
return vec![LispValue::Nil]
|
||||
} else if x.len() == 1 {
|
||||
return vec![x[0].clone()];
|
||||
} else if args.len() == 1 {
|
||||
return vec![args[0].clone()];
|
||||
}
|
||||
|
||||
let mut t = "int";
|
||||
for v in &x {
|
||||
for v in &args {
|
||||
match v {
|
||||
LispValue::Float(_) => t = "float",
|
||||
LispValue::Integer(_) => (),
|
||||
|
@ -225,10 +298,10 @@ impl LispState {
|
|||
|
||||
match t {
|
||||
"int" => {
|
||||
if let LispValue::Integer(n) = x[0] {
|
||||
if let LispValue::Integer(n) = args[0] {
|
||||
let mut sum = n;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Integer(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Integer(n) = &args[i] {
|
||||
sum *= n;
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -240,24 +313,24 @@ impl LispState {
|
|||
}
|
||||
},
|
||||
"float" => {
|
||||
if let LispValue::Float(n) = x[0] {
|
||||
if let LispValue::Float(n) = args[0] {
|
||||
let mut product = n;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Float(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Float(n) = &args[i] {
|
||||
product *= *n;
|
||||
} else if let LispValue::Integer(n) = &x[i] {
|
||||
} else if let LispValue::Integer(n) = &args[i] {
|
||||
product *= *n as f32;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
return vec![LispValue::Float(product)];
|
||||
} else if let LispValue::Integer(n) = x[0] {
|
||||
} else if let LispValue::Integer(n) = args[0] {
|
||||
let mut product = n as f32;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Float(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Float(n) = &args[i] {
|
||||
product *= *n;
|
||||
} else if let LispValue::Integer(n) = &x[i] {
|
||||
} else if let LispValue::Integer(n) = &args[i] {
|
||||
product *= *n as f32;
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -272,15 +345,15 @@ impl LispState {
|
|||
}
|
||||
});
|
||||
|
||||
add_function(&mut table, "div", |x| {
|
||||
if x.len() < 1 {
|
||||
add_function(&mut table, "div", |_, args| {
|
||||
if args.len() < 1 {
|
||||
return vec![LispValue::Nil]
|
||||
} else if x.len() == 1 {
|
||||
return vec![x[0].clone()];
|
||||
} else if args.len() == 1 {
|
||||
return vec![args[0].clone()];
|
||||
}
|
||||
|
||||
let mut t = "int";
|
||||
for v in &x {
|
||||
for v in &args {
|
||||
match v {
|
||||
LispValue::Float(_) => t = "float",
|
||||
LispValue::Integer(_) => (),
|
||||
|
@ -290,10 +363,10 @@ impl LispState {
|
|||
|
||||
match t {
|
||||
"int" => {
|
||||
if let LispValue::Integer(n) = x[0] {
|
||||
if let LispValue::Integer(n) = args[0] {
|
||||
let mut sum = n;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Integer(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Integer(n) = &args[i] {
|
||||
sum /= n;
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -305,24 +378,24 @@ impl LispState {
|
|||
}
|
||||
},
|
||||
"float" => {
|
||||
if let LispValue::Float(n) = x[0] {
|
||||
if let LispValue::Float(n) = args[0] {
|
||||
let mut product = n;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Float(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Float(n) = &args[i] {
|
||||
product /= *n;
|
||||
} else if let LispValue::Integer(n) = &x[i] {
|
||||
} else if let LispValue::Integer(n) = &args[i] {
|
||||
product /= *n as f32;
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
return vec![LispValue::Float(product)];
|
||||
} else if let LispValue::Integer(n) = x[0] {
|
||||
} else if let LispValue::Integer(n) = args[0] {
|
||||
let mut product = n as f32;
|
||||
for i in 1..x.len() {
|
||||
if let LispValue::Float(n) = &x[i] {
|
||||
for i in 1..args.len() {
|
||||
if let LispValue::Float(n) = &args[i] {
|
||||
product /= *n;
|
||||
} else if let LispValue::Integer(n) = &x[i] {
|
||||
} else if let LispValue::Integer(n) = &args[i] {
|
||||
product /= *n as f32;
|
||||
} else {
|
||||
unreachable!()
|
||||
|
@ -366,7 +439,7 @@ impl LispState {
|
|||
out
|
||||
}
|
||||
|
||||
fn eval_list(list: &Vec<LispValue>, quoted: bool) -> (Vec<LispValue>, bool) {
|
||||
fn eval_list(&mut self, list: &Vec<LispValue>, quoted: bool) -> (Vec<LispValue>, bool) {
|
||||
if list.len() < 1 {
|
||||
return (vec![LispValue::List(Vec::new(), quoted)], false);
|
||||
}
|
||||
|
@ -375,7 +448,7 @@ impl LispState {
|
|||
|
||||
for i in 0..list.len() {
|
||||
if let LispValue::List(elements, quoted) = &list[i] {
|
||||
let (elems, astuple) = Self::eval_list(elements, *quoted);
|
||||
let (elems, astuple) = self.eval_list(elements, *quoted);
|
||||
if astuple {
|
||||
list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned();
|
||||
for j in 1..elems.len() {
|
||||
|
@ -392,23 +465,23 @@ impl LispState {
|
|||
}
|
||||
|
||||
if let LispValue::RustFunction(_name, f) = &list[0] {
|
||||
(f(list[1..].to_vec()), true)
|
||||
} else if let LispValue::LispFunction(_name, ins) = &list[0] {
|
||||
(Self::call_lisp_func(&list[0], list[1..].to_vec()), true)
|
||||
(f(self, list[1..].to_vec()), true)
|
||||
} else if let LispValue::LispFunction(_name, _) = &list[0] {
|
||||
(self.call_lisp_func(&list[0], list[1..].to_vec()), true)
|
||||
} else {
|
||||
(list.to_vec(), false)
|
||||
}
|
||||
}
|
||||
|
||||
fn call_lisp_func(f: &LispValue, args: Vec<LispValue>) -> Vec<LispValue> {
|
||||
todo!()
|
||||
fn call_lisp_func(&mut self, f: &LispValue, args: Vec<LispValue>) -> Vec<LispValue> {
|
||||
todo!("Calling lisp function {} with args {:?}", f, args)
|
||||
}
|
||||
|
||||
pub fn execute(&self, instructions: Vec<PreLispValue>) {
|
||||
pub fn execute(&mut self, instructions: Vec<PreLispValue>) {
|
||||
let instructions = Self::handle_prevalues(self, instructions);
|
||||
for val in instructions {
|
||||
if let LispValue::List(elements, quoted) = val {
|
||||
Self::eval_list(&elements, quoted);
|
||||
self.eval_list(&elements, quoted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -7,20 +7,16 @@ use parser::*;
|
|||
mod executor;
|
||||
use executor::*;
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), TokenizerError> {
|
||||
let source = std::fs::read_to_string("src/test.lisp").unwrap();
|
||||
|
||||
let mut tokenizer = Tokenizer::new(source);
|
||||
let tokens = match tokenizer.tokenize() {
|
||||
Ok(tokens) => tokens,
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
let tokens = tokenizer.tokenize()?;
|
||||
let instructions = parse(tokens);
|
||||
|
||||
let state = LispState::new();
|
||||
let mut state = LispState::new();
|
||||
|
||||
state.execute(instructions);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,8 +1,91 @@
|
|||
use std::fmt;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{parse, PreLispValue, Tokenizer, TokenizerError};
|
||||
|
||||
fn quick_parse(source: &str) -> Result<Vec<PreLispValue>, TokenizerError> {
|
||||
let mut tokenizer = Tokenizer::new(String::from(source));
|
||||
let tokens = tokenizer.tokenize()?;
|
||||
Ok(parse(tokens))
|
||||
}
|
||||
|
||||
fn var(name: &str) -> PreLispValue {
|
||||
PreLispValue::Var(String::from(name))
|
||||
}
|
||||
fn string(s: &str) -> PreLispValue {
|
||||
PreLispValue::String(String::from(s))
|
||||
}
|
||||
fn list(v: Vec<PreLispValue>, quoted: bool) -> PreLispValue {
|
||||
PreLispValue::List(v, quoted)
|
||||
}
|
||||
fn int(n: i32) -> PreLispValue {
|
||||
PreLispValue::Integer(n)
|
||||
}
|
||||
fn float(n: f32) -> PreLispValue {
|
||||
PreLispValue::Float(n)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hello_world() -> Result<(), TokenizerError> {
|
||||
assert_eq!(
|
||||
vec![
|
||||
list(vec![
|
||||
var("print"),
|
||||
string("Hello, World!")
|
||||
], false)
|
||||
],
|
||||
quick_parse("
|
||||
(print \"Hello, World!\")
|
||||
")?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_math() -> Result<(), TokenizerError> {
|
||||
assert_eq!(
|
||||
vec![
|
||||
list(vec![
|
||||
var("print"),
|
||||
list(vec![
|
||||
var("add"),
|
||||
list(vec![
|
||||
var("div"),
|
||||
float(4.5),
|
||||
list(vec![
|
||||
var("sub"),
|
||||
float(0.5),
|
||||
float(0.2)
|
||||
], false)
|
||||
], false),
|
||||
list(vec![
|
||||
var("mul"),
|
||||
int(21),
|
||||
float(0.05)
|
||||
], false)
|
||||
], false)
|
||||
], false)
|
||||
],
|
||||
quick_parse("
|
||||
(print
|
||||
(add
|
||||
(div
|
||||
4.5
|
||||
(sub 0.5 0.2)
|
||||
)
|
||||
(mul 21 0.05)
|
||||
)
|
||||
)
|
||||
")?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
use crate::Token;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum PreLispValue {
|
||||
Nil,
|
||||
String(String),
|
||||
|
@ -110,7 +193,11 @@ fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue {
|
|||
unquote_next_list = false;
|
||||
},
|
||||
Token::Identifier(name) => {
|
||||
values.push(PreLispValue::Var(name.to_owned()));
|
||||
if name == &String::from("nil") {
|
||||
values.push(PreLispValue::Nil)
|
||||
} else {
|
||||
values.push(PreLispValue::Var(name.to_owned()));
|
||||
}
|
||||
},
|
||||
Token::Integer(num) => {
|
||||
values.push(PreLispValue::Integer(*num));
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
; This is a comment
|
||||
|
||||
(print "Hello, world!")
|
||||
|
||||
(print (1 2 3))
|
||||
|
||||
(print
|
||||
(add 15 105.3)
|
||||
)
|
||||
|
||||
(print
|
||||
'(add 15 105.3)
|
||||
)
|
||||
(add
|
||||
(div
|
||||
4.5
|
||||
(sub 0.5 0.2)
|
||||
)
|
||||
(mul 21 0.05)
|
||||
)
|
||||
)
|
|
@ -1,6 +1,92 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Token, Tokenizer, TokenizerError};
|
||||
|
||||
fn quick_tokenize(source: &str) -> Result<Vec<Token>, TokenizerError> {
|
||||
let mut tokenizer = Tokenizer::new(String::from(source));
|
||||
return tokenizer.tokenize();
|
||||
}
|
||||
|
||||
fn open() -> Token {
|
||||
Token::OpenParen
|
||||
}
|
||||
fn close() -> Token {
|
||||
Token::CloseParen
|
||||
}
|
||||
fn iden(s: &str) -> Token {
|
||||
Token::Identifier(String::from(s))
|
||||
}
|
||||
fn string(s: &str) -> Token {
|
||||
Token::String(String::from(s))
|
||||
}
|
||||
fn int(n: i32) -> Token {
|
||||
Token::Integer(n)
|
||||
}
|
||||
fn float(n: f32) -> Token {
|
||||
Token::Float(n)
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_hello_world() -> Result<(), TokenizerError> {
|
||||
assert_eq!(
|
||||
vec![
|
||||
open(),
|
||||
iden("print"),
|
||||
string("Hello, World!"),
|
||||
close()
|
||||
],
|
||||
quick_tokenize("
|
||||
(print \"Hello, World!\")
|
||||
")?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_math() -> Result<(), TokenizerError> {
|
||||
assert_eq!(
|
||||
vec![
|
||||
open(),
|
||||
iden("print"),
|
||||
open(),
|
||||
iden("add"),
|
||||
open(),
|
||||
iden("div"),
|
||||
float(4.5),
|
||||
open(),
|
||||
iden("sub"),
|
||||
float(0.5),
|
||||
float(0.2),
|
||||
close(),
|
||||
close(),
|
||||
open(),
|
||||
iden("mul"),
|
||||
int(21),
|
||||
float(0.05),
|
||||
close(),
|
||||
close(),
|
||||
close()
|
||||
],
|
||||
quick_tokenize("
|
||||
(print
|
||||
(add
|
||||
(div
|
||||
4.5
|
||||
(sub 0.5 0.2)
|
||||
)
|
||||
(mul 21 0.05)
|
||||
)
|
||||
)
|
||||
")?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Token {
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
|
@ -12,7 +98,7 @@ pub enum Token {
|
|||
Float(f32)
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TokenizerError {
|
||||
line: u64,
|
||||
column: u64,
|
||||
|
|
Reference in a new issue