Browse Source

Fix clippy warnings (#153)

* Fixed clippy warnings option_unwrap_used and result_unwrap_used.

* Fixed float_cmp clippy error and the option_unwrap_used it was hiding.

* Fixed shadowing issues.

* Disabled some clippy lints in tests.

* Fixed clippy string_add issues.

* Added allow else_if_without_else since an else-block would not make sense.

* Fixed integer arithmetic issues.

* Fixed all clippy get_unwrap issues.

* Fixed usage of unimplemented and an occurrence of variable name shadowing.

* Fixed indexing may panic issues.

* Fixed a slicing may panic issue.

* Changed some unnecessary uses of match that I introduced for expect.
pull/158/head
Mathias Peters 5 years ago committed by Jason Williams
parent
commit
f6467db21b
  1. 32
      src/lib/environment/declarative_environment_record.rs
  2. 32
      src/lib/environment/function_environment_record.rs
  3. 3
      src/lib/environment/global_environment_record.rs
  4. 18
      src/lib/environment/lexical_environment.rs
  5. 24
      src/lib/exec.rs
  6. 49
      src/lib/js/array.rs
  7. 1
      src/lib/js/boolean.rs
  8. 14
      src/lib/js/console.rs
  9. 6
      src/lib/js/function.rs
  10. 66
      src/lib/js/math.rs
  11. 6
      src/lib/js/regexp.rs
  12. 37
      src/lib/js/string.rs
  13. 14
      src/lib/js/value.rs
  14. 39
      src/lib/syntax/lexer.rs
  15. 19
      src/lib/syntax/parser.rs

32
src/lib/environment/declarative_environment_record.rs

@ -90,6 +90,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
} }
} }
#[allow(clippy::else_if_without_else)]
fn set_mutable_binding(&mut self, name: &str, value: Value, mut strict: bool) { fn set_mutable_binding(&mut self, name: &str, value: Value, mut strict: bool) {
if self.env_rec.get(name).is_none() { if self.env_rec.get(name).is_none() {
if strict { if strict {
@ -120,25 +121,30 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
} }
fn get_binding_value(&self, name: &str, _strict: bool) -> Value { fn get_binding_value(&self, name: &str, _strict: bool) -> Value {
if self.env_rec.get(name).is_some() && self.env_rec.get(name).unwrap().value.is_some() { match self.env_rec.get(name) {
let record: &DeclarativeEnvironmentRecordBinding = self.env_rec.get(name).unwrap(); Some(binding) => {
record.value.as_ref().unwrap().clone() binding.value.as_ref().expect("Could not get record as reference").clone()
} else { },
// TODO: change this when error handling comes into play None => {
panic!("ReferenceError: Cannot get binding value for {}", name); // TODO: change this when error handling comes into play
panic!("ReferenceError: Cannot get binding value for {}", name);
}
} }
} }
fn delete_binding(&mut self, name: &str) -> bool { fn delete_binding(&mut self, name: &str) -> bool {
if self.env_rec.get(name).is_some() { match self.env_rec.get(name) {
if self.env_rec.get(name).unwrap().can_delete { Some(binding) => {
self.env_rec.remove(name); if binding.can_delete {
true self.env_rec.remove(name);
} else { true
} else {
false
}
},
None => {
false false
} }
} else {
false
} }
} }

32
src/lib/environment/function_environment_record.rs

@ -147,6 +147,7 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
} }
} }
#[allow(clippy::else_if_without_else)]
fn set_mutable_binding(&mut self, name: &str, value: Value, mut strict: bool) { fn set_mutable_binding(&mut self, name: &str, value: Value, mut strict: bool) {
if self.env_rec.get(name).is_none() { if self.env_rec.get(name).is_none() {
if strict { if strict {
@ -178,25 +179,30 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
} }
fn get_binding_value(&self, name: &str, _strict: bool) -> Value { fn get_binding_value(&self, name: &str, _strict: bool) -> Value {
if self.env_rec.get(name).is_some() && self.env_rec.get(name).unwrap().value.is_some() { match self.env_rec.get(name) {
let record: &DeclarativeEnvironmentRecordBinding = self.env_rec.get(name).unwrap(); Some(binding) => {
record.value.as_ref().unwrap().clone() binding.value.as_ref().expect("Could not get record as reference").clone()
} else { },
// TODO: change this when error handling comes into play None => {
panic!("ReferenceError: Cannot get binding value for {}", name); // TODO: change this when error handling comes into play
panic!("ReferenceError: Cannot get binding value for {}", name);
}
} }
} }
fn delete_binding(&mut self, name: &str) -> bool { fn delete_binding(&mut self, name: &str) -> bool {
if self.env_rec.get(name).is_some() { match self.env_rec.get(name) {
if self.env_rec.get(name).unwrap().can_delete { Some(binding) => {
self.env_rec.remove(name); if binding.can_delete {
true self.env_rec.remove(name);
} else { true
} else {
false
}
},
None => {
false false
} }
} else {
false
} }
} }

3
src/lib/environment/global_environment_record.rs

@ -179,7 +179,8 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
} }
fn set_outer_environment(&mut self, _env: Environment) { fn set_outer_environment(&mut self, _env: Environment) {
unimplemented!(); // TODO: Implement
panic!("Not implemented yet")
} }
fn get_environment_type(&self) -> EnvironmentType { fn get_environment_type(&self) -> EnvironmentType {

18
src/lib/environment/lexical_environment.rs

@ -91,8 +91,8 @@ impl LexicalEnvironment {
} }
pub fn get_global_object(&self) -> Option<Value> { pub fn get_global_object(&self) -> Option<Value> {
let global = &self.environment_stack[0]; self.environment_stack.get(0).expect("").borrow().get_global_object()
global.borrow().get_global_object()
} }
pub fn create_mutable_binding(&mut self, name: String, deletion: bool) { pub fn create_mutable_binding(&mut self, name: String, deletion: bool) {
@ -120,16 +120,14 @@ impl LexicalEnvironment {
/// get_current_environment_ref is used when you only need to borrow the environment /// get_current_environment_ref is used when you only need to borrow the environment
/// (you only need to add a new variable binding, or you want to fetch a value) /// (you only need to add a new variable binding, or you want to fetch a value)
pub fn get_current_environment_ref(&self) -> &Environment { pub fn get_current_environment_ref(&self) -> &Environment {
&self let index = self.environment_stack.len().wrapping_sub(1);
.environment_stack &self.environment_stack.get(index).expect("Could not get current environment")
.get(self.environment_stack.len() - 1)
.unwrap()
} }
/// When neededing to clone an environment (linking it with another environnment) /// When neededing to clone an environment (linking it with another environnment)
/// cloning is more suited. The GC will remove the env once nothing is linking to it anymore /// cloning is more suited. The GC will remove the env once nothing is linking to it anymore
pub fn get_current_environment(&mut self) -> &mut Environment { pub fn get_current_environment(&mut self) -> &mut Environment {
self.environment_stack.back_mut().unwrap() self.environment_stack.back_mut().expect("Could not get mutable reference to back object")
} }
pub fn get_binding_value(&mut self, name: &str) -> Value { pub fn get_binding_value(&mut self, name: &str) -> Value {
@ -144,10 +142,10 @@ impl LexicalEnvironment {
if borrowed_env.get_outer_environment().is_some() { if borrowed_env.get_outer_environment().is_some() {
let mut outer: Option<Environment> = borrowed_env.get_outer_environment(); let mut outer: Option<Environment> = borrowed_env.get_outer_environment();
while outer.is_some() { while outer.is_some() {
if outer.as_ref().unwrap().borrow().has_binding(&name) { if outer.as_ref().expect("Could not get outer as reference").borrow().has_binding(&name) {
return outer.unwrap().borrow().get_binding_value(name, false); return outer.expect("Outer was None").borrow().get_binding_value(name, false);
} }
outer = outer.unwrap().borrow().get_outer_environment(); outer = outer.expect("Outer was None").borrow().get_outer_environment();
} }
} }

24
src/lib/exec.rs

@ -154,7 +154,7 @@ impl Executor for Interpreter {
let block = &tup.1; let block = &tup.1;
if val == self.run(cond)? { if val == self.run(cond)? {
matched = true; matched = true;
let last_expr = block.last().unwrap(); let last_expr = block.last().expect("Block has no expressions");
for expr in block.iter() { for expr in block.iter() {
let e_result = self.run(expr)?; let e_result = self.run(expr)?;
if expr == last_expr { if expr == last_expr {
@ -164,12 +164,12 @@ impl Executor for Interpreter {
} }
} }
if !matched && default.is_some() { if !matched && default.is_some() {
result = self.run(default.as_ref().unwrap())?; result = self.run(default.as_ref().expect("Could not get default as reference"))?;
} }
Ok(result) Ok(result)
} }
ExprDef::ObjectDecl(ref map) => { ExprDef::ObjectDecl(ref map) => {
let global_val = &self.realm.environment.get_global_object().unwrap(); let global_val = &self.realm.environment.get_global_object().expect("Could not get the global object");
let obj = ValueData::new_obj(Some(global_val)); let obj = ValueData::new_obj(Some(global_val));
for (key, val) in map.iter() { for (key, val) in map.iter() {
obj.borrow().set_field(key.clone(), self.run(val)?); obj.borrow().set_field(key.clone(), self.run(val)?);
@ -177,7 +177,7 @@ impl Executor for Interpreter {
Ok(obj) Ok(obj)
} }
ExprDef::ArrayDecl(ref arr) => { ExprDef::ArrayDecl(ref arr) => {
let global_val = &self.realm.environment.get_global_object().unwrap(); let global_val = &self.realm.environment.get_global_object().expect("Could not get the global object");
let arr_map = ValueData::new_obj(Some(global_val)); let arr_map = ValueData::new_obj(Some(global_val));
// Note that this object is an Array // Note that this object is an Array
arr_map.set_kind(ObjectKind::Array); arr_map.set_kind(ObjectKind::Array);
@ -205,10 +205,10 @@ impl Executor for Interpreter {
if name.is_some() { if name.is_some() {
self.realm self.realm
.environment .environment
.create_mutable_binding(name.clone().unwrap(), false); .create_mutable_binding(name.clone().expect("No name was supplied"), false);
self.realm self.realm
.environment .environment
.initialize_binding(name.as_ref().unwrap(), val.clone()) .initialize_binding(name.as_ref().expect("Could not get name as reference"), val.clone())
} }
Ok(val) Ok(val)
} }
@ -277,8 +277,8 @@ impl Executor for Interpreter {
})) }))
} }
ExprDef::BinOp(BinOp::Log(ref op), ref a, ref b) => { ExprDef::BinOp(BinOp::Log(ref op), ref a, ref b) => {
let v_a = from_value::<bool>(self.run(a)?).unwrap(); let v_a = from_value::<bool>(self.run(a)?).expect("Could not convert JS value to bool");
let v_b = from_value::<bool>(self.run(b)?).unwrap(); let v_b = from_value::<bool>(self.run(b)?).expect("Could not convert JS value to bool");
Ok(match *op { Ok(match *op {
LogOp::And => to_value(v_a && v_b), LogOp::And => to_value(v_a && v_b),
LogOp::Or => to_value(v_a || v_b), LogOp::Or => to_value(v_a || v_b),
@ -338,8 +338,8 @@ impl Executor for Interpreter {
)); ));
for i in 0..data.args.len() { for i in 0..data.args.len() {
let name = data.args.get(i).unwrap(); let name = data.args.get(i).expect("Could not get data argument");
let expr = v_args.get(i).unwrap(); let expr = v_args.get(i).expect("Could not get argument");
env.create_mutable_binding(name.clone(), false); env.create_mutable_binding(name.clone(), false);
env.initialize_binding(name, expr.to_owned()); env.initialize_binding(name, expr.to_owned());
} }
@ -468,8 +468,8 @@ impl Interpreter {
Some(env.get_current_environment_ref().clone()), Some(env.get_current_environment_ref().clone()),
)); ));
for i in 0..data.args.len() { for i in 0..data.args.len() {
let name = data.args.get(i).unwrap(); let name = data.args.get(i).expect("Could not get data argument");
let expr: &Value = arguments_list.get(i).unwrap(); let expr: &Value = arguments_list.get(i).expect("Could not get argument");
self.realm self.realm
.environment .environment
.create_mutable_binding(name.clone(), false); .create_mutable_binding(name.clone(), false);

49
src/lib/js/array.rs

@ -35,11 +35,11 @@ fn add_to_array_object(array_ptr: &Value, add_values: &[Value]) -> ResultValue {
from_value(array_ptr.get_field_slice("length")).expect("failed to conveert lenth to i32"); from_value(array_ptr.get_field_slice("length")).expect("failed to conveert lenth to i32");
for (n, value) in add_values.iter().enumerate() { for (n, value) in add_values.iter().enumerate() {
let new_index = orig_length + (n as i32); let new_index = orig_length.wrapping_add(n as i32);
array_ptr.set_field(new_index.to_string(), value.clone()); array_ptr.set_field(new_index.to_string(), value.clone());
} }
array_ptr.set_field_slice("length", to_value(orig_length + add_values.len() as i32)); array_ptr.set_field_slice("length", to_value(orig_length.wrapping_add(add_values.len() as i32)));
Ok(array_ptr.clone()) Ok(array_ptr.clone())
} }
@ -55,8 +55,8 @@ pub fn make_array(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultVa
match args.len() { match args.len() {
0 => construct_array(this, &[]), 0 => construct_array(this, &[]),
1 => { 1 => {
let array = construct_array(this, &[]).unwrap(); let array = construct_array(this, &[]).expect("Could not construct array");
let size: i32 = from_value(args[0].clone()).unwrap(); let size: i32 = from_value(args.get(0).expect("Could not get argument").clone()).expect("Could not convert argument to i32");
array.set_field_slice("length", to_value(size)); array.set_field_slice("length", to_value(size));
Ok(array) Ok(array)
} }
@ -87,13 +87,13 @@ pub fn concat(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue
// one) // one)
let mut new_values: Vec<Value> = Vec::new(); let mut new_values: Vec<Value> = Vec::new();
let this_length: i32 = from_value(this.get_field_slice("length")).unwrap(); let this_length: i32 = from_value(this.get_field_slice("length")).expect("Could not convert argument to i32");
for n in 0..this_length { for n in 0..this_length {
new_values.push(this.get_field(&n.to_string())); new_values.push(this.get_field(&n.to_string()));
} }
for concat_array in args { for concat_array in args {
let concat_length: i32 = from_value(concat_array.get_field_slice("length")).unwrap(); let concat_length: i32 = from_value(concat_array.get_field_slice("length")).expect("Could not convert argument to i32");
for n in 0..concat_length { for n in 0..concat_length {
new_values.push(concat_array.get_field(&n.to_string())); new_values.push(concat_array.get_field(&n.to_string()));
} }
@ -118,13 +118,13 @@ pub fn push(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
/// The last element of the array is removed from the array and returned. /// The last element of the array is removed from the array and returned.
/// <https://tc39.es/ecma262/#sec-array.prototype.pop> /// <https://tc39.es/ecma262/#sec-array.prototype.pop>
pub fn pop(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { pub fn pop(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let curr_length: i32 = from_value(this.get_field_slice("length")).unwrap(); let curr_length: i32 = from_value(this.get_field_slice("length")).expect("Could not convert argument to i32");
if curr_length < 1 { if curr_length < 1 {
return Err(to_value( return Err(to_value(
"Cannot pop() on an array with zero length".to_string(), "Cannot pop() on an array with zero length".to_string(),
)); ));
} }
let pop_index = curr_length - 1; let pop_index = curr_length.wrapping_sub(1);
let pop_value: Value = this.get_field(&pop_index.to_string()); let pop_value: Value = this.get_field(&pop_index.to_string());
this.remove_prop(&pop_index.to_string()); this.remove_prop(&pop_index.to_string());
this.set_field_slice("length", to_value(pop_index)); this.set_field_slice("length", to_value(pop_index));
@ -141,11 +141,11 @@ pub fn join(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
let separator = if args.is_empty() { let separator = if args.is_empty() {
String::from(",") String::from(",")
} else { } else {
args[0].to_string() args.get(0).expect("Could not get argument").to_string()
}; };
let mut elem_strs: Vec<String> = Vec::new(); let mut elem_strs: Vec<String> = Vec::new();
let length: i32 = from_value(this.get_field_slice("length")).unwrap(); let length: i32 = from_value(this.get_field_slice("length")).expect("Could not convert argument to i32");
for n in 0..length { for n in 0..length {
let elem_str: String = this.get_field(&n.to_string()).to_string(); let elem_str: String = this.get_field(&n.to_string()).to_string();
elem_strs.push(elem_str); elem_strs.push(elem_str);
@ -159,12 +159,13 @@ pub fn join(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
/// The elements of the array are rearranged so as to reverse their order. /// The elements of the array are rearranged so as to reverse their order.
/// The object is returned as the result of the call. /// The object is returned as the result of the call.
/// <https://tc39.es/ecma262/#sec-array.prototype.reverse/> /// <https://tc39.es/ecma262/#sec-array.prototype.reverse/>
#[allow(clippy::else_if_without_else)]
pub fn reverse(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { pub fn reverse(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let len: i32 = from_value(this.get_field_slice("length")).unwrap(); let len: i32 = from_value(this.get_field_slice("length")).expect("Could not convert argument to i32");
let middle: i32 = len / 2; let middle: i32 = len.wrapping_div(2);
for lower in 0..middle { for lower in 0..middle {
let upper = len - lower - 1; let upper = len.wrapping_sub(lower).wrapping_sub(1);
let upper_exists = this.has_field(&upper.to_string()); let upper_exists = this.has_field(&upper.to_string());
let lower_exists = this.has_field(&lower.to_string()); let lower_exists = this.has_field(&lower.to_string());
@ -192,7 +193,7 @@ pub fn reverse(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
/// The first element of the array is removed from the array and returned. /// The first element of the array is removed from the array and returned.
/// <https://tc39.es/ecma262/#sec-array.prototype.shift/> /// <https://tc39.es/ecma262/#sec-array.prototype.shift/>
pub fn shift(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { pub fn shift(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let len: i32 = from_value(this.get_field_slice("length")).unwrap(); let len: i32 = from_value(this.get_field_slice("length")).expect("Could not convert argument to i32");
if len == 0 { if len == 0 {
this.set_field_slice("length", to_value(0_i32)); this.set_field_slice("length", to_value(0_i32));
@ -204,7 +205,7 @@ pub fn shift(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
for k in 1..len { for k in 1..len {
let from = k.to_string(); let from = k.to_string();
let to = (k - 1).to_string(); let to = (k.wrapping_sub(1)).to_string();
let from_value = this.get_field(&from); let from_value = this.get_field(&from);
if from_value == Gc::new(ValueData::Undefined) { if from_value == Gc::new(ValueData::Undefined) {
@ -214,8 +215,9 @@ pub fn shift(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
} }
} }
this.remove_prop(&(len - 1).to_string()); let final_index = len.wrapping_sub(1);
this.set_field_slice("length", to_value(len - 1)); this.remove_prop(&(final_index).to_string());
this.set_field_slice("length", to_value(final_index));
Ok(first) Ok(first)
} }
@ -227,13 +229,13 @@ pub fn shift(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
/// argument list. /// argument list.
/// <https://tc39.es/ecma262/#sec-array.prototype.unshift/> /// <https://tc39.es/ecma262/#sec-array.prototype.unshift/>
pub fn unshift(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub fn unshift(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
let len: i32 = from_value(this.get_field_slice("length")).unwrap(); let len: i32 = from_value(this.get_field_slice("length")).expect("Could not convert argument to i32");
let arg_c: i32 = args.len() as i32; let arg_c: i32 = args.len() as i32;
if arg_c > 0 { if arg_c > 0 {
for k in (1..=len).rev() { for k in (1..=len).rev() {
let from = (k - 1).to_string(); let from = (k.wrapping_sub(1)).to_string();
let to = (k + arg_c - 1).to_string(); let to = (k.wrapping_add(arg_c).wrapping_sub(1)).to_string();
let from_value = this.get_field(&from); let from_value = this.get_field(&from);
if from_value == Gc::new(ValueData::Undefined) { if from_value == Gc::new(ValueData::Undefined) {
@ -243,12 +245,13 @@ pub fn unshift(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue
} }
} }
for j in 0..arg_c { for j in 0..arg_c {
this.set_field_slice(&j.to_string(), args[j as usize].clone()); this.set_field_slice(&j.to_string(), args.get(j as usize).expect("Could not get argument").clone());
} }
} }
this.set_field_slice("length", to_value(len + arg_c)); let temp = len.wrapping_add(arg_c);
Ok(to_value(len + arg_c)) this.set_field_slice("length", to_value(temp));
Ok(to_value(temp))
} }
/// Create a new `Array` object /// Create a new `Array` object

1
src/lib/js/boolean.rs

@ -101,6 +101,7 @@ mod tests {
assert_eq!(boolean_constructor.is_function(), true); assert_eq!(boolean_constructor.is_function(), true);
} }
#[allow(clippy::result_unwrap_used)]
#[test] #[test]
/// Test the correct type is returned from call and construct /// Test the correct type is returned from call and construct
fn construct_and_call() { fn construct_and_call() {

14
src/lib/js/console.rs

@ -41,10 +41,10 @@ fn log_string_from(x: Value) -> String {
.unwrap() .unwrap()
.value .value
.clone() .clone()
.unwrap() .expect("Could not borrow value")
.clone(), .clone(),
) )
.unwrap(); .expect("Could not convert JS value to i32");
for i in 0..len { for i in 0..len {
// Introduce recursive call to stringify any objects // Introduce recursive call to stringify any objects
// which are part of the Array // which are part of the Array
@ -55,11 +55,11 @@ fn log_string_from(x: Value) -> String {
.unwrap() .unwrap()
.value .value
.clone() .clone()
.unwrap() .expect("Could not borrow value")
.clone(), .clone(),
); );
write!(s, "{}", arr_str).unwrap(); write!(s, "{}", arr_str).unwrap();
if i != len - 1 { if i != len.wrapping_sub(1) {
write!(s, ", ").unwrap(); write!(s, ", ").unwrap();
} }
} }
@ -79,7 +79,7 @@ fn log_string_from(x: Value) -> String {
s, s,
"{}: {}", "{}: {}",
key, key,
log_string_from(val.value.clone().unwrap().clone()) log_string_from(val.value.clone().expect("Could not read value").clone())
) )
.unwrap(); .unwrap();
if key != last_key { if key != last_key {
@ -93,7 +93,7 @@ fn log_string_from(x: Value) -> String {
s s
} }
_ => from_value::<String>(x.clone()).unwrap(), _ => from_value::<String>(x.clone()).expect("Could not convert value to String"),
} }
} }
@ -113,7 +113,7 @@ pub fn log(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
pub fn error(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub fn error(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
let args: Vec<String> = FromIterator::from_iter( let args: Vec<String> = FromIterator::from_iter(
args.iter() args.iter()
.map(|x| from_value::<String>(x.clone()).unwrap()), .map(|x| from_value::<String>(x.clone()).expect("Could not convert value to String")),
); );
println!("{}", args.join(" ")); println!("{}", args.join(" "));
Ok(Gc::new(ValueData::Undefined)) Ok(Gc::new(ValueData::Undefined))

6
src/lib/js/function.rs

@ -115,7 +115,7 @@ pub fn create_unmapped_arguments_object(arguments_list: Vec<Value>) -> Value {
obj.define_own_property("length".to_string(), length); obj.define_own_property("length".to_string(), length);
let mut index: usize = 0; let mut index: usize = 0;
while index < len { while index < len {
let val = arguments_list.get(index).unwrap(); let val = arguments_list.get(index).expect("Could not get argument");
let mut prop = Property::default(); let mut prop = Property::default();
prop = prop prop = prop
.value(val.clone()) .value(val.clone())
@ -136,6 +136,7 @@ mod tests {
use crate::realm::Realm; use crate::realm::Realm;
use crate::{forward, forward_val, js::value::from_value}; use crate::{forward, forward_val, js::value::from_value};
#[allow(clippy::float_cmp)]
#[test] #[test]
fn check_arguments_object() { fn check_arguments_object() {
let realm = Realm::create(); let realm = Realm::create();
@ -148,8 +149,9 @@ mod tests {
"#; "#;
forward(&mut engine, init); forward(&mut engine, init);
let expected_return_val: f64 = 100.0;
let return_val = forward_val(&mut engine, "val").expect("value expected"); let return_val = forward_val(&mut engine, "val").expect("value expected");
assert_eq!(return_val.is_double(), true); assert_eq!(return_val.is_double(), true);
assert_eq!(from_value::<f64>(return_val).unwrap(), 100.0); assert_eq!(from_value::<f64>(return_val).expect("Could not convert value to f64"), expected_return_val);
} }
} }

66
src/lib/js/math.rs

@ -13,8 +13,8 @@ pub fn abs(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.abs() .abs()
})) }))
} }
@ -23,8 +23,8 @@ pub fn acos(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.acos() .acos()
})) }))
} }
@ -33,8 +33,8 @@ pub fn asin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.asin() .asin()
})) }))
} }
@ -43,8 +43,8 @@ pub fn atan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.atan() .atan()
})) }))
} }
@ -53,9 +53,9 @@ pub fn atan2(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.atan2(args.get(1).unwrap().to_num()) .atan2(args.get(1).expect("Could not get argument").to_num())
})) }))
} }
/// Get the cubic root of a number /// Get the cubic root of a number
@ -63,8 +63,8 @@ pub fn cbrt(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.cbrt() .cbrt()
})) }))
} }
@ -73,8 +73,8 @@ pub fn ceil(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.ceil() .ceil()
})) }))
} }
@ -83,8 +83,8 @@ pub fn cos(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.cos() .cos()
})) }))
} }
@ -93,8 +93,8 @@ pub fn exp(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.exp() .exp()
})) }))
} }
@ -103,8 +103,8 @@ pub fn floor(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.floor() .floor()
})) }))
} }
@ -113,8 +113,8 @@ pub fn log(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.log(f64::consts::E) .log(f64::consts::E)
})) }))
} }
@ -139,8 +139,8 @@ pub fn min(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
/// Raise a number to a power /// Raise a number to a power
pub fn pow(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub fn pow(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.len() >= 2 { Ok(to_value(if args.len() >= 2 {
let num: f64 = from_value(args.get(0).unwrap().clone()).unwrap(); let num: f64 = from_value(args.get(0).expect("Could not get argument").clone()).expect("Could not convert argument to f64");
let power: f64 = from_value(args.get(1).unwrap().clone()).unwrap(); let power: f64 = from_value(args.get(1).expect("Could not get argument").clone()).expect("Could not convert argument to f64");
num.powf(power) num.powf(power)
} else { } else {
f64::NAN f64::NAN
@ -155,8 +155,8 @@ pub fn round(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.round() .round()
})) }))
} }
@ -165,8 +165,8 @@ pub fn sin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.sin() .sin()
})) }))
} }
@ -175,8 +175,8 @@ pub fn sqrt(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.sqrt() .sqrt()
})) }))
} }
@ -185,8 +185,8 @@ pub fn tan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() { Ok(to_value(if args.is_empty() {
f64::NAN f64::NAN
} else { } else {
from_value::<f64>(args.get(0).unwrap().clone()) from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.unwrap() .expect("Could not convert argument to f64")
.tan() .tan()
})) }))
} }

6
src/lib/js/regexp.rs

@ -62,10 +62,10 @@ pub fn make_regexp(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultV
if slots.get("RegExpMatcher").is_some() { if slots.get("RegExpMatcher").is_some() {
// first argument is another `RegExp` object, so copy its pattern and flags // first argument is another `RegExp` object, so copy its pattern and flags
if let Some(body) = slots.get("OriginalSource") { if let Some(body) = slots.get("OriginalSource") {
regex_body = from_value(body.clone()).unwrap(); regex_body = from_value(body.clone()).expect("Could not convert value to String");
} }
if let Some(flags) = slots.get("OriginalFlags") { if let Some(flags) = slots.get("OriginalFlags") {
regex_flags = from_value(flags.clone()).unwrap(); regex_flags = from_value(flags.clone()).expect("Could not convert value to String");
} }
} }
} }
@ -227,7 +227,7 @@ pub fn exec(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
let mut result = Vec::with_capacity(locations.len()); let mut result = Vec::with_capacity(locations.len());
for i in 0..locations.len() { for i in 0..locations.len() {
if let Some((start, end)) = locations.get(i) { if let Some((start, end)) = locations.get(i) {
result.push(to_value(&arg_str[start..end])); result.push(to_value(arg_str.get(start..end).expect("Could not get slice")));
} else { } else {
result.push(Gc::new(ValueData::Undefined)); result.push(Gc::new(ValueData::Undefined));
} }

37
src/lib/js/string.rs

@ -199,11 +199,11 @@ pub fn slice(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue
min(end, length) min(end, length)
}; };
let span = max(to - from, 0); let span = max(to.wrapping_sub(from), 0);
let mut new_str = String::new(); let mut new_str = String::new();
for i in from..from + span { for i in from..from.wrapping_add(span) {
new_str.push(primitive_val.chars().nth(i as usize).unwrap()); new_str.push(primitive_val.chars().nth(i as usize).expect("Could not get nth char"));
} }
Ok(to_value(new_str)) Ok(to_value(new_str))
} }
@ -272,11 +272,11 @@ pub fn ends_with(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultV
let end_position: i32 = if args.len() < 2 { let end_position: i32 = if args.len() < 2 {
length length
} else { } else {
from_value(args[1].clone()).unwrap() from_value(args.get(1).expect("Could not get argumetn").clone()).expect("Could not convert value to i32")
}; };
let end = min(max(end_position, 0), length); let end = min(max(end_position, 0), length);
let start = end - search_length; let start = end.wrapping_sub(search_length);
if start < 0 { if start < 0 {
Ok(to_value(false)) Ok(to_value(false))
@ -311,7 +311,7 @@ pub fn includes(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultVa
let position: i32 = if args.len() < 2 { let position: i32 = if args.len() < 2 {
0 0
} else { } else {
from_value(args[1].clone()).unwrap() from_value(args.get(1).expect("Could not get argument").clone()).expect("Could not convert value to i32")
}; };
let start = min(max(position, 0), length); let start = min(max(position, 0), length);
@ -347,7 +347,7 @@ pub fn index_of(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultVa
let position: i32 = if args.len() < 2 { let position: i32 = if args.len() < 2 {
0 0
} else { } else {
from_value(args[1].clone()).unwrap() from_value(args.get(1).expect("Could not get argument").clone()).expect("Could not convert value to i32")
}; };
let start = min(max(position, 0), length); let start = min(max(position, 0), length);
@ -392,7 +392,7 @@ pub fn last_index_of(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Res
let position: i32 = if args.len() < 2 { let position: i32 = if args.len() < 2 {
0 0
} else { } else {
from_value(args[1].clone()).unwrap() from_value(args.get(1).expect("Could not get argument").clone()).expect("Could not convert value to i32")
}; };
let start = min(max(position, 0), length); let start = min(max(position, 0), length);
@ -437,7 +437,7 @@ fn string_pad(
return Ok(to_value(primitive)); return Ok(to_value(primitive));
} }
let fill_len = max_length - primitive_length; let fill_len = max_length.wrapping_sub(primitive_length);
let mut fill_str = String::new(); let mut fill_str = String::new();
while fill_str.len() < fill_len as usize { while fill_str.len() < fill_len as usize {
@ -447,9 +447,9 @@ fn string_pad(
let concat_fill_str: String = fill_str.chars().take(fill_len as usize).collect(); let concat_fill_str: String = fill_str.chars().take(fill_len as usize).collect();
if at_start { if at_start {
Ok(to_value(concat_fill_str + &primitive)) Ok(to_value(format!("{}{}", concat_fill_str, &primitive)))
} else { } else {
Ok(to_value(primitive + &concat_fill_str)) Ok(to_value(format!("{}{}", primitive, &concat_fill_str)))
} }
} }
@ -471,7 +471,7 @@ pub fn pad_end(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultVal
.expect("failed to parse argument for String method"); .expect("failed to parse argument for String method");
let fill_string: Option<String> = match args.len() { let fill_string: Option<String> = match args.len() {
1 => None, 1 => None,
_ => Some(from_value(args[1].clone()).unwrap()), _ => Some(from_value(args.get(1).expect("Could not get argument").clone()).expect("Could not convert value to Option<String>")),
}; };
string_pad(primitive_val, max_length, fill_string, false) string_pad(primitive_val, max_length, fill_string, false)
@ -495,7 +495,7 @@ pub fn pad_start(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultV
.expect("failed to parse argument for String method"); .expect("failed to parse argument for String method");
let fill_string: Option<String> = match args.len() { let fill_string: Option<String> = match args.len() {
1 => None, 1 => None,
_ => Some(from_value(args[1].clone()).unwrap()), _ => Some(from_value(args.get(1).expect("Could not get argument").clone()).expect("Could not convert value to Option<String>")),
}; };
string_pad(primitive_val, max_length, fill_string, true) string_pad(primitive_val, max_length, fill_string, true)
@ -587,7 +587,7 @@ pub fn substring(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultV
let end = if args.len() < 2 { let end = if args.len() < 2 {
length length
} else { } else {
from_value(args[1].clone()).expect("failed to parse argument for String method") from_value(args.get(1).expect("Could not get argument").clone()).expect("failed to parse argument for String method")
}; };
// Both start and end args replaced by 0 if they were negative // Both start and end args replaced by 0 if they were negative
// or by the length of the String if they were greater // or by the length of the String if they were greater
@ -598,7 +598,7 @@ pub fn substring(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultV
let to = max(final_start, final_end) as usize; let to = max(final_start, final_end) as usize;
// Extract the part of the string contained between the start index and the end index // Extract the part of the string contained between the start index and the end index
// where start is guaranteed to be smaller or equals to end // where start is guaranteed to be smaller or equals to end
let extracted_string: String = primitive_val.chars().skip(from).take(to - from).collect(); let extracted_string: String = primitive_val.chars().skip(from).take(to.wrapping_sub(from)).collect();
Ok(to_value(extracted_string)) Ok(to_value(extracted_string))
} }
@ -631,15 +631,15 @@ pub fn substr(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValu
let end = if args.len() < 2 { let end = if args.len() < 2 {
i32::max_value() i32::max_value()
} else { } else {
from_value(args[1].clone()).expect("failed to parse argument for String method") from_value(args.get(1).expect("Could not get argument").clone()).expect("failed to parse argument for String method")
}; };
// If start is negative it become the number of code units from the end of the string // If start is negative it become the number of code units from the end of the string
if start < 0 { if start < 0 {
start = max(length + start, 0); start = max(length.wrapping_add(start), 0);
} }
// length replaced by 0 if it was negative // length replaced by 0 if it was negative
// or by the number of code units from start to the end of the string if it was greater // or by the number of code units from start to the end of the string if it was greater
let result_length = min(max(end, 0), length - start); let result_length = min(max(end, 0), length.wrapping_sub(start));
// If length is negative we return an empty string // If length is negative we return an empty string
// otherwise we extract the part of the string from start and is length code units long // otherwise we extract the part of the string from start and is length code units long
if result_length <= 0 { if result_length <= 0 {
@ -765,6 +765,7 @@ mod tests {
//assert_eq!(b, String::from("Hello, world! Have a nice day.")); //assert_eq!(b, String::from("Hello, world! Have a nice day."));
} }
#[allow(clippy::result_unwrap_used)]
#[test] #[test]
/// Test the correct type is returned from call and construct /// Test the correct type is returned from call and construct
fn construct_and_call() { fn construct_and_call() {

14
src/lib/js/value.rs

@ -307,7 +307,7 @@ impl ValueData {
match prop_getter { match prop_getter {
Some(val) => val, Some(val) => val,
None => { None => {
let val = prop.value.as_ref().unwrap(); let val = prop.value.as_ref().expect("Could not get property as reference");
val.clone() val.clone()
} }
} }
@ -481,7 +481,7 @@ impl ValueData {
/// Convert from a JSON value to a JS value /// Convert from a JSON value to a JS value
pub fn from_json(json: JSONValue) -> Self { pub fn from_json(json: JSONValue) -> Self {
match json { match json {
JSONValue::Number(v) => ValueData::Number(v.as_f64().unwrap()), JSONValue::Number(v) => ValueData::Number(v.as_f64().expect("Could not convert value to f64")),
JSONValue::String(v) => ValueData::String(v), JSONValue::String(v) => ValueData::String(v),
JSONValue::Bool(v) => ValueData::Boolean(v), JSONValue::Bool(v) => ValueData::Boolean(v),
JSONValue::Array(vs) => { JSONValue::Array(vs) => {
@ -527,7 +527,7 @@ impl ValueData {
JSONValue::Object(new_obj) JSONValue::Object(new_obj)
} }
ValueData::String(ref str) => JSONValue::String(str.clone()), ValueData::String(ref str) => JSONValue::String(str.clone()),
ValueData::Number(num) => JSONValue::Number(JSONNumber::from_f64(num).unwrap()), ValueData::Number(num) => JSONValue::Number(JSONNumber::from_f64(num).expect("Could not convert to JSONNumber")),
ValueData::Integer(val) => JSONValue::Number(JSONNumber::from(val)), ValueData::Integer(val) => JSONValue::Number(JSONNumber::from(val)),
} }
} }
@ -619,8 +619,8 @@ impl Add for ValueData {
type Output = Self; type Output = Self;
fn add(self, other: Self) -> Self { fn add(self, other: Self) -> Self {
match (self, other) { match (self, other) {
(ValueData::String(ref s), ref o) => ValueData::String(s.clone() + &o.to_string()), (ValueData::String(ref s), ref o) => ValueData::String(format!("{}{}", s.clone(), &o.to_string())),
(ref s, ValueData::String(ref o)) => ValueData::String(s.to_string() + o), (ref s, ValueData::String(ref o)) => ValueData::String(format!("{}{}", s.to_string(), o)),
(ref s, ref o) => ValueData::Number(s.to_num() + o.to_num()), (ref s, ref o) => ValueData::Number(s.to_num() + o.to_num()),
} }
} }
@ -725,7 +725,7 @@ impl FromValue for String {
impl<'s> ToValue for &'s str { impl<'s> ToValue for &'s str {
fn to_value(&self) -> Value { fn to_value(&self) -> Value {
Gc::new(ValueData::String(String::from_str(*self).unwrap())) Gc::new(ValueData::String(String::from_str(*self).expect("Could not convert string to self to String")))
} }
} }
@ -736,7 +736,7 @@ impl ToValue for char {
} }
impl FromValue for char { impl FromValue for char {
fn from_value(v: Value) -> Result<Self, &'static str> { fn from_value(v: Value) -> Result<Self, &'static str> {
Ok(v.to_string().chars().next().unwrap()) Ok(v.to_string().chars().next().expect("Could not get next char"))
} }
} }

39
src/lib/syntax/lexer.rs

@ -180,7 +180,7 @@ impl<'a> Lexer<'a> {
F: FnMut(char) -> bool, F: FnMut(char) -> bool,
{ {
let mut s = String::new(); let mut s = String::new();
while self.buffer.peek().is_some() && f(self.preview_next().unwrap()) { while self.buffer.peek().is_some() && f(self.preview_next().expect("Could not preview next value")) {
s.push(self.next()?); s.push(self.next()?);
} }
@ -253,7 +253,7 @@ impl<'a> Lexer<'a> {
if self.next_is('{') { if self.next_is('{') {
let s = self let s = self
.take_char_while(char::is_alphanumeric) .take_char_while(char::is_alphanumeric)
.unwrap(); .expect("Could not read chars");
// We know this is a single unicode codepoint, convert to u32 // We know this is a single unicode codepoint, convert to u32
let as_num = match u32::from_str_radix(&s, 16) { let as_num = match u32::from_str_radix(&s, 16) {
@ -264,7 +264,7 @@ impl<'a> Lexer<'a> {
.expect("Invalid Unicode escape sequence"); .expect("Invalid Unicode escape sequence");
self.next()?; // '}' self.next()?; // '}'
self.column_number += s.len() as u64 + 3; self.column_number += (s.len() as u64).wrapping_add(3);
c c
} else { } else {
let mut codepoints: Vec<u16> = vec![]; let mut codepoints: Vec<u16> = vec![];
@ -272,7 +272,7 @@ impl<'a> Lexer<'a> {
// Collect each character after \u e.g \uD83D will give "D83D" // Collect each character after \u e.g \uD83D will give "D83D"
let s = self let s = self
.take_char_while(char::is_alphanumeric) .take_char_while(char::is_alphanumeric)
.unwrap(); .expect("Could not read chars");
// Convert to u16 // Convert to u16
let as_num = match u16::from_str_radix(&s, 16) { let as_num = match u16::from_str_radix(&s, 16) {
@ -281,7 +281,7 @@ impl<'a> Lexer<'a> {
}; };
codepoints.push(as_num); codepoints.push(as_num);
self.column_number += s.len() as u64 + 2; self.column_number += (s.len() as u64).wrapping_add(2);
// Check for another UTF-16 codepoint // Check for another UTF-16 codepoint
if self.next_is('\\') && self.next_is('u') { if self.next_is('\\') && self.next_is('u') {
@ -294,8 +294,8 @@ impl<'a> Lexer<'a> {
// Rust's decode_utf16 will deal with it regardless // Rust's decode_utf16 will deal with it regardless
decode_utf16(codepoints.iter().cloned()) decode_utf16(codepoints.iter().cloned())
.next() .next()
.unwrap() .expect("Could not get next codepoint")
.unwrap() .expect("Could not get next codepoint")
} }
} }
'\'' | '"' | '\\' => escape, '\'' | '"' | '\\' => escape,
@ -315,7 +315,7 @@ impl<'a> Lexer<'a> {
// Why +1? Quotation marks are not included, // Why +1? Quotation marks are not included,
// So technically it would be +2, (for both " ") but we want to be 1 less // So technically it would be +2, (for both " ") but we want to be 1 less
// to compensate for the incrementing at the top // to compensate for the incrementing at the top
self.column_number += str_length + 1; self.column_number += str_length.wrapping_add(1);
} }
'0' => { '0' => {
let mut buf = String::new(); let mut buf = String::new();
@ -327,7 +327,7 @@ impl<'a> Lexer<'a> {
break; break;
} }
} }
u64::from_str_radix(&buf, 16).unwrap() u64::from_str_radix(&buf, 16).expect("Could not convert value to u64")
} else if self.next_is('b') { } else if self.next_is('b') {
while let Some(ch) = self.preview_next() { while let Some(ch) = self.preview_next() {
if ch.is_digit(2) { if ch.is_digit(2) {
@ -336,14 +336,14 @@ impl<'a> Lexer<'a> {
break; break;
} }
} }
u64::from_str_radix(&buf, 2).unwrap() u64::from_str_radix(&buf, 2).expect("Could not convert value to u64")
} else { } else {
let mut gone_decimal = false; let mut gone_decimal = false;
loop { loop {
let next_ch = self.preview_next().unwrap_or('_'); let next_ch = self.preview_next().unwrap_or('_');
match next_ch { match next_ch {
next_ch if next_ch.is_digit(8) => { c if next_ch.is_digit(8) => {
buf.push(next_ch); buf.push(c);
self.next()?; self.next()?;
} }
'O' | 'o' => { 'O' | 'o' => {
@ -358,11 +358,11 @@ impl<'a> Lexer<'a> {
} }
} }
if gone_decimal { if gone_decimal {
u64::from_str(&buf).unwrap() u64::from_str(&buf).expect("Could not convert value to u64r")
} else if buf.is_empty() { } else if buf.is_empty() {
0 0
} else { } else {
u64::from_str_radix(&buf, 8).unwrap() u64::from_str_radix(&buf, 8).expect("Could not convert value to u64")
} }
}; };
self.push_token(TokenData::NumericLiteral(num as f64)) self.push_token(TokenData::NumericLiteral(num as f64))
@ -374,12 +374,12 @@ impl<'a> Lexer<'a> {
'.' => loop { '.' => loop {
buf.push(self.next()?); buf.push(self.next()?);
let ch = match self.preview_next() { let c = match self.preview_next() {
Some(ch) => ch, Some(ch) => ch,
None => break, None => break,
}; };
if !ch.is_digit(10) { if !c.is_digit(10) {
break 'digitloop; break 'digitloop;
} }
}, },
@ -393,7 +393,7 @@ impl<'a> Lexer<'a> {
} }
} }
// TODO make this a bit more safe -------------------------------VVVV // TODO make this a bit more safe -------------------------------VVVV
self.push_token(TokenData::NumericLiteral(f64::from_str(&buf).unwrap())) self.push_token(TokenData::NumericLiteral(f64::from_str(&buf).expect("Could not convert value to f64")))
} }
_ if ch.is_alphabetic() || ch == '$' || ch == '_' => { _ if ch.is_alphabetic() || ch == '$' || ch == '_' => {
let mut buf = ch.to_string(); let mut buf = ch.to_string();
@ -419,7 +419,7 @@ impl<'a> Lexer<'a> {
} }
}); });
// Move position forward the length of keyword // Move position forward the length of keyword
self.column_number += (buf_compare.len() - 1) as u64; self.column_number += (buf_compare.len().wrapping_sub(1)) as u64;
} }
';' => self.push_punc(Punctuator::Semicolon), ';' => self.push_punc(Punctuator::Semicolon),
':' => self.push_punc(Punctuator::Colon), ':' => self.push_punc(Punctuator::Colon),
@ -573,7 +573,7 @@ impl<'a> Lexer<'a> {
self.column_number = 0; self.column_number = 0;
} }
' ' => (), ' ' => (),
ch => panic!( _ => panic!(
"{}:{}: Unexpected '{}'", "{}:{}: Unexpected '{}'",
self.line_number, self.column_number, ch self.line_number, self.column_number, ch
), ),
@ -582,6 +582,7 @@ impl<'a> Lexer<'a> {
} }
} }
#[allow(clippy::indexing_slicing)]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

19
src/lib/syntax/parser.rs

@ -201,7 +201,7 @@ impl Parser {
ExprDef::If( ExprDef::If(
Box::new(cond), Box::new(cond),
Box::new(expr), Box::new(expr),
if next.is_ok() && next.unwrap().data == TokenData::Keyword(Keyword::Else) { if next.is_ok() && next.expect("Could not get next value").data == TokenData::Keyword(Keyword::Else) {
self.pos += 1; self.pos += 1;
Some(Box::new(self.parse()?)) Some(Box::new(self.parse()?))
} else { } else {
@ -227,7 +227,7 @@ impl Parser {
self.expect_punc(Punctuator::OpenBlock, "switch block")?; self.expect_punc(Punctuator::OpenBlock, "switch block")?;
let mut cases = Vec::new(); let mut cases = Vec::new();
let mut default = None; let mut default = None;
while self.pos + 1 < self.tokens.len() { while self.pos.wrapping_add(1) < self.tokens.len() {
let tok = self.get_token(self.pos)?; let tok = self.get_token(self.pos)?;
self.pos += 1; self.pos += 1;
match tok.data { match tok.data {
@ -243,7 +243,7 @@ impl Parser {
_ => block.push(self.parse()?), _ => block.push(self.parse()?),
} }
} }
cases.push((cond.unwrap(), block)); cases.push((cond.expect("No condition supplied"), block));
} }
TokenData::Keyword(Keyword::Default) => { TokenData::Keyword(Keyword::Default) => {
let mut block = Vec::new(); let mut block = Vec::new();
@ -276,7 +276,7 @@ impl Parser {
Ok(mk!( Ok(mk!(
self, self,
ExprDef::Switch( ExprDef::Switch(
Box::new(value.unwrap()), Box::new(value.expect("Could not get value")),
cases, cases,
match default { match default {
Some(v) => Some(Box::new(v)), Some(v) => Some(Box::new(v)),
@ -369,7 +369,7 @@ impl Parser {
TokenData::Punctuator(Punctuator::OpenParen) => { TokenData::Punctuator(Punctuator::OpenParen) => {
match self.get_token(self.pos)?.data { match self.get_token(self.pos)?.data {
TokenData::Punctuator(Punctuator::CloseParen) TokenData::Punctuator(Punctuator::CloseParen)
if self.get_token(self.pos + 1)?.data if self.get_token(self.pos.wrapping_add(1))?.data
== TokenData::Punctuator(Punctuator::Arrow) => == TokenData::Punctuator(Punctuator::Arrow) =>
{ {
self.pos += 2; self.pos += 2;
@ -503,11 +503,11 @@ impl Parser {
mk!(self, ExprDef::ObjectDecl(Box::new(BTreeMap::new())), token) mk!(self, ExprDef::ObjectDecl(Box::new(BTreeMap::new())), token)
} }
TokenData::Punctuator(Punctuator::OpenBlock) TokenData::Punctuator(Punctuator::OpenBlock)
if self.get_token(self.pos + 1)?.data if self.get_token(self.pos.wrapping_add(1))?.data
== TokenData::Punctuator(Punctuator::Colon) => == TokenData::Punctuator(Punctuator::Colon) =>
{ {
let mut map = Box::new(BTreeMap::new()); let mut map = Box::new(BTreeMap::new());
while self.get_token(self.pos - 1)?.data == TokenData::Punctuator(Punctuator::Comma) while self.get_token(self.pos.wrapping_sub(1))?.data == TokenData::Punctuator(Punctuator::Comma)
|| map.len() == 0 || map.len() == 0
{ {
let tk = self.get_token(self.pos)?; let tk = self.get_token(self.pos)?;
@ -603,7 +603,7 @@ impl Parser {
} }
TokenData::Punctuator(Punctuator::OpenParen) => { TokenData::Punctuator(Punctuator::OpenParen) => {
let mut args = Vec::new(); let mut args = Vec::new();
let mut expect_comma_or_end = self.get_token(self.pos + 1)?.data let mut expect_comma_or_end = self.get_token(self.pos.wrapping_add(1))?.data
== TokenData::Punctuator(Punctuator::CloseParen); == TokenData::Punctuator(Punctuator::CloseParen);
loop { loop {
self.pos += 1; self.pos += 1;
@ -822,7 +822,7 @@ impl Parser {
/// Returns an error if the next symbol is not `tk` /// Returns an error if the next symbol is not `tk`
fn expect(&mut self, tk: TokenData, routine: &'static str) -> Result<(), ParseError> { fn expect(&mut self, tk: TokenData, routine: &'static str) -> Result<(), ParseError> {
self.pos += 1; self.pos += 1;
let curr_tk = self.get_token(self.pos - 1)?; let curr_tk = self.get_token(self.pos.wrapping_sub(1))?;
if curr_tk.data == tk { if curr_tk.data == tk {
Ok(()) Ok(())
} else { } else {
@ -845,6 +845,7 @@ mod tests {
lexer::Lexer, lexer::Lexer,
}; };
#[allow(clippy::result_unwrap_used)]
fn check_parser(js: &str, expr: &[Expr]) { fn check_parser(js: &str, expr: &[Expr]) {
let mut lexer = Lexer::new(js); let mut lexer = Lexer::new(js);
lexer.lex().expect("failed to lex"); lexer.lex().expect("failed to lex");

Loading…
Cancel
Save