float and int values.

main
bog 2024-03-01 15:34:45 +01:00
parent 6e94192fa9
commit efdbafb645
6 changed files with 181 additions and 25 deletions

View File

@ -1,4 +1,4 @@
MODULE ::= INSTR* MODULE ::= INSTR*
INSTR ::= EXPR semicolon INSTR ::= EXPR semicolon
EXPR ::= BUILTIN EXPR ::= BUILTIN
BUILTIN ::= bool BUILTIN ::= bool | float | int

View File

@ -1,8 +1,8 @@
use crate::ast::node; use crate::ast::node::Node;
struct Token { struct Token {
position: usize, position: usize,
value: String, value: String
} }
pub struct Lexer { pub struct Lexer {
@ -53,6 +53,79 @@ impl Lexer {
false false
} }
fn scan_int(&self) -> Option<Token> {
let mut value = String::from("");
if let Some('-') = self.text.chars().nth(self.cursor) {
value.push('-');
}
for c in self.text.chars().skip(self.cursor + value.len()) {
if c.is_digit(10) {
value.push(c);
} else {
break;
}
}
if value.len() > 0 {
Some(Token {
position: self.cursor + value.len(),
value
})
} else {
None
}
}
fn scan_float(&self) -> Option<Token> {
let mut value = String::from("");
if let Some('-') = self.text.chars().nth(self.cursor) {
value.push('-');
}
for c in self.text.chars().skip(self.cursor + value.len()) {
if c.is_digit(10) {
value.push(c);
} else {
break;
}
}
if let Some('.') = self.text.chars().nth(self.cursor + value.len()) {
value.push('.');
} else {
return None;
}
for c in self.text.chars().skip(self.cursor + value.len()) {
if c.is_digit(10) {
value.push(c);
} else {
break;
}
}
if value.len() > 0 && value != "." {
if value.chars().nth(0).unwrap() == '.' {
value = format!("0{}", value);
}
if value.chars().last().unwrap() == '.' {
value = format!("{}0", value);
}
Some(Token {
position: self.cursor + value.len(),
value
})
} else {
None
}
}
fn scan_text(&self, text: &str) -> Option<Token> { fn scan_text(&self, text: &str) -> Option<Token> {
let c = self.cursor; let c = self.cursor;
@ -112,24 +185,38 @@ impl Lexer {
} }
impl Iterator for Lexer { impl Iterator for Lexer {
type Item = node::Node; type Item = Node;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.skip_spaces(); self.skip_spaces();
if let Some(token) = self.scan_keyword("true") { if let Some(token) = self.scan_keyword("true") {
self.cursor = token.position; self.cursor = token.position;
return Some(node::Node::Bool(token.value == "true")); return Some(Node::Bool(token.value == "true"));
} }
if let Some(token) = self.scan_keyword("false") { if let Some(token) = self.scan_keyword("false") {
self.cursor = token.position; self.cursor = token.position;
return Some(node::Node::Bool(token.value == "true")); return Some(Node::Bool(token.value == "true"));
} }
if let Some(token) = self.scan_text(";") { if let Some(token) = self.scan_text(";") {
self.cursor = token.position; self.cursor = token.position;
return Some(node::Node::Semicolon); return Some(Node::Semicolon);
}
if let Some(token) = self.scan_float() {
if let Ok(val) = token.value.parse::<f64>() {
self.cursor = token.position;
return Some(Node::Float(val));
}
}
if let Some(token) = self.scan_int() {
if let Ok(val) = token.value.parse::<i32>() {
self.cursor = token.position;
return Some(Node::Int(val));
}
} }
None None
@ -140,8 +227,9 @@ impl Iterator for Lexer {
mod test { mod test {
use super::*; use super::*;
use crate::ast::error; use crate::ast::error;
use crate::ast::node::Node;
fn lexer_run(lexer: &mut Lexer, text: &str) -> Result<Vec<node::Node>, error::AstError> { fn lexer_run(lexer: &mut Lexer, text: &str) -> Result<Vec<Node>, error::AstError> {
lexer.prepare(text); lexer.prepare(text);
let result = lexer.collect(); let result = lexer.collect();
@ -168,8 +256,8 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, "true false").unwrap(); let res = lexer_run(&mut lex, "true false").unwrap();
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!("Bool(true)", format!("{:?}", res.get(0).unwrap())); assert_eq!(Node::Bool(true), *res.get(0).unwrap());
assert_eq!("Bool(false)", format!("{:?}", res.get(1).unwrap())); assert_eq!(Node::Bool(false), *res.get(1).unwrap());
} }
#[test] #[test]
@ -177,8 +265,8 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, "true;").unwrap(); let res = lexer_run(&mut lex, "true;").unwrap();
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!("Bool(true)", format!("{:?}", res.get(0).unwrap())); assert_eq!(Node::Bool(true), *res.get(0).unwrap());
assert_eq!("Semicolon", format!("{:?}", res.get(1).unwrap())); assert_eq!(Node::Semicolon, *res.get(1).unwrap());
} }
#[test] #[test]
@ -203,8 +291,33 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " ;; ")?; let res = lexer_run(&mut lex, " ;; ")?;
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!("Semicolon", format!("{:?}", res.get(0).unwrap())); assert_eq!(Node::Semicolon, *res.get(0).unwrap());
assert_eq!("Semicolon", format!("{:?}", res.get(1).unwrap())); assert_eq!(Node::Semicolon, *res.get(1).unwrap());
Ok(())
}
#[test]
fn test_integers() -> Result<(), error::AstError> {
let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " 4 -2 328")?;
assert_eq!(3, res.len());
assert_eq!(Node::Int(4), *res.get(0).unwrap());
assert_eq!(Node::Int(-2), *res.get(1).unwrap());
assert_eq!(Node::Int(328), *res.get(2).unwrap());
Ok(())
}
#[test]
fn test_floats() -> Result<(), error::AstError> {
let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " 2.0 .7 5. -3.14 ")?;
assert_eq!(4, res.len());
assert_eq!(Node::Float(2.0), *res.get(0).unwrap());
assert_eq!(Node::Float(0.7), *res.get(1).unwrap());
assert_eq!(Node::Float(5.0), *res.get(2).unwrap());
assert_eq!(Node::Float(-3.14), *res.get(3).unwrap());
Ok(()) Ok(())
} }
} }

View File

@ -3,6 +3,8 @@
pub enum Node { pub enum Node {
Module(String, Vec<Node>), Module(String, Vec<Node>),
Bool(bool), Bool(bool),
Int(i32),
Float(f64),
Semicolon Semicolon
} }

View File

@ -1,5 +1,5 @@
use crate::ast::{ use crate::ast::{
node, node::Node,
lexer, lexer,
error error
}; };
@ -9,7 +9,7 @@ pub struct Parser {
lexer: lexer::Lexer lexer: lexer::Lexer
} }
type ParseResult = Result<Option<node::Node>, error::AstError>; type ParseResult = Result<Option<Node>, error::AstError>;
impl Parser { impl Parser {
pub fn new(module_name: &str, lex: lexer::Lexer) -> Self { pub fn new(module_name: &str, lex: lexer::Lexer) -> Self {
@ -24,7 +24,7 @@ impl Parser {
} }
fn parse_module(&mut self) -> ParseResult { fn parse_module(&mut self) -> ParseResult {
let mut children: Vec<node::Node> = vec![]; let mut children: Vec<Node> = vec![];
loop { loop {
match self.parse_instr() { match self.parse_instr() {
@ -41,7 +41,7 @@ impl Parser {
}); });
} }
let n = node::Node::Module(self.module_name.clone(), children); let n = Node::Module(self.module_name.clone(), children);
Ok(Some(n)) Ok(Some(n))
} }
@ -49,7 +49,7 @@ impl Parser {
match self.parse_expr() { match self.parse_expr() {
Ok(Some(expr)) => { Ok(Some(expr)) => {
match self.lexer.next() { match self.lexer.next() {
Some(node::Node::Semicolon) => Ok(Some(expr)), Some(Node::Semicolon) => Ok(Some(expr)),
None => Ok(None), None => Ok(None),
_ => Err(error::AstError { _ => Err(error::AstError {
msg: String::from("missing semicolon"), msg: String::from("missing semicolon"),
@ -68,8 +68,14 @@ impl Parser {
fn parse_builtin(&mut self) -> ParseResult { fn parse_builtin(&mut self) -> ParseResult {
match self.lexer.next() { match self.lexer.next() {
Some(node::Node::Bool(value)) Some(Node::Int(value))
=> Ok(Some(node::Node::Bool(value))), => Ok(Some(Node::Int(value))),
Some(Node::Float(value))
=> Ok(Some(Node::Float(value))),
Some(Node::Bool(value))
=> Ok(Some(Node::Bool(value))),
Some(other) => { Some(other) => {
Err(error::AstError { Err(error::AstError {
@ -86,11 +92,10 @@ impl Parser {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::ast::node::Node;
type TestResult = Result<(), String>; type TestResult = Result<(), String>;
fn test_parser(oracle: node::Node, source: &str) -> TestResult { fn test_parser(oracle: Node, source: &str) -> TestResult {
let mut lex = lexer::Lexer::new(); let mut lex = lexer::Lexer::new();
lex.prepare(source); lex.prepare(source);
let mut parser = Parser::new("mod", lex); let mut parser = Parser::new("mod", lex);
@ -140,4 +145,23 @@ mod test {
Ok(()) Ok(())
} }
#[test]
fn numbers() -> TestResult {
test_parser(
Node::Module("mod".to_owned(), vec![
Node::Float(27.3)
]),
" 27.3; "
)?;
test_parser(
Node::Module("mod".to_owned(), vec![
Node::Int(-27)
]),
" -27; "
)?;
Ok(())
}
} }

View File

@ -29,7 +29,11 @@ impl Evaluator {
Ok(res) Ok(res)
}, },
Node::Bool(value) => Ok(Some(Value::Bool(*value))), Node::Bool(value) => Ok(Some(Value::Bool(*value))),
Node::Int(value) => Ok(Some(Value::Int(*value))),
Node::Float(value) => Ok(Some(Value::Float(*value))),
_ => Ok(None) _ => Ok(None)
} }
} }
@ -65,7 +69,10 @@ mod test {
Ok(()) Ok(())
} }
} else { } else {
Ok(()) Err(Box::new(EvalError {
msg: format!("unexpected: {:?}", value),
line: 0
}))
} }
}, },
None => Ok(()) None => Ok(())
@ -79,4 +86,12 @@ mod test {
Ok(()) Ok(())
} }
#[test]
fn numbers() -> TestResult {
test_eval_value(Value::Float(-271.4), " -271.4; ")?;
test_eval_value(Value::Int(333), " 333; ")?;
Ok(())
}
} }

View File

@ -1,6 +1,8 @@
#[derive(PartialEq)] #[derive(PartialEq)]
#[derive(Debug)] #[derive(Debug)]
pub enum Value { pub enum Value {
Bool(bool) Bool(bool),
Int(i32),
Float(f64)
} }