Skip to content

Commit 3c19db9

Browse files
authored
Merge pull request rust-lang#31 from oli-obk/chars
implement char handling
2 parents 579628f + b10fc7a commit 3c19db9

File tree

6 files changed

+51
-4
lines changed

6 files changed

+51
-4
lines changed

Diff for: src/error.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub enum EvalError<'tcx> {
2828
ExecuteMemory,
2929
ArrayIndexOutOfBounds(Span, u64, u64),
3030
Math(Span, ConstMathErr),
31+
InvalidChar(u32),
3132
}
3233

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

@@ -82,9 +85,11 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
8285
EvalError::FunctionPointerTyMismatch(expected, got) =>
8386
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
8487
EvalError::ArrayIndexOutOfBounds(span, len, index) =>
85-
write!(f, "array index {} out of bounds {} at {:?}", index, len, span),
88+
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
8689
EvalError::Math(span, ref err) =>
87-
write!(f, "mathematical operation at {:?} failed with {:?}", span, err),
90+
write!(f, "{:?} at {:?}", err, span),
91+
EvalError::InvalidChar(c) =>
92+
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
8893
_ => write!(f, "{}", self.description()),
8994
}
9095
}

Diff for: src/interpreter/mod.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
208208
self.memory.write_bool(ptr, b)?;
209209
Ok(ptr)
210210
}
211-
Char(_c) => unimplemented!(),
211+
Char(c) => {
212+
let ptr = self.memory.allocate(4);
213+
self.memory.write_uint(ptr, c as u64, 4)?;
214+
Ok(ptr)
215+
},
212216
Struct(_node_id) => unimplemented!(),
213217
Tuple(_node_id) => unimplemented!(),
214218
Function(_def_id) => unimplemented!(),
@@ -402,11 +406,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
402406

403407
SwitchInt { ref discr, ref values, ref targets, .. } => {
404408
let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
409+
let discr_ty = self.lvalue_ty(discr);
405410
let discr_size = self
406-
.type_layout(self.lvalue_ty(discr))
411+
.type_layout(discr_ty)
407412
.size(&self.tcx.data_layout)
408413
.bytes() as usize;
409414
let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
415+
if let ty::TyChar = discr_ty.sty {
416+
if ::std::char::from_u32(discr_val as u32).is_none() {
417+
return Err(EvalError::InvalidChar(discr_val as u32));
418+
}
419+
}
410420

411421
// Branch to the `otherwise` case by default, if no match is found.
412422
let mut target_block = targets[targets.len() - 1];
@@ -1371,6 +1381,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13711381
use syntax::ast::{IntTy, UintTy};
13721382
let val = match (self.memory.pointer_size, &ty.sty) {
13731383
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),
1384+
(_, &ty::TyChar) => {
1385+
let c = self.memory.read_uint(ptr, 4)? as u32;
1386+
match ::std::char::from_u32(c) {
1387+
Some(ch) => PrimVal::Char(ch),
1388+
None => return Err(EvalError::InvalidChar(c)),
1389+
}
1390+
}
13741391
(_, &ty::TyInt(IntTy::I8)) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
13751392
(2, &ty::TyInt(IntTy::Is)) |
13761393
(_, &ty::TyInt(IntTy::I16)) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),

Diff for: src/memory.rs

+1
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ impl<'tcx> Memory<'tcx> {
369369
PrimVal::U16(n) => self.write_uint(ptr, n as u64, 2),
370370
PrimVal::U32(n) => self.write_uint(ptr, n as u64, 4),
371371
PrimVal::U64(n) => self.write_uint(ptr, n as u64, 8),
372+
PrimVal::Char(c) => self.write_uint(ptr, c as u64, 4),
372373
PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
373374
PrimVal::FnPtr(_p) |
374375
PrimVal::AbstractPtr(_p) => unimplemented!(),

Diff for: src/primval.rs

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub enum PrimVal {
1212
AbstractPtr(Pointer),
1313
FnPtr(Pointer),
1414
IntegerPtr(u64),
15+
Char(char),
1516
}
1617

1718
/// returns the result of the operation and whether the operation overflowed
@@ -127,6 +128,15 @@ pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> Eva
127128
(U16(l), U16(r)) => int_binops!(U16, l, r),
128129
(U32(l), U32(r)) => int_binops!(U32, l, r),
129130
(U64(l), U64(r)) => int_binops!(U64, l, r),
131+
(Char(l), Char(r)) => match bin_op {
132+
Eq => Bool(l == r),
133+
Ne => Bool(l != r),
134+
Lt => Bool(l < r),
135+
Le => Bool(l <= r),
136+
Gt => Bool(l > r),
137+
Ge => Bool(l >= r),
138+
_ => panic!("invalid char op: {:?}", bin_op),
139+
},
130140

131141
(Bool(l), Bool(r)) => {
132142
Bool(match bin_op {

Diff for: tests/compile-fail/option_eq.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//error-pattern: can't handle cast: tmp0 as isize (Misc)
2+
// no-ignore-x86 ignore-x86_64
3+
fn main() {
4+
assert_eq!(std::char::from_u32('x' as u32), Some('x'));
5+
}

Diff for: tests/run-pass/char.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
let c = 'x';
3+
assert_eq!(c, 'x');
4+
assert!('a' < 'z');
5+
assert!('1' < '9');
6+
assert_eq!(std::char::from_u32('x' as u32).unwrap(), 'x');
7+
// FIXME:
8+
// assert_eq!(std::char::from_u32('x' as u32), Some('x'));
9+
}

0 commit comments

Comments
 (0)