mirror of https://github.com/vinc/moros.git
Add support for hexadecimal numbers in Lisp (#540)
* Add support for hexadecimal numbers in lisp * Add source in comment * Add support for 0X * Add doc * Remove extra space in doc * Remove plural * Add negative number to doc * Update doc * Fix typo * Add ntp client * Add ntp to install * Remove ntp code
This commit is contained in:
parent
74df7467cb
commit
96b20dfb51
|
@ -9,7 +9,11 @@ MOROS Lisp is a Lisp-1 dialect inspired by Scheme, Clojure, and Ruby!
|
|||
|
||||
### Types
|
||||
- Basics: `bool`, `list`, `symbol`, `string`
|
||||
- Numbers: `float`, `int`, `bigint`
|
||||
- Number: `float`, `int`, `bigint`
|
||||
|
||||
### Literals
|
||||
- String: `"Hello, World!"`
|
||||
- Number: `2.5`, `-25`, `255`, `0xFF`, `0xDEAD_C0DE`
|
||||
|
||||
### Built-in Operators
|
||||
- `quote` (abbreviated with `'`)
|
||||
|
@ -203,3 +207,4 @@ language and reading from the filesystem.
|
|||
- Add socket functions
|
||||
|
||||
### Unreleased
|
||||
- Add hexadecimal number literals
|
||||
|
|
|
@ -339,6 +339,25 @@ fn test_lisp() {
|
|||
};
|
||||
}
|
||||
|
||||
// num
|
||||
assert_eq!(eval!("6"), "6");
|
||||
assert_eq!(eval!("16"), "16");
|
||||
assert_eq!(eval!("0x6"), "6");
|
||||
assert_eq!(eval!("0xf"), "15");
|
||||
assert_eq!(eval!("0x10"), "16");
|
||||
assert_eq!(eval!("1.5"), "1.5");
|
||||
assert_eq!(eval!("0xff"), "255");
|
||||
assert_eq!(eval!("0XFF"), "255");
|
||||
|
||||
assert_eq!(eval!("-6"), "-6");
|
||||
assert_eq!(eval!("-16"), "-16");
|
||||
assert_eq!(eval!("-0x6"), "-6");
|
||||
assert_eq!(eval!("-0xF"), "-15");
|
||||
assert_eq!(eval!("-0x10"), "-16");
|
||||
assert_eq!(eval!("-1.5"), "-1.5");
|
||||
assert_eq!(eval!("-0xff"), "-255");
|
||||
assert_eq!(eval!("-0XFF"), "-255");
|
||||
|
||||
// quote
|
||||
assert_eq!(eval!("(quote (1 2 3))"), "(1 2 3)");
|
||||
assert_eq!(eval!("'(1 2 3)"), "(1 2 3)");
|
||||
|
@ -500,6 +519,9 @@ fn test_lisp() {
|
|||
// bigint
|
||||
assert_eq!(eval!("9223372036854775807"), "9223372036854775807"); // -> int
|
||||
assert_eq!(eval!("9223372036854775808"), "9223372036854775808"); // -> bigint
|
||||
assert_eq!(eval!("0x7fffffffffffffff"), "9223372036854775807"); // -> int
|
||||
assert_eq!(eval!("0x8000000000000000"), "9223372036854775808"); // -> bigint
|
||||
assert_eq!(eval!("0x800000000000000f"), "9223372036854775823"); // -> bigint
|
||||
assert_eq!(eval!("(+ 9223372036854775807 0)"), "9223372036854775807"); // -> int
|
||||
assert_eq!(eval!("(- 9223372036854775808 1)"), "9223372036854775807"); // -> bigint
|
||||
assert_eq!(eval!("(+ 9223372036854775807 1)"), "9223372036854775808"); // -> bigint
|
||||
|
|
|
@ -5,9 +5,12 @@ use alloc::format;
|
|||
use alloc::vec::Vec;
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
use core::num::ParseIntError;
|
||||
use core::ops::{Neg, Add, Div, Mul, Sub, Rem, Shl, Shr};
|
||||
use core::str::FromStr;
|
||||
use num_bigint::BigInt;
|
||||
use num_bigint::ParseBigIntError;
|
||||
use num_traits::Num;
|
||||
use num_traits::Zero;
|
||||
use num_traits::cast::ToPrimitive;
|
||||
|
||||
|
@ -196,39 +199,46 @@ operator!(Rem, rem);
|
|||
operator!(Shl, shl);
|
||||
operator!(Shr, shr);
|
||||
|
||||
fn parse_int(s: &str) -> Result<i64, ParseIntError> {
|
||||
if s.starts_with("0x") || s.starts_with("0X") {
|
||||
i64::from_str_radix(&s[2..], 16)
|
||||
} else if s.starts_with("-0x") || s.starts_with("-0X") {
|
||||
i64::from_str_radix(&s[3..], 16).map(|n| -n)
|
||||
} else {
|
||||
i64::from_str_radix(s, 10)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_float(s: &str) -> Result<BigInt, ParseBigIntError> {
|
||||
if s.starts_with("0x") || s.starts_with("0X") {
|
||||
BigInt::from_str_radix(&s[2..], 16)
|
||||
} else if s.starts_with("-0x") || s.starts_with("-0X") {
|
||||
BigInt::from_str_radix(&s[3..], 16).map(|n| -n)
|
||||
} else {
|
||||
BigInt::from_str_radix(s, 10)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Number {
|
||||
type Err = Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let err = could_not!("parse number");
|
||||
if s.is_empty() {
|
||||
return Ok(Number::Int(0));
|
||||
Ok(Number::Int(0))
|
||||
} else if s.contains('.') {
|
||||
if let Ok(n) = s.parse() {
|
||||
return Ok(Number::Float(n));
|
||||
Ok(Number::Float(n))
|
||||
} else {
|
||||
err
|
||||
}
|
||||
} else if let Ok(n) = s.parse() {
|
||||
return Ok(Number::Int(n));
|
||||
} else if let Ok(n) = parse_int(s) {
|
||||
Ok(Number::Int(n))
|
||||
} else if let Ok(n) = parse_float(s) {
|
||||
Ok(Number::BigInt(n))
|
||||
} else {
|
||||
let mut chars = s.chars().peekable();
|
||||
let is_neg = chars.peek() == Some(&'-');
|
||||
if is_neg {
|
||||
chars.next().unwrap();
|
||||
}
|
||||
let mut res = BigInt::from(0);
|
||||
for c in chars {
|
||||
if !c.is_ascii_digit() {
|
||||
return err;
|
||||
}
|
||||
let d = c as u8 - b'0';
|
||||
res = res * BigInt::from(10) + BigInt::from(d as u32);
|
||||
}
|
||||
res *= BigInt::from(if is_neg { -1 } else { 1 });
|
||||
return Ok(Number::BigInt(res));
|
||||
} /* else if let Ok(n) = s.parse() { // FIXME: rust-lld: error: undefined symbol: fmod
|
||||
return Ok(Number::BigInt(n));
|
||||
} */
|
||||
err
|
||||
err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ use nom::bytes::complete::is_not;
|
|||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::take_while1;
|
||||
use nom::character::complete::char;
|
||||
use nom::character::complete::digit1;
|
||||
use nom::character::complete::multispace0;
|
||||
use nom::combinator::map;
|
||||
use nom::combinator::opt;
|
||||
|
@ -23,6 +22,66 @@ use nom::multi::many0;
|
|||
use nom::sequence::delimited;
|
||||
use nom::sequence::preceded;
|
||||
use nom::sequence::tuple;
|
||||
use nom::character::complete::one_of;
|
||||
use nom::multi::many1;
|
||||
use nom::sequence::terminated;
|
||||
|
||||
// https://docs.rs/nom/latest/nom/recipes/index.html#hexadecimal
|
||||
fn hexadecimal(input: &str) -> IResult<&str, &str> {
|
||||
preceded(
|
||||
alt((tag("0x"), tag("0X"))),
|
||||
recognize(
|
||||
many1(
|
||||
terminated(one_of("0123456789abcdefABCDEF"), many0(char('_')))
|
||||
)
|
||||
)
|
||||
)(input)
|
||||
}
|
||||
|
||||
// https://docs.rs/nom/latest/nom/recipes/index.html#decimal
|
||||
fn decimal(input: &str) -> IResult<&str, &str> {
|
||||
recognize(
|
||||
many1(
|
||||
terminated(one_of("0123456789"), many0(char('_')))
|
||||
)
|
||||
)(input)
|
||||
}
|
||||
|
||||
// https://docs.rs/nom/latest/nom/recipes/index.html#floating-point-numbers
|
||||
fn float(input: &str) -> IResult<&str, &str> {
|
||||
alt((
|
||||
recognize( // .42
|
||||
tuple((
|
||||
char('.'),
|
||||
decimal,
|
||||
opt(tuple((
|
||||
one_of("eE"),
|
||||
opt(one_of("+-")),
|
||||
decimal
|
||||
)))
|
||||
))
|
||||
),
|
||||
recognize( // 42e42 and 42.42e42
|
||||
tuple((
|
||||
decimal,
|
||||
opt(preceded(
|
||||
char('.'),
|
||||
decimal,
|
||||
)),
|
||||
one_of("eE"),
|
||||
opt(one_of("+-")),
|
||||
decimal
|
||||
))
|
||||
),
|
||||
recognize( // 42. and 42.42
|
||||
tuple((
|
||||
decimal,
|
||||
char('.'),
|
||||
opt(decimal)
|
||||
))
|
||||
)
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn is_symbol_letter(c: char) -> bool {
|
||||
let chars = "<>=-+*/%^?.";
|
||||
|
@ -49,8 +108,7 @@ fn parse_sym(input: &str) -> IResult<&str, Exp> {
|
|||
fn parse_num(input: &str) -> IResult<&str, Exp> {
|
||||
let (input, num) = recognize(tuple((
|
||||
opt(alt((char('+'), char('-')))),
|
||||
digit1,
|
||||
opt(tuple((char('.'), digit1)))
|
||||
alt((float, hexadecimal, decimal))
|
||||
)))(input)?;
|
||||
Ok((input, Exp::Num(Number::from(num))))
|
||||
}
|
||||
|
|
|
@ -19,7 +19,14 @@ of the Shell.</p>
|
|||
|
||||
<ul>
|
||||
<li>Basics: <code>bool</code>, <code>list</code>, <code>symbol</code>, <code>string</code></li>
|
||||
<li>Numbers: <code>float</code>, <code>int</code>, <code>bigint</code></li>
|
||||
<li>Number: <code>float</code>, <code>int</code>, <code>bigint</code></li>
|
||||
</ul>
|
||||
|
||||
<h3>Literals</h3>
|
||||
|
||||
<ul>
|
||||
<li>String: <code>"Hello, World!"</code></li>
|
||||
<li>Number: <code>2.5</code>, <code>-25</code>, <code>255</code>, <code>0xFF</code>, <code>0xDEAD_C0DE</code></li>
|
||||
</ul>
|
||||
|
||||
<h3>Built-in Operators</h3>
|
||||
|
@ -244,5 +251,9 @@ language and reading from the filesystem.</p>
|
|||
</ul>
|
||||
|
||||
<h3>Unreleased</h3>
|
||||
|
||||
<ul>
|
||||
<li>Add hexadecimal number literals</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue