Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a76381e

Browse files
committed
add(ir) tonumber with no base
1 parent 8cad327 commit a76381e

4 files changed

Lines changed: 102 additions & 52 deletions

File tree

lua_ir/src/builtin/mod.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,57 @@ fn dofile(env: &mut LuaEnv, args: usize, expected_ret: Option<usize>) -> Result<
128128
let func = LuaFunction::LuaFunc(func);
129129
env.function_call(0, func.into(), expected_ret)
130130
}
131-
fn tonumber(_env: &mut LuaEnv, _args: usize) -> Result<usize, RuntimeError> {
132-
unimplemented!("tonumber");
133-
}
134131
fn collectgarbage(_env: &mut LuaEnv, _args: usize) -> Result<usize, RuntimeError> {
135132
unimplemented!("collectgarbage");
136133
}
137134
fn xpcall(_env: &mut LuaEnv, _args: usize) -> Result<usize, RuntimeError> {
138135
unimplemented!("xpcall");
139136
}
137+
fn tonumber(env: &mut LuaEnv, args: usize) -> Result<usize, RuntimeError> {
138+
match args {
139+
0 => return Err(RuntimeError::new_empty_argument(1, "value")),
140+
1 => {
141+
let value = env.pop();
142+
let res = match value {
143+
LuaValue::Number(n) => LuaValue::Number(n),
144+
LuaValue::String(s) => LuaValue::Number(s.try_to_number()?),
145+
_ => LuaValue::Nil,
146+
};
147+
env.push(res);
148+
Ok(1)
149+
}
150+
_ => {
151+
env.pop_n(args - 2);
152+
let (value, base) = env.pop2();
153+
let base = match base {
154+
LuaValue::Number(n) => n.try_to_int()?,
155+
LuaValue::String(s) => s.try_to_number()?.try_to_int()?,
156+
_ => {
157+
return Err(RuntimeError::BadArgument(
158+
2,
159+
Box::new(RuntimeError::Expected("number", base.type_str().into())),
160+
))
161+
}
162+
};
163+
if base < 2 || base > 36 {
164+
return Err(RuntimeError::BadArgument(
165+
2,
166+
Box::new(RuntimeError::BaseOutOfRange),
167+
));
168+
}
169+
let _value = match value {
170+
LuaValue::String(s) => s,
171+
_ => {
172+
return Err(RuntimeError::BadArgument(
173+
1,
174+
Box::new(RuntimeError::Expected("string", value.type_str().into())),
175+
))
176+
}
177+
};
178+
unreachable!("tonumber with more than 1 argument");
179+
}
180+
}
181+
}
140182

141183
pub fn pcall(
142184
env: &mut LuaEnv,

lua_ir/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ pub enum RuntimeError {
4747

4848
TokenizeError(TokenizeError),
4949

50+
/// tonumber
51+
BaseOutOfRange,
52+
5053
// ========================
5154
/// not implemented yet (dummy error for some functions)
5255
Error,
@@ -119,6 +122,7 @@ impl<'a> std::fmt::Display for RuntimeErrorEnvPair<'a> {
119122
}
120123
RuntimeError::NoIntegerRepresentation => "number has no integer representation".fmt(f),
121124
RuntimeError::TokenizeError(err) => write!(f, "{}", err),
125+
RuntimeError::BaseOutOfRange => "base out of range".fmt(f),
122126

123127
RuntimeError::Custom(val) => write!(f, "{}", val),
124128
_ => write!(f, "{:?}", self.0),

lua_ir/src/luaval.rs

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -125,55 +125,7 @@ impl LuaValue {
125125
pub fn try_to_number(&self) -> Result<LuaNumber, RuntimeError> {
126126
match self {
127127
LuaValue::Number(n) => Ok(*n),
128-
LuaValue::String(s) => {
129-
// use `lua_tokenizer` to parse the string into a number
130-
let mut tokenizer = lua_tokenizer::Tokenizer::from_bytes(s.as_bytes());
131-
tokenizer.ignore_whitespace();
132-
// sign
133-
let neg = match tokenizer.peek() {
134-
Some(b'-') => {
135-
tokenizer.next();
136-
true
137-
}
138-
Some(b'+') => {
139-
tokenizer.next();
140-
false
141-
}
142-
_ => false,
143-
};
144-
// number
145-
let tokenize_res = tokenizer.tokenize_numeric();
146-
match tokenize_res {
147-
Ok(Some(res)) => {
148-
tokenizer.ignore_whitespace();
149-
if tokenizer.is_end() {
150-
match res.token_type {
151-
lua_tokenizer::TokenType::Numeric(numeric) => match numeric {
152-
lua_tokenizer::IntOrFloat::Int(i) => {
153-
if neg {
154-
Ok((-i).into())
155-
} else {
156-
Ok(i.into())
157-
}
158-
}
159-
lua_tokenizer::IntOrFloat::Float(f) => {
160-
if neg {
161-
Ok((-f).into())
162-
} else {
163-
Ok(f.into())
164-
}
165-
}
166-
},
167-
_ => Err(RuntimeError::Expected("number", Some("string"))),
168-
}
169-
} else {
170-
Err(RuntimeError::Expected("number", Some("string")))
171-
}
172-
}
173-
Ok(None) => Err(RuntimeError::Expected("number", Some("string"))),
174-
Err(tokenize_error) => Err(RuntimeError::TokenizeError(tokenize_error)),
175-
}
176-
}
128+
LuaValue::String(s) => s.try_to_number(),
177129
_ => Err(RuntimeError::Expected("number", Some(self.type_str()))),
178130
}
179131
}

lua_ir/src/string.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::{LuaNumber, RuntimeError};
2+
13
/// A Lua string, which can be stored on the heap, stack, or as a static reference, based on its length.
24
#[derive(Clone)]
35
pub enum LuaString {
@@ -79,6 +81,56 @@ impl LuaString {
7981
}
8082
}
8183
}
84+
85+
pub fn try_to_number(&self) -> Result<LuaNumber, RuntimeError> {
86+
// use `lua_tokenizer` to parse the string into a number
87+
let mut tokenizer = lua_tokenizer::Tokenizer::from_bytes(self.as_bytes());
88+
tokenizer.ignore_whitespace();
89+
// sign
90+
let neg = match tokenizer.peek() {
91+
Some(b'-') => {
92+
tokenizer.next();
93+
true
94+
}
95+
Some(b'+') => {
96+
tokenizer.next();
97+
false
98+
}
99+
_ => false,
100+
};
101+
// number
102+
let tokenize_res = tokenizer.tokenize_numeric();
103+
match tokenize_res {
104+
Ok(Some(res)) => {
105+
tokenizer.ignore_whitespace();
106+
if tokenizer.is_end() {
107+
match res.token_type {
108+
lua_tokenizer::TokenType::Numeric(numeric) => match numeric {
109+
lua_tokenizer::IntOrFloat::Int(i) => {
110+
if neg {
111+
Ok((-i).into())
112+
} else {
113+
Ok(i.into())
114+
}
115+
}
116+
lua_tokenizer::IntOrFloat::Float(f) => {
117+
if neg {
118+
Ok((-f).into())
119+
} else {
120+
Ok(f.into())
121+
}
122+
}
123+
},
124+
_ => Err(RuntimeError::Expected("number", Some("string"))),
125+
}
126+
} else {
127+
Err(RuntimeError::Expected("number", Some("string")))
128+
}
129+
}
130+
Ok(None) => Err(RuntimeError::Expected("number", Some("string"))),
131+
Err(tokenize_error) => Err(RuntimeError::TokenizeError(tokenize_error)),
132+
}
133+
}
82134
}
83135

84136
impl std::hash::Hash for LuaString {

0 commit comments

Comments
 (0)