Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions crates/loon-lang/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,45 @@ mod tests {
assert_eq!(exprs.len(), 1);
}

#[test]
fn parse_scientific_notation_without_decimal_point() {
for (src, want) in [
("1e6", 1e6),
("2.5e-3", 2.5e-3),
("1E+3", 1e3),
("-4e2", -4e2),
("3e-0", 3.0),
] {
let exprs = parse(src).unwrap();
assert_eq!(exprs.len(), 1, "{src}");
match &exprs[0].kind {
ExprKind::Float(f) => assert_eq!(*f, want, "{src}"),
other => panic!("{src} parsed as {other:?}"),
}
}
// Inside a call: one argument each, not `1e` + `6`.
let exprs = parse("[cube 1e6 1e6 1e6]").unwrap();
match &exprs[0].kind {
ExprKind::List(items) => {
assert_eq!(items.len(), 4);
assert!(items[1..]
.iter()
.all(|e| matches!(e.kind, ExprKind::Float(f) if f == 1e6)));
}
other => panic!("{other:?}"),
}
assert_eq!(exprs[0].to_string(), "[cube 1000000 1000000 1000000]");
}

#[test]
fn unit_suffixes_still_desugar() {
assert_eq!(parse("10mm").unwrap()[0].to_string(), "[unit 10 :mm]");
assert_eq!(parse("2.5in").unwrap()[0].to_string(), "[unit 2.5 :in]");
assert_eq!(parse("90deg").unwrap()[0].to_string(), "[unit 90 :deg]");
// An exponent followed by a unit keeps both.
assert_eq!(parse("1e3mm").unwrap()[0].to_string(), "[unit 1000 :mm]");
}

#[test]
fn parse_hello_world() {
let src = r#"[fn main [] [println "hello, world!"]]"#;
Expand Down
4 changes: 4 additions & 0 deletions crates/loon-lang/src/syntax/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ pub enum Token {

// Literals — higher priority than Symbol
#[regex(r"-?[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?(f32|f64|[a-zA-Z]+)?", priority = 10, callback = |lex| lex.slice().to_string())]
// Scientific notation without a decimal point (1e6, 2E-3, 1e+3mm). Longest
// match beats the Int rule's unit-suffix group, which would otherwise read
// `1e6` as `1e` (unit `:e`) followed by `6`.
#[regex(r"-?[0-9]+[eE][+-]?[0-9]+(f32|f64|[a-zA-Z]+)?", priority = 11, callback = |lex| lex.slice().to_string())]
Float(String),
// Radix literals (issue #24): hex 0xFF, octal 0o17, binary 0b1010.
// Higher priority than the decimal rule, which would otherwise split
Expand Down
Loading