Skip to content

Commit

Permalink
Merge pull request rust-lang#31 from oli-obk/chars
Browse files Browse the repository at this point in the history
implement char handling
  • Loading branch information
solson authored Jun 21, 2016
2 parents 579628f + b10fc7a commit 3c19db9
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 4 deletions.
9 changes: 7 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub enum EvalError<'tcx> {
ExecuteMemory,
ArrayIndexOutOfBounds(Span, u64, u64),
Math(Span, ConstMathErr),
InvalidChar(u32),
}

pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
Expand Down Expand Up @@ -66,6 +67,8 @@ impl<'tcx> Error for EvalError<'tcx> {
"array index out of bounds",
EvalError::Math(..) =>
"mathematical operation failed",
EvalError::InvalidChar(..) =>
"tried to interpret an invalid 32-bit value as a char",
}
}

Expand All @@ -82,9 +85,11 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
EvalError::FunctionPointerTyMismatch(expected, got) =>
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
EvalError::ArrayIndexOutOfBounds(span, len, index) =>
write!(f, "array index {} out of bounds {} at {:?}", index, len, span),
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
EvalError::Math(span, ref err) =>
write!(f, "mathematical operation at {:?} failed with {:?}", span, err),
write!(f, "{:?} at {:?}", err, span),
EvalError::InvalidChar(c) =>
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
_ => write!(f, "{}", self.description()),
}
}
Expand Down
21 changes: 19 additions & 2 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.memory.write_bool(ptr, b)?;
Ok(ptr)
}
Char(_c) => unimplemented!(),
Char(c) => {
let ptr = self.memory.allocate(4);
self.memory.write_uint(ptr, c as u64, 4)?;
Ok(ptr)
},
Struct(_node_id) => unimplemented!(),
Tuple(_node_id) => unimplemented!(),
Function(_def_id) => unimplemented!(),
Expand Down Expand Up @@ -402,11 +406,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

SwitchInt { ref discr, ref values, ref targets, .. } => {
let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
let discr_ty = self.lvalue_ty(discr);
let discr_size = self
.type_layout(self.lvalue_ty(discr))
.type_layout(discr_ty)
.size(&self.tcx.data_layout)
.bytes() as usize;
let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
if let ty::TyChar = discr_ty.sty {
if ::std::char::from_u32(discr_val as u32).is_none() {
return Err(EvalError::InvalidChar(discr_val as u32));
}
}

// Branch to the `otherwise` case by default, if no match is found.
let mut target_block = targets[targets.len() - 1];
Expand Down Expand Up @@ -1371,6 +1381,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
use syntax::ast::{IntTy, UintTy};
let val = match (self.memory.pointer_size, &ty.sty) {
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),
(_, &ty::TyChar) => {
let c = self.memory.read_uint(ptr, 4)? as u32;
match ::std::char::from_u32(c) {
Some(ch) => PrimVal::Char(ch),
None => return Err(EvalError::InvalidChar(c)),
}
}
(_, &ty::TyInt(IntTy::I8)) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
(2, &ty::TyInt(IntTy::Is)) |
(_, &ty::TyInt(IntTy::I16)) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
Expand Down
1 change: 1 addition & 0 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ impl<'tcx> Memory<'tcx> {
PrimVal::U16(n) => self.write_uint(ptr, n as u64, 2),
PrimVal::U32(n) => self.write_uint(ptr, n as u64, 4),
PrimVal::U64(n) => self.write_uint(ptr, n as u64, 8),
PrimVal::Char(c) => self.write_uint(ptr, c as u64, 4),
PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
PrimVal::FnPtr(_p) |
PrimVal::AbstractPtr(_p) => unimplemented!(),
Expand Down
10 changes: 10 additions & 0 deletions src/primval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum PrimVal {
AbstractPtr(Pointer),
FnPtr(Pointer),
IntegerPtr(u64),
Char(char),
}

/// returns the result of the operation and whether the operation overflowed
Expand Down Expand Up @@ -127,6 +128,15 @@ pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> Eva
(U16(l), U16(r)) => int_binops!(U16, l, r),
(U32(l), U32(r)) => int_binops!(U32, l, r),
(U64(l), U64(r)) => int_binops!(U64, l, r),
(Char(l), Char(r)) => match bin_op {
Eq => Bool(l == r),
Ne => Bool(l != r),
Lt => Bool(l < r),
Le => Bool(l <= r),
Gt => Bool(l > r),
Ge => Bool(l >= r),
_ => panic!("invalid char op: {:?}", bin_op),
},

(Bool(l), Bool(r)) => {
Bool(match bin_op {
Expand Down
5 changes: 5 additions & 0 deletions tests/compile-fail/option_eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//error-pattern: can't handle cast: tmp0 as isize (Misc)
// no-ignore-x86 ignore-x86_64
fn main() {
assert_eq!(std::char::from_u32('x' as u32), Some('x'));
}
9 changes: 9 additions & 0 deletions tests/run-pass/char.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn main() {
let c = 'x';
assert_eq!(c, 'x');
assert!('a' < 'z');
assert!('1' < '9');
assert_eq!(std::char::from_u32('x' as u32).unwrap(), 'x');
// FIXME:
// assert_eq!(std::char::from_u32('x' as u32), Some('x'));
}

0 comments on commit 3c19db9

Please sign in to comment.