diff options
| author | Tolmachev Igor <me@igorek.dev> | 2026-05-10 12:54:41 +0300 |
|---|---|---|
| committer | Tolmachev Igor <me@igorek.dev> | 2026-05-10 12:54:41 +0300 |
| commit | 843242e692280d604b74324ba26ead6158223439 (patch) | |
| tree | e5f2d362b1c728f900d8214bc415752336fa4a94 | |
| parent | 1801afdbd0058cc9cc040b977de0d5652d65aab9 (diff) | |
| download | crisp-843242e692280d604b74324ba26ead6158223439.tar.gz crisp-843242e692280d604b74324ba26ead6158223439.zip | |
Remove Float from parser
Dropped to make the language simpler.
| -rw-r--r-- | compiler/src/ast/error.rs | 10 | ||||
| -rw-r--r-- | compiler/src/ast/models.rs | 1 | ||||
| -rw-r--r-- | compiler/src/ast/parser.rs | 19 | ||||
| -rw-r--r-- | compiler/src/ast/tests.rs | 96 | ||||
| -rw-r--r-- | compiler/src/lex/lexer.rs | 6 | ||||
| -rw-r--r-- | compiler/src/lex/tests.rs | 8 |
6 files changed, 7 insertions, 133 deletions
diff --git a/compiler/src/ast/error.rs b/compiler/src/ast/error.rs index 8117513..38b3916 100644 --- a/compiler/src/ast/error.rs +++ b/compiler/src/ast/error.rs | |||
| @@ -1,13 +1,8 @@ | |||
| 1 | use std::{ | 1 | use std::{error, fmt, num::ParseIntError, rc::Rc}; |
| 2 | error, fmt, | ||
| 3 | num::{ParseFloatError, ParseIntError}, | ||
| 4 | rc::Rc, | ||
| 5 | }; | ||
| 6 | 2 | ||
| 7 | #[derive(Clone, Debug, PartialEq, Eq)] | 3 | #[derive(Clone, Debug, PartialEq, Eq)] |
| 8 | pub enum Error { | 4 | pub enum Error { |
| 9 | // Number | 5 | // Number |
| 10 | InvalidFloatLiteral(Rc<str>, ParseFloatError), | ||
| 11 | InvalidIntegerLiteral(Rc<str>, ParseIntError), | 6 | InvalidIntegerLiteral(Rc<str>, ParseIntError), |
| 12 | 7 | ||
| 13 | // String | 8 | // String |
| @@ -26,9 +21,6 @@ pub enum Error { | |||
| 26 | impl fmt::Display for Error { | 21 | impl fmt::Display for Error { |
| 27 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 28 | match self { | 23 | match self { |
| 29 | Error::InvalidFloatLiteral(number, err) => { | ||
| 30 | write!(f, "invalid float literal {number}: {err}") | ||
| 31 | } | ||
| 32 | Error::InvalidIntegerLiteral(number, err) => { | 24 | Error::InvalidIntegerLiteral(number, err) => { |
| 33 | write!(f, "invalid integer literal {number}: {err}") | 25 | write!(f, "invalid integer literal {number}: {err}") |
| 34 | } | 26 | } |
diff --git a/compiler/src/ast/models.rs b/compiler/src/ast/models.rs index db9728d..2a8c5ae 100644 --- a/compiler/src/ast/models.rs +++ b/compiler/src/ast/models.rs | |||
| @@ -4,7 +4,6 @@ use crate::span::Spanned; | |||
| 4 | 4 | ||
| 5 | #[derive(Clone, Debug, PartialEq)] | 5 | #[derive(Clone, Debug, PartialEq)] |
| 6 | pub enum Atom { | 6 | pub enum Atom { |
| 7 | Float(f64), | ||
| 8 | Integer(i64), | 7 | Integer(i64), |
| 9 | String(Rc<str>), | 8 | String(Rc<str>), |
| 10 | Symbol(Rc<str>), | 9 | Symbol(Rc<str>), |
diff --git a/compiler/src/ast/parser.rs b/compiler/src/ast/parser.rs index bb4e0ce..c0ad917 100644 --- a/compiler/src/ast/parser.rs +++ b/compiler/src/ast/parser.rs | |||
| @@ -9,19 +9,9 @@ use crate::{ | |||
| 9 | pub(super) const MAX_DEPTH: usize = 256; // TODO: make it a compile flag | 9 | pub(super) const MAX_DEPTH: usize = 256; // TODO: make it a compile flag |
| 10 | 10 | ||
| 11 | fn parse_number(number: &str) -> Result<Atom, Error> { | 11 | fn parse_number(number: &str) -> Result<Atom, Error> { |
| 12 | let is_float = number.bytes().any(|b| matches!(b, b'.' | b'e' | b'E')) | 12 | match number.parse() { |
| 13 | || matches!(number, "inf" | "+inf" | "-inf" | "nan"); | 13 | Ok(ok) => Ok(Atom::Integer(ok)), |
| 14 | 14 | Err(err) => Err(Error::InvalidIntegerLiteral(number.into(), err)), | |
| 15 | if is_float { | ||
| 16 | match number.parse() { | ||
| 17 | Ok(ok) => Ok(Atom::Float(ok)), | ||
| 18 | Err(err) => Err(Error::InvalidFloatLiteral(number.into(), err)), | ||
| 19 | } | ||
| 20 | } else { | ||
| 21 | match number.parse() { | ||
| 22 | Ok(ok) => Ok(Atom::Integer(ok)), | ||
| 23 | Err(err) => Err(Error::InvalidIntegerLiteral(number.into(), err)), | ||
| 24 | } | ||
| 25 | } | 15 | } |
| 26 | } | 16 | } |
| 27 | 17 | ||
| @@ -59,9 +49,6 @@ fn parse_symbol(symbol: &str) -> Atom { | |||
| 59 | "true" => Atom::Bool(true), | 49 | "true" => Atom::Bool(true), |
| 60 | "false" => Atom::Bool(false), | 50 | "false" => Atom::Bool(false), |
| 61 | "nil" => Atom::Nil, | 51 | "nil" => Atom::Nil, |
| 62 | "inf" | "+inf" => Atom::Float(f64::INFINITY), | ||
| 63 | "-inf" => Atom::Float(f64::NEG_INFINITY), | ||
| 64 | "nan" => Atom::Float(f64::NAN), | ||
| 65 | _ => Atom::Symbol(symbol.into()), | 52 | _ => Atom::Symbol(symbol.into()), |
| 66 | } | 53 | } |
| 67 | } | 54 | } |
diff --git a/compiler/src/ast/tests.rs b/compiler/src/ast/tests.rs index 505b075..44789cb 100644 --- a/compiler/src/ast/tests.rs +++ b/compiler/src/ast/tests.rs | |||
| @@ -8,7 +8,6 @@ use crate::{ | |||
| 8 | 8 | ||
| 9 | #[derive(Debug, PartialEq)] | 9 | #[derive(Debug, PartialEq)] |
| 10 | enum E { | 10 | enum E { |
| 11 | Flt(f64), | ||
| 12 | Int(i64), | 11 | Int(i64), |
| 13 | Str(&'static str), | 12 | Str(&'static str), |
| 14 | Sym(&'static str), | 13 | Sym(&'static str), |
| @@ -21,7 +20,6 @@ impl From<Expr> for E { | |||
| 21 | fn from(expr: Expr) -> Self { | 20 | fn from(expr: Expr) -> Self { |
| 22 | match expr { | 21 | match expr { |
| 23 | Expr::Atom(atom) => match atom { | 22 | Expr::Atom(atom) => match atom { |
| 24 | Atom::Float(f) => Flt(f), | ||
| 25 | Atom::Integer(i) => Int(i), | 23 | Atom::Integer(i) => Int(i), |
| 26 | Atom::String(s) => Str(Box::leak(s.into())), | 24 | Atom::String(s) => Str(Box::leak(s.into())), |
| 27 | Atom::Symbol(s) => Sym(Box::leak(s.into())), | 25 | Atom::Symbol(s) => Sym(Box::leak(s.into())), |
| @@ -69,47 +67,11 @@ fn test_integers() { | |||
| 69 | } | 67 | } |
| 70 | 68 | ||
| 71 | #[test] | 69 | #[test] |
| 72 | fn test_floats() { | ||
| 73 | let cases = vec![ | ||
| 74 | (vec![Number("2.71")], vec![Flt(2.71)]), | ||
| 75 | (vec![Number("-2.5")], vec![Flt(-2.5)]), | ||
| 76 | (vec![Number("+0.0")], vec![Flt(0.0)]), | ||
| 77 | (vec![Number(".5")], vec![Flt(0.5)]), | ||
| 78 | (vec![Number("-.5")], vec![Flt(-0.5)]), | ||
| 79 | (vec![Number("+.5")], vec![Flt(0.5)]), | ||
| 80 | (vec![Number("1e10")], vec![Flt(1e10)]), | ||
| 81 | (vec![Number("1E10")], vec![Flt(1e10)]), | ||
| 82 | (vec![Number("1.5e-3")], vec![Flt(1.5e-3)]), | ||
| 83 | (vec![Number("-1.5E+3")], vec![Flt(-1.5e3)]), | ||
| 84 | (vec![Number("inf")], vec![Flt(f64::INFINITY)]), | ||
| 85 | (vec![Number("-inf")], vec![Flt(f64::NEG_INFINITY)]), | ||
| 86 | (vec![Number("1e9999")], vec![Flt(f64::INFINITY)]), | ||
| 87 | (vec![Number("-1e9999")], vec![Flt(f64::NEG_INFINITY)]), | ||
| 88 | ]; | ||
| 89 | for (tokens, ast) in cases { | ||
| 90 | assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}"); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | #[test] | ||
| 95 | fn test_float_nan() { | ||
| 96 | let tokens = vec![Number("nan")]; | ||
| 97 | let expr = &parse(tokens.clone())[0]; | ||
| 98 | assert!( | ||
| 99 | matches!(expr, Flt(f) if f.is_nan()), | ||
| 100 | "input: {tokens:?}, got: {expr:?}" | ||
| 101 | ); | ||
| 102 | } | ||
| 103 | |||
| 104 | #[test] | ||
| 105 | fn test_keywords() { | 70 | fn test_keywords() { |
| 106 | let cases = vec![ | 71 | let cases = vec![ |
| 107 | (vec![Symbol("true")], vec![Bool(true)]), | 72 | (vec![Symbol("true")], vec![Bool(true)]), |
| 108 | (vec![Symbol("false")], vec![Bool(false)]), | 73 | (vec![Symbol("false")], vec![Bool(false)]), |
| 109 | (vec![Symbol("nil")], vec![Nil]), | 74 | (vec![Symbol("nil")], vec![Nil]), |
| 110 | (vec![Symbol("inf")], vec![Flt(f64::INFINITY)]), | ||
| 111 | (vec![Symbol("+inf")], vec![Flt(f64::INFINITY)]), | ||
| 112 | (vec![Symbol("-inf")], vec![Flt(f64::NEG_INFINITY)]), | ||
| 113 | (vec![LeftPar, RightPar], vec![Nil]), | 75 | (vec![LeftPar, RightPar], vec![Nil]), |
| 114 | ]; | 76 | ]; |
| 115 | for (tokens, ast) in cases { | 77 | for (tokens, ast) in cases { |
| @@ -118,16 +80,6 @@ fn test_keywords() { | |||
| 118 | } | 80 | } |
| 119 | 81 | ||
| 120 | #[test] | 82 | #[test] |
| 121 | fn test_keyword_nan() { | ||
| 122 | let tokens = vec![Symbol("nan")]; | ||
| 123 | let expr = &parse(tokens.clone())[0]; | ||
| 124 | assert!( | ||
| 125 | matches!(expr, Flt(f) if f.is_nan()), | ||
| 126 | "input: {tokens:?}, got: {expr:?}" | ||
| 127 | ); | ||
| 128 | } | ||
| 129 | |||
| 130 | #[test] | ||
| 131 | fn test_keywords_case_sensitive() { | 83 | fn test_keywords_case_sensitive() { |
| 132 | let cases = vec![ | 84 | let cases = vec![ |
| 133 | (vec![Symbol("True")], vec![Sym("True")]), | 85 | (vec![Symbol("True")], vec![Sym("True")]), |
| @@ -241,7 +193,7 @@ fn test_lists() { | |||
| 241 | vec![ | 193 | vec![ |
| 242 | LeftPar, | 194 | LeftPar, |
| 243 | Number("1"), | 195 | Number("1"), |
| 244 | Number("2.5"), | 196 | Number("-1"), |
| 245 | String("s"), | 197 | String("s"), |
| 246 | Symbol("foo"), | 198 | Symbol("foo"), |
| 247 | Symbol("true"), | 199 | Symbol("true"), |
| @@ -250,7 +202,7 @@ fn test_lists() { | |||
| 250 | ], | 202 | ], |
| 251 | vec![List(vec![ | 203 | vec![List(vec![ |
| 252 | Int(1), | 204 | Int(1), |
| 253 | Flt(2.5), | 205 | Int(-1), |
| 254 | Str("s"), | 206 | Str("s"), |
| 255 | Sym("foo"), | 207 | Sym("foo"), |
| 256 | Bool(true), | 208 | Bool(true), |
| @@ -351,36 +303,6 @@ fn test_invalid_integer() { | |||
| 351 | } | 303 | } |
| 352 | 304 | ||
| 353 | #[test] | 305 | #[test] |
| 354 | fn test_invalid_float() { | ||
| 355 | let cases = vec![ | ||
| 356 | "12somE0txt", | ||
| 357 | "12som.0txt", | ||
| 358 | "12.3txt", | ||
| 359 | "1.2.3", | ||
| 360 | "1.2.3.4", | ||
| 361 | ".", | ||
| 362 | "+.", | ||
| 363 | "-.", | ||
| 364 | "1e", | ||
| 365 | "1e+", | ||
| 366 | "1e-", | ||
| 367 | "1.e", | ||
| 368 | ".e5", | ||
| 369 | "1ee5", | ||
| 370 | "1e1.5", | ||
| 371 | ]; | ||
| 372 | for number in cases { | ||
| 373 | let tokens = vec![Number(number)]; | ||
| 374 | let error = number.parse::<f64>().unwrap_err(); | ||
| 375 | assert_eq!( | ||
| 376 | parse_err(tokens.clone()), | ||
| 377 | Error::InvalidFloatLiteral(number.into(), error), | ||
| 378 | "input: {tokens:?}", | ||
| 379 | ); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | #[test] | ||
| 384 | fn test_unclosed_string() { | 306 | fn test_unclosed_string() { |
| 385 | let cases = vec![ | 307 | let cases = vec![ |
| 386 | ( | 308 | ( |
| @@ -505,20 +427,6 @@ fn test_error_span_invalid_integer() { | |||
| 505 | } | 427 | } |
| 506 | 428 | ||
| 507 | #[test] | 429 | #[test] |
| 508 | fn test_error_span_invalid_float() { | ||
| 509 | let s = sp((1, 0, 0), (1, 5, 5)); | ||
| 510 | let tokens = vec![tsp(Number("1.2.3"), s)]; | ||
| 511 | let err = parse_sp_err(tokens.clone()); | ||
| 512 | |||
| 513 | assert!( | ||
| 514 | matches!(err.inner, Error::InvalidFloatLiteral(..)), | ||
| 515 | "input: {tokens:?}, got: {:?}", | ||
| 516 | err.inner, | ||
| 517 | ); | ||
| 518 | assert_eq!(err.span, s, "input: {tokens:?}"); | ||
| 519 | } | ||
| 520 | |||
| 521 | #[test] | ||
| 522 | fn test_error_span_unclosed_left_par() { | 430 | fn test_error_span_unclosed_left_par() { |
| 523 | let lp = sp((1, 0, 0), (1, 1, 1)); | 431 | let lp = sp((1, 0, 0), (1, 1, 1)); |
| 524 | let tokens = vec![tsp(LeftPar, lp)]; | 432 | let tokens = vec![tsp(LeftPar, lp)]; |
diff --git a/compiler/src/lex/lexer.rs b/compiler/src/lex/lexer.rs index 6efbca0..5e45b20 100644 --- a/compiler/src/lex/lexer.rs +++ b/compiler/src/lex/lexer.rs | |||
| @@ -131,12 +131,8 @@ impl<'a> Iterator for Lexer<'a> { | |||
| 131 | 131 | ||
| 132 | // Number | 132 | // Number |
| 133 | ch if ch.is_ascii_digit() | 133 | ch if ch.is_ascii_digit() |
| 134 | || ch == '.' && self.peek_nth(1).is_some_and(|ch| ch.is_ascii_digit()) | ||
| 135 | || matches!(ch, '+' | '-') | 134 | || matches!(ch, '+' | '-') |
| 136 | && self.peek_nth(1).is_some_and(|ch| ch.is_ascii_digit()) | 135 | && self.peek_nth(1).is_some_and(|ch| ch.is_ascii_digit()) => |
| 137 | || matches!(ch, '+' | '-') | ||
| 138 | && self.peek_nth(1).is_some_and(|ch| ch == '.') | ||
| 139 | && self.peek_nth(2).is_some_and(|ch| ch.is_ascii_digit()) => | ||
| 140 | { | 136 | { |
| 141 | Token::Number(self.next_atom()) | 137 | Token::Number(self.next_atom()) |
| 142 | } | 138 | } |
diff --git a/compiler/src/lex/tests.rs b/compiler/src/lex/tests.rs index d0ed658..0672dfa 100644 --- a/compiler/src/lex/tests.rs +++ b/compiler/src/lex/tests.rs | |||
| @@ -42,16 +42,8 @@ fn test_numbers() { | |||
| 42 | let cases = vec![ | 42 | let cases = vec![ |
| 43 | ("0", vec![Number("0")]), | 43 | ("0", vec![Number("0")]), |
| 44 | ("42", vec![Number("42")]), | 44 | ("42", vec![Number("42")]), |
| 45 | ("3.14", vec![Number("3.14")]), | ||
| 46 | ("-7", vec![Number("-7")]), | 45 | ("-7", vec![Number("-7")]), |
| 47 | ("+5", vec![Number("+5")]), | 46 | ("+5", vec![Number("+5")]), |
| 48 | ("-0.5", vec![Number("-0.5")]), | ||
| 49 | ("1e10", vec![Number("1e10")]), | ||
| 50 | ("1.5e-3", vec![Number("1.5e-3")]), | ||
| 51 | (".5", vec![Number(".5")]), | ||
| 52 | ("-.5", vec![Number("-.5")]), | ||
| 53 | ("+.5", vec![Number("+.5")]), | ||
| 54 | ("-.0", vec![Number("-.0")]), | ||
| 55 | ]; | 47 | ]; |
| 56 | for (code, tokens) in cases { | 48 | for (code, tokens) in cases { |
| 57 | assert_eq!(tokenize(code), tokens); | 49 | assert_eq!(tokenize(code), tokens); |
