diff --git a/Cargo.lock b/Cargo.lock index 6e6f5d3..3571d40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,7 @@ dependencies = [ "indexmap", "parser", "rustc-hash", + "smallvec", ] [[package]] @@ -473,9 +474,9 @@ checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" [[package]] name = "smallvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smawk" diff --git a/analysis/Cargo.toml b/analysis/Cargo.toml index fe938b8..575e6b3 100644 --- a/analysis/Cargo.toml +++ b/analysis/Cargo.toml @@ -10,3 +10,4 @@ bumpalo = "3.10.0" indexmap = "1.9.1" parser = { path = "../parser" } rustc-hash = "1.1.0" +smallvec = { version = "1.10.0", features = ["union"] } diff --git a/analysis/src/ir.rs b/analysis/src/ir.rs index 8f683b1..97ee1cc 100644 --- a/analysis/src/ir.rs +++ b/analysis/src/ir.rs @@ -187,6 +187,7 @@ pub enum UnaryKind { pub enum ConstValue { Void, Int(u128), + StaticPtr(DefId), } impl Func<'_> { diff --git a/analysis/src/ir/pretty.rs b/analysis/src/ir/pretty.rs index c2e3e81..1c62e7f 100644 --- a/analysis/src/ir/pretty.rs +++ b/analysis/src/ir/pretty.rs @@ -186,6 +186,7 @@ impl Display for ConstValue { match self { ConstValue::Int(int) => <_ as Display>::fmt(int, f), ConstValue::Void => f.write_str("void"), + ConstValue::StaticPtr(def_id) => write!(f, "{{{}}}", def_id.0), } } } diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index fa00dda..c7ceb0d 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -1,4 +1,5 @@ mod builder; +mod typeck; use std::cell::{Cell, RefCell}; @@ -24,6 +25,7 @@ type Result = std::result::Result; struct LoweringCx<'cx> { tys: RefCell>>, layouts: RefCell>, + string_literals: RefCell>, arena: &'cx bumpalo::Bump, next_def_id: Cell, } @@ -38,13 +40,10 @@ impl<'cx> LoweringCx<'cx> { let kind = match ty { ast::TypeSpecifier::Void => TyKind::Void, ast::TypeSpecifier::Char => TyKind::Char, - ast::TypeSpecifier::SChar => TyKind::SChar, - ast::TypeSpecifier::UChar => TyKind::UChar, ast::TypeSpecifier::Integer(int) => TyKind::Integer(*int), ast::TypeSpecifier::Float => TyKind::Float, ast::TypeSpecifier::Double => TyKind::Double, ast::TypeSpecifier::LongDouble => TyKind::LongDouble, - ast::TypeSpecifier::Bool => TyKind::Bool, }; self.intern_ty(kind) } @@ -73,22 +72,34 @@ impl<'cx> LoweringCx<'cx> { } } + fn intern_str_lit(&self, str: &[u8]) -> DefId { + let opt_str = self.string_literals.borrow().get(str).copied(); + match opt_str { + Some(lit_def_id) => lit_def_id, + None => { + let str = self.arena.alloc_slice_copy(str); + let lit_def_id = self.next_def_id(); + self.string_literals.borrow_mut().insert(str, lit_def_id); + lit_def_id + } + } + } + fn layout_of(&self, ty: Ty<'cx>) -> TyLayout<'cx> { let layout = match *ty { TyKind::Void => Layout::size_align(0, 1), TyKind::Char => Layout::size_align(1, 1), - TyKind::SChar => Layout::size_align(1, 1), - TyKind::UChar => Layout::size_align(1, 1), TyKind::Integer(int) => match int.kind { - parser::ast::IntTyKind::Short => Layout::size_align(2, 2), - parser::ast::IntTyKind::Int => Layout::size_align(4, 4), - parser::ast::IntTyKind::Long => Layout::size_align(8, 8), - parser::ast::IntTyKind::LongLong => Layout::size_align(8, 8), + IntTyKind::Bool => Layout::size_align(1, 1), + IntTyKind::Char => Layout::size_align(1, 1), + IntTyKind::Short => Layout::size_align(2, 2), + IntTyKind::Int => Layout::size_align(4, 4), + IntTyKind::Long => Layout::size_align(8, 8), + IntTyKind::LongLong => Layout::size_align(8, 8), }, TyKind::Float => Layout::size_align(4, 4), TyKind::Double => Layout::size_align(8, 8), TyKind::LongDouble => Layout::size_align(8, 8), - TyKind::Bool => Layout::size_align(1, 1), TyKind::Struct(_) => todo!("layout_of struct"), TyKind::Union(_) => todo!("layout_of union"), TyKind::Enum(_) => todo!("layout_of enum"), @@ -106,6 +117,7 @@ pub fn lower_translation_unit<'cx>( let lcx = LoweringCx { tys: RefCell::default(), layouts: RefCell::default(), + string_literals: RefCell::default(), arena, next_def_id: Cell::new(DefId(0)), }; @@ -139,11 +151,25 @@ pub fn lower_translation_unit<'cx>( Ok(ir) } -#[derive(Debug)] struct FnLoweringCtxt<'a, 'cx> { scopes: Vec>>, build: FuncBuilder<'a, 'cx>, lcx: &'a LoweringCx<'cx>, + types: CommonTypes<'cx>, +} + +struct CommonInt<'cx> { + signed: Ty<'cx>, + unsigned: Ty<'cx>, +} + +struct CommonTypes<'cx> { + void: Ty<'cx>, + char: Ty<'cx>, + su_char: CommonInt<'cx>, + short: CommonInt<'cx>, + int: CommonInt<'cx>, + long: CommonInt<'cx>, } impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { @@ -292,18 +318,15 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { } fn lower_expr(&mut self, expr: &ast::Expr, span: Span) -> Result<(Operand, TyLayout<'cx>)> { - match expr { - ast::Expr::Atom(ast::Atom::Char(c)) => Ok(( + let op_tyl = match expr { + ast::Expr::Atom(ast::Atom::Char(c)) => ( Operand::Const(ConstValue::Int((*c).into())), - self.ty_layout(TyKind::Char), - )), - ast::Expr::Atom(ast::Atom::Int(i)) => Ok(( + self.lcx.layout_of(self.types.char), + ), + ast::Expr::Atom(ast::Atom::Int(i)) => ( Operand::Const(ConstValue::Int(*i as _)), - self.ty_layout(TyKind::Integer(IntTy { - sign: IntTySignedness::Signed, - kind: IntTyKind::Int, - })), - )), + self.lcx.layout_of(self.types.int.signed), + ), ast::Expr::Atom(ast::Atom::Float(_)) => todo!("no floats"), ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) => { let Some(var) = self.resolve_ident(*ident) else { @@ -311,9 +334,15 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { }; let tyl = var.tyl; let op = self.build.load(var.tyl, var.ptr_to, span); - Ok((Operand::Reg(op), tyl)) + (Operand::Reg(op), tyl) + } + ast::Expr::Atom(ast::Atom::String(string)) => { + let lit_def_id = self.lcx.intern_str_lit(string); + ( + Operand::Const(ConstValue::StaticPtr(lit_def_id)), + self.ty_layout(TyKind::Ptr(self.types.char)), + ) } - ast::Expr::Atom(ast::Atom::String(_)) => todo!("no string literals"), ast::Expr::Unary(ast::ExprUnary { op: op @ (ast::UnaryOp::Increment | ast::UnaryOp::Decrement), rhs: rhs_expr, @@ -341,7 +370,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { .binary(bin_kind, Operand::Reg(lhs), rhs, span, self.dummy_tyl()); self.build.store(lhs, rhs, self.dummy_tyl().layout, span); - Ok((Operand::Reg(result), self.dummy_tyl())) + (Operand::Reg(result), self.dummy_tyl()) } ast::Expr::Unary(unary) => { let rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?; @@ -357,7 +386,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { }; let reg = self.build.unary(kind, rhs.0, span, self.dummy_tyl()); - Ok((Operand::Reg(reg), self.dummy_tyl())) + (Operand::Reg(reg), self.dummy_tyl()) } ast::Expr::Binary(ast::ExprBinary { lhs, @@ -372,7 +401,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { let ptr_to = self.expr_as_lvalue(&lhs.0)?; self.build .store(ptr_to, rhs.0, self.dummy_tyl().layout, span); - Ok(rhs) + rhs } ast::Expr::Binary(binary) => { let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?; @@ -408,7 +437,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { .build .binary(kind, lhs.0, rhs.0, span, self.dummy_tyl()); - Ok((Operand::Reg(reg), self.dummy_tyl())) + (Operand::Reg(reg), self.dummy_tyl()) } ast::Expr::Postfix(postfix) => { let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?; @@ -420,7 +449,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { .collect::>()?; let reg = self.build.call(self.dummy_tyl(), lhs.0, args, span); - Ok((Operand::Reg(reg), self.dummy_tyl())) + (Operand::Reg(reg), self.dummy_tyl()) } ast::PostfixOp::Member(_) => todo!("member expr"), ast::PostfixOp::ArrowMember(_) => todo!("arrow member expr"), @@ -430,7 +459,8 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { ast::PostfixOp::Decrement => todo!(), } } - } + }; + Ok(op_tyl) } } @@ -461,6 +491,7 @@ fn lower_func<'cx>( params.len().try_into().unwrap(), ), lcx, + types: CommonTypes::new(lcx), }; for param in params { @@ -512,3 +543,22 @@ fn lower_func<'cx>( Ok(cx.build.finish()) } + +impl<'cx> CommonTypes<'cx> { + fn new(lcx: &LoweringCx<'cx>) -> Self { + let int = |sign, kind| lcx.intern_ty(TyKind::Integer(IntTy { sign, kind })); + let int_pair = |kind| CommonInt { + signed: int(IntTySignedness::Signed, kind), + unsigned: int(IntTySignedness::Unsigned, kind), + }; + + Self { + void: lcx.intern_ty(TyKind::Void), + char: lcx.intern_ty(TyKind::Char), + su_char: int_pair(IntTyKind::Char), + short: int_pair(IntTyKind::Short), + int: int_pair(IntTyKind::Int), + long: int_pair(IntTyKind::Long), + } + } +} diff --git a/analysis/src/lower/typeck.rs b/analysis/src/lower/typeck.rs new file mode 100644 index 0000000..c73dc5b --- /dev/null +++ b/analysis/src/lower/typeck.rs @@ -0,0 +1,160 @@ +use parser::{ + ast::{IntTy, IntTyKind, IntTySignedness}, + Span, +}; +use smallvec::{smallvec, SmallVec}; + +use super::{FnLoweringCtxt, Result}; +use crate::{ + ty::{Ty, TyKind}, + Error, +}; + +pub(super) type Coercions<'cx> = SmallVec<[(Coercion, Ty<'cx>); 2]>; + +pub(super) enum Coercion { + ZeroExt, + SignExt, + SignToUnsigned, +} + +pub(super) struct ArithCoerce<'cx> { + pub result: Ty<'cx>, + pub lhs: Coercions<'cx>, + pub rhs: Coercions<'cx>, +} + +impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { + /// Performs implicit coercion. + /// §6.3.1.8 Usual arithmetic conversions + pub(super) fn arith_op( + &mut self, + lhs: Ty<'cx>, + rhs: Ty<'cx>, + span: Span, + ) -> Result<(Ty<'cx>, Coercions<'cx>, Coercions<'cx>)> { + Ok(match (*lhs, *rhs) { + (TyKind::LongDouble, _) => (lhs, smallvec![], self.coerce(rhs, lhs)?), + (_, TyKind::LongDouble) => (rhs, self.coerce(lhs, rhs)?, smallvec![]), + (TyKind::Double, _) => (lhs, smallvec![], self.coerce(rhs, lhs)?), + (_, TyKind::Double) => (rhs, self.coerce(lhs, rhs)?, smallvec![]), + (TyKind::Float, _) => (lhs, smallvec![], self.coerce(rhs, lhs)?), + (_, TyKind::Float) => (rhs, self.coerce(lhs, rhs)?, smallvec![]), + (_, _) => { + let mut lhs_coerce = self.promote(lhs, span)?; + let mut rhs_coerce = self.promote(rhs, span)?; + + let lhs_prom = lhs_coerce.last().map_or(lhs, |(_, ty)| *ty); + let rhs_prom = rhs_coerce.last().map_or(rhs, |(_, ty)| *ty); + let lhs_prom_int = lhs_prom.unwrap_int(); + let rhs_prom_int = rhs_prom.unwrap_int(); + + let lhs_sign = lhs_prom_int.sign; + let rhs_sign = rhs_prom_int.sign; + + let lhs_kind = lhs_prom_int.kind; + let rhs_kind = rhs_prom_int.kind; + + // If both operands have the same type, then no further conversion is needed. + let result = if lhs_prom == rhs_prom { + lhs + // Otherwise, if both operands have signed integer types or both have unsigned + // integer types, the operand with the type of lesser integer conversion rank is + // converted to the type of the operand with greater rank. + } else if (lhs_sign.unsigned() && rhs_prom_int.sign.unsigned()) + || (lhs_sign.signed() && rhs_sign.signed()) + { + if lhs_kind > rhs_kind { + rhs_coerce.extend(self.coerce(rhs_prom, lhs_prom)?); + lhs + } else if lhs_kind < rhs_kind { + lhs_coerce.extend(self.coerce(lhs_prom, rhs_prom)?); + rhs + } else { + unreachable!("integers must have different rank here") + } + // Otherwise, if the operand that has unsigned integer type has rank greater or + // equal to the rank of the type of the other operand, then the operand with + // signed integer type is converted to the type of the operand with unsigned + // integer type. + } else if (lhs_sign.unsigned() && lhs_kind >= rhs_kind) + || (rhs_sign.unsigned() && rhs_kind >= lhs_kind) + { + if lhs_sign.unsigned() { + rhs_coerce.extend(self.coerce(rhs_prom, lhs_prom)?); + lhs + } else { + lhs_coerce.extend(self.coerce(lhs_prom, rhs_prom)?); + rhs + } + // Otherwise, if the type of the operand with signed integer type can represent + // all of the values of the type of the operand with unsigned integer type, then + // the operand with unsigned integer type is converted to the type of the + // operand with signed integer type. + } else if (lhs_sign.unsigned() && is_int_bigger(rhs_kind, lhs_kind)) + || (rhs_sign.unsigned() && is_int_bigger(lhs_kind, rhs_kind)) + { + if lhs_sign.unsigned() { + lhs_coerce.extend(self.coerce(lhs_prom, rhs_prom)?); + rhs + } else { + rhs_coerce.extend(self.coerce(rhs_prom, lhs_prom)?); + lhs + } + // Otherwise, both operands are converted to the unsigned integer type + // corresponding to the type of the operand with signed integer type. + } else { + let kind = if lhs_sign.signed() { + lhs_kind + } else { + rhs_kind + }; + let ty = self.lcx.intern_ty(TyKind::Integer(IntTy { + kind, + sign: IntTySignedness::Unsigned, + })); + lhs_coerce.extend(self.coerce(lhs_prom, ty)?); + ty + }; + + (result, lhs_coerce, rhs_coerce) + } + }) + } + + fn coerce(&mut self, from: Ty<'cx>, to: Ty<'cx>) -> Result> { + if from != to { + todo!("coerce.") + } + Ok(smallvec![]) + } + + // §6.3.1.1 Boolean, characters, and integers + fn promote(&self, ty: Ty<'cx>, span: Span) -> Result> { + Ok(match *ty { + TyKind::Char => smallvec![(Coercion::SignExt, self.types.int.signed)], + TyKind::Integer(int) if int.kind < IntTyKind::Int => match int.sign { + IntTySignedness::Signed => smallvec![(Coercion::SignExt, self.types.int.signed)], + IntTySignedness::Unsigned => { + smallvec![(Coercion::ZeroExt, self.types.int.unsigned)] + } + }, + TyKind::Integer(_) => smallvec![], + TyKind::Enum(_) => todo!("enums are unimplemented"), + _ => return Err(Error::new(format!("cannot convert {ty} to integer"), span)), + }) + } +} + +fn is_int_bigger(this: IntTyKind, compared_to: IntTyKind) -> bool { + let num = |kind| match kind { + IntTyKind::Bool => 1, + IntTyKind::Char => 2, + IntTyKind::Short => 3, + IntTyKind::Int => 4, + IntTyKind::Long => 5, + IntTyKind::LongLong => 5, + }; + + num(this) > num(compared_to) +} diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 7918b7c..d3f2fa6 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -12,20 +12,17 @@ use parser::{ use crate::ir::DefId; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, Eq)] pub struct Ty<'cx>(&'cx TyKind<'cx>); #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum TyKind<'cx> { Void, Char, - SChar, - UChar, Integer(IntTy), Float, Double, LongDouble, - Bool, Ptr(Ty<'cx>), Union(UnionTy<'cx>), Struct(StructTy<'cx>), @@ -84,14 +81,14 @@ impl Display for Ty<'_> { match **self { TyKind::Void => f.write_str("void"), TyKind::Char => f.write_str("char"), - TyKind::SChar => f.write_str("signed char"), - TyKind::UChar => f.write_str("unsigned char"), TyKind::Integer(int) => { match int.sign { IntTySignedness::Signed => f.write_str("signed "), IntTySignedness::Unsigned => f.write_str("unsigned "), }?; match int.kind { + IntTyKind::Bool => f.write_str("_Bool"), + IntTyKind::Char => f.write_str("char"), IntTyKind::Short => f.write_str("short"), IntTyKind::Int => f.write_str("int"), IntTyKind::Long => f.write_str("long"), @@ -102,7 +99,6 @@ impl Display for Ty<'_> { TyKind::Float => f.write_str("float"), TyKind::Double => f.write_str("double"), TyKind::LongDouble => f.write_str("long double"), - TyKind::Bool => f.write_str("_Bool"), TyKind::Ptr(ty) => { write!(f, "{ty}*") } @@ -113,11 +109,29 @@ impl Display for Ty<'_> { } } -impl<'cx> Ty<'cx> { - pub fn is_integral(self) -> bool { - matches!( - *self, - TyKind::Char | TyKind::SChar | TyKind::UChar | TyKind::Integer(_) - ) +impl PartialEq for Ty<'_> { + fn eq(&self, other: &Self) -> bool { + // Interning. + std::ptr::eq(&self.0, &other.0) + } +} + +impl Hash for Ty<'_> { + fn hash(&self, state: &mut H) { + // Interning. + std::ptr::hash(&self.0, state) + } +} + +impl<'cx> Ty<'cx> { + pub fn is_integral(self) -> bool { + matches!(*self, TyKind::Char | TyKind::Integer(_)) + } + + pub fn unwrap_int(self) -> IntTy { + match *self { + TyKind::Integer(int) => *int, + _ => panic!("expected integer type, found {self}"), + } } } diff --git a/parser/src/ast.rs b/parser/src/ast.rs index cd9bc88..d805b18 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -17,7 +17,7 @@ pub enum Atom { Ident(Ident), Int(u128), Float(f64), - String(String), + String(Vec), Char(u8), } @@ -157,8 +157,11 @@ impl Default for IntTySignedness { } } -#[derive(Debug, DebugPls, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, DebugPls, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +// N.B: Ord, order matters. pub enum IntTyKind { + Bool, + Char, Short, Int, Long, @@ -175,13 +178,10 @@ pub struct IntTy { pub enum TypeSpecifier { Void, Char, - SChar, - UChar, Integer(IntTy), Float, Double, LongDouble, - Bool, // TODO // complex // atomic-type-specifier @@ -294,3 +294,13 @@ impl DirectDeclarator { } } } + +impl IntTySignedness { + pub fn signed(self) -> bool { + matches!(self, Self::Signed) + } + + pub fn unsigned(self) -> bool { + matches!(self, Self::Unsigned) + } +} diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 28448ce..6e3cf58 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -292,8 +292,10 @@ where let ty = match token { Tok::Kw(Kw::Void) => TypeSpecifier::Void, Tok::Kw(Kw::Char) => match signedness { - Some(IntTySignedness::Signed) => TypeSpecifier::SChar, - Some(IntTySignedness::Unsigned) => TypeSpecifier::UChar, + Some(signedness) => TypeSpecifier::Integer(IntTy { + sign: signedness, + kind: IntTyKind::Char, + }), None => TypeSpecifier::Char, }, Tok::Kw(Kw::Short) => { @@ -362,7 +364,10 @@ where } Tok::Kw(Kw::Float) => TypeSpecifier::Float, Tok::Kw(Kw::Double) => TypeSpecifier::Double, - Tok::Kw(Kw::Bool) => TypeSpecifier::Bool, + Tok::Kw(Kw::Bool) => TypeSpecifier::Integer(IntTy { + sign: IntTySignedness::Unsigned, + kind: IntTyKind::Bool, + }), Tok::Kw(Kw::Complex) => { return Err(ParserError::new( span, diff --git a/parser/src/parser/expr.rs b/parser/src/parser/expr.rs index 66f79c0..93010e0 100644 --- a/parser/src/parser/expr.rs +++ b/parser/src/parser/expr.rs @@ -25,7 +25,9 @@ where fn get_lhs(&mut self) -> Result> { let (typ, span) = match self.peek_t()? { &(Tok::Ident(ident), span) => (Atom::Ident((Symbol::intern(ident), span)), span), - &(Tok::StringLiteral(literal), span) => (Atom::String(literal.to_string()), span), + &(Tok::StringLiteral(literal), span) => { + (Atom::String(literal.to_string().into_bytes()), span) + } &(Tok::Constant(Constant::Int(int)), span) => (Atom::Int(int), span), &(Tok::Constant(Constant::Float(float)), span) => (Atom::Float(float), span), &(Tok::Constant(Constant::Char(char)), span) => (Atom::Char(char), span), diff --git a/parser/src/pretty.rs b/parser/src/pretty.rs index 62cc6a2..dce7af8 100644 --- a/parser/src/pretty.rs +++ b/parser/src/pretty.rs @@ -231,8 +231,6 @@ impl PrettyPrinter { match spec { TypeSpecifier::Void => self.string("void"), TypeSpecifier::Char => self.string("char"), - TypeSpecifier::SChar => self.string("signed char"), - TypeSpecifier::UChar => self.string("unsigned char"), TypeSpecifier::Integer(int) => { // prefix the unsignedness if desired if let IntTySignedness::Unsigned = int.sign { @@ -240,6 +238,8 @@ impl PrettyPrinter { } match int.kind { + IntTyKind::Bool => self.string("_Bool"), + IntTyKind::Char => self.string("char"), IntTyKind::Short => self.string("short"), IntTyKind::Int => self.string("int"), IntTyKind::Long => self.string("long"), @@ -249,7 +249,6 @@ impl PrettyPrinter { TypeSpecifier::Float => self.string("float"), TypeSpecifier::Double => self.string("double"), TypeSpecifier::LongDouble => self.string("long double"), - TypeSpecifier::Bool => self.string("_Bool"), } } @@ -316,7 +315,11 @@ impl PrettyPrinter { Atom::String(string) => { self.string("\"")?; // bare attempt at escpaing - self.string(&string.replace('\"', "\\\""))?; + self.string( + &std::str::from_utf8(string) + .unwrap_or("") + .replace('\"', "\\\""), + )?; self.string("\"")?; Ok(()) }