Skip to content

Commit

Permalink
feat: add bin/oct/hex literal
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Jul 12, 2023
1 parent e73e404 commit 9025fe7
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 10 deletions.
2 changes: 1 addition & 1 deletion crates/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn type_from_token_kind(kind: TokenKind) -> Type {
use TokenKind::*;

match kind {
NatLit => Type::Nat,
NatLit | BinLit | OctLit | HexLit => Type::Nat,
IntLit => Type::Int,
RatioLit => Type::Ratio,
StrLit | DocComment => Type::Str,
Expand Down
29 changes: 23 additions & 6 deletions crates/erg_compiler/ty/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,12 +920,29 @@ impl ValueObj {
pub fn from_str(t: Type, mut content: Str) -> Option<Self> {
match t {
Type::Int => content.replace('_', "").parse::<i32>().ok().map(Self::Int),
Type::Nat => content
.trim_start_matches('-') // -0 -> 0
.replace('_', "")
.parse::<u64>()
.ok()
.map(Self::Nat),
Type::Nat => {
let content = content
.trim_start_matches('-') // -0 -> 0
.replace('_', "");
if content.len() <= 1 {
return content.parse::<u64>().ok().map(Self::Nat);
}
match &content[0..=1] {
pre @ ("0b" | "0B") => {
let content = content.trim_start_matches(pre);
u64::from_str_radix(content, 2).ok().map(Self::Nat)
}
pre @ ("0o" | "0O") => {
let content = content.trim_start_matches(pre);
u64::from_str_radix(content, 8).ok().map(Self::Nat)
}
pre @ ("0x" | "0X") => {
let content = content.trim_start_matches(pre);
u64::from_str_radix(content, 16).ok().map(Self::Nat)
}
_ => content.parse::<u64>().ok().map(Self::Nat),
}
}
Type::Float => content
.replace('_', "")
.parse::<f64>()
Expand Down
47 changes: 46 additions & 1 deletion crates/erg_parser/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,18 @@ impl Lexer /*<'a>*/ {
n if n.is_ascii_digit() || n == '_' => {
num.push(self.consume().unwrap());
}
'b' | 'B' => {
num.push(self.consume().unwrap());
return self.lex_bin(num);
}
'o' | 'O' => {
num.push(self.consume().unwrap());
return self.lex_oct(num);
}
'x' | 'X' => {
num.push(self.consume().unwrap());
return self.lex_hex(num);
}
c if Self::is_valid_continue_symbol_ch(c) => {
// exponent (e.g. 10e+3)
if c == 'e'
Expand Down Expand Up @@ -682,6 +694,39 @@ impl Lexer /*<'a>*/ {
}
}

fn lex_bin(&mut self, mut num: String) -> LexResult<Token> {
while let Some(cur) = self.peek_cur_ch() {
if cur == '0' || cur == '1' || cur == '_' {
num.push(self.consume().unwrap());
} else {
break;
}
}
Ok(self.emit_token(BinLit, &num))
}

fn lex_oct(&mut self, mut num: String) -> LexResult<Token> {
while let Some(cur) = self.peek_cur_ch() {
if matches!(cur, '0'..='7') || cur == '_' {
num.push(self.consume().unwrap());
} else {
break;
}
}
Ok(self.emit_token(OctLit, &num))
}

fn lex_hex(&mut self, mut num: String) -> LexResult<Token> {
while let Some(cur) = self.peek_cur_ch() {
if cur.is_ascii_hexdigit() || cur == '_' {
num.push(self.consume().unwrap());
} else {
break;
}
}
Ok(self.emit_token(HexLit, &num))
}

/// int_part_and_point must be like `12.`
fn lex_ratio(&mut self, intpart_and_point: String) -> LexResult<Token> {
let mut num = intpart_and_point;
Expand Down Expand Up @@ -1547,7 +1592,7 @@ impl Iterator for Lexer /*<'a>*/ {
None,
)))
}
// IntLit or RatioLit
// IntLit (or Bin/Oct/Hex) or RatioLit
Some(n) if n.is_ascii_digit() => Some(self.lex_num(n)),
// Symbol (includes '_')
Some(c) if Self::is_valid_start_symbol_ch(c) => Some(self.lex_symbol(c)),
Expand Down
10 changes: 8 additions & 2 deletions crates/erg_parser/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ pub enum TokenKind {
NatLit,
/// e.g. -1, -2
IntLit,
/// e.g. 0b101
BinLit,
/// e.g. 0o777
OctLit,
/// e.g. 0xdeadbeef
HexLit,
RatioLit,
BoolLit,
StrLit,
Expand Down Expand Up @@ -232,8 +238,8 @@ impl TokenKind {
pub const fn category(&self) -> TokenCategory {
match self {
Symbol => TokenCategory::Symbol,
NatLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit | EllipsisLit | InfLit
| DocComment => TokenCategory::Literal,
NatLit | BinLit | OctLit | HexLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit
| EllipsisLit | InfLit | DocComment => TokenCategory::Literal,
StrInterpLeft => TokenCategory::StrInterpLeft,
StrInterpMid => TokenCategory::StrInterpMid,
StrInterpRight => TokenCategory::StrInterpRight,
Expand Down
8 changes: 8 additions & 0 deletions tests/should_ok/decimal.er
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
b = 0b010010
assert b == 18

o = 0o22
assert o == 18

h = 0x12
assert h == 18
5 changes: 5 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ fn exec_control_expr() -> Result<(), ()> {
expect_success("tests/should_ok/control_expr.er", 3)
}

#[test]
fn exec_decimal() -> Result<(), ()> {
expect_success("tests/should_ok/decimal.er", 0)
}

#[test]
fn exec_default_param() -> Result<(), ()> {
expect_success("tests/should_ok/default_param.er", 0)
Expand Down

0 comments on commit 9025fe7

Please sign in to comment.