c what is this

This commit is contained in:
nora 2023-05-23 20:42:51 +02:00
parent ffd3dad040
commit 54226ad499
11 changed files with 305 additions and 57 deletions

5
Cargo.lock generated
View file

@ -36,6 +36,7 @@ dependencies = [
"indexmap", "indexmap",
"parser", "parser",
"rustc-hash", "rustc-hash",
"smallvec",
] ]
[[package]] [[package]]
@ -473,9 +474,9 @@ checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.8.1" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]] [[package]]
name = "smawk" name = "smawk"

View file

@ -10,3 +10,4 @@ bumpalo = "3.10.0"
indexmap = "1.9.1" indexmap = "1.9.1"
parser = { path = "../parser" } parser = { path = "../parser" }
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
smallvec = { version = "1.10.0", features = ["union"] }

View file

@ -187,6 +187,7 @@ pub enum UnaryKind {
pub enum ConstValue { pub enum ConstValue {
Void, Void,
Int(u128), Int(u128),
StaticPtr(DefId),
} }
impl Func<'_> { impl Func<'_> {

View file

@ -186,6 +186,7 @@ impl Display for ConstValue {
match self { match self {
ConstValue::Int(int) => <_ as Display>::fmt(int, f), ConstValue::Int(int) => <_ as Display>::fmt(int, f),
ConstValue::Void => f.write_str("void"), ConstValue::Void => f.write_str("void"),
ConstValue::StaticPtr(def_id) => write!(f, "{{{}}}", def_id.0),
} }
} }
} }

View file

@ -1,4 +1,5 @@
mod builder; mod builder;
mod typeck;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
@ -24,6 +25,7 @@ type Result<T, E = Error> = std::result::Result<T, E>;
struct LoweringCx<'cx> { struct LoweringCx<'cx> {
tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>, tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>,
layouts: RefCell<FxHashSet<&'cx Layout>>, layouts: RefCell<FxHashSet<&'cx Layout>>,
string_literals: RefCell<FxHashMap<&'cx [u8], DefId>>,
arena: &'cx bumpalo::Bump, arena: &'cx bumpalo::Bump,
next_def_id: Cell<DefId>, next_def_id: Cell<DefId>,
} }
@ -38,13 +40,10 @@ impl<'cx> LoweringCx<'cx> {
let kind = match ty { let kind = match ty {
ast::TypeSpecifier::Void => TyKind::Void, ast::TypeSpecifier::Void => TyKind::Void,
ast::TypeSpecifier::Char => TyKind::Char, ast::TypeSpecifier::Char => TyKind::Char,
ast::TypeSpecifier::SChar => TyKind::SChar,
ast::TypeSpecifier::UChar => TyKind::UChar,
ast::TypeSpecifier::Integer(int) => TyKind::Integer(*int), ast::TypeSpecifier::Integer(int) => TyKind::Integer(*int),
ast::TypeSpecifier::Float => TyKind::Float, ast::TypeSpecifier::Float => TyKind::Float,
ast::TypeSpecifier::Double => TyKind::Double, ast::TypeSpecifier::Double => TyKind::Double,
ast::TypeSpecifier::LongDouble => TyKind::LongDouble, ast::TypeSpecifier::LongDouble => TyKind::LongDouble,
ast::TypeSpecifier::Bool => TyKind::Bool,
}; };
self.intern_ty(kind) 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> { fn layout_of(&self, ty: Ty<'cx>) -> TyLayout<'cx> {
let layout = match *ty { let layout = match *ty {
TyKind::Void => Layout::size_align(0, 1), TyKind::Void => Layout::size_align(0, 1),
TyKind::Char => Layout::size_align(1, 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 { TyKind::Integer(int) => match int.kind {
parser::ast::IntTyKind::Short => Layout::size_align(2, 2), IntTyKind::Bool => Layout::size_align(1, 1),
parser::ast::IntTyKind::Int => Layout::size_align(4, 4), IntTyKind::Char => Layout::size_align(1, 1),
parser::ast::IntTyKind::Long => Layout::size_align(8, 8), IntTyKind::Short => Layout::size_align(2, 2),
parser::ast::IntTyKind::LongLong => Layout::size_align(8, 8), 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::Float => Layout::size_align(4, 4),
TyKind::Double => Layout::size_align(8, 8), TyKind::Double => Layout::size_align(8, 8),
TyKind::LongDouble => 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::Struct(_) => todo!("layout_of struct"),
TyKind::Union(_) => todo!("layout_of union"), TyKind::Union(_) => todo!("layout_of union"),
TyKind::Enum(_) => todo!("layout_of enum"), TyKind::Enum(_) => todo!("layout_of enum"),
@ -106,6 +117,7 @@ pub fn lower_translation_unit<'cx>(
let lcx = LoweringCx { let lcx = LoweringCx {
tys: RefCell::default(), tys: RefCell::default(),
layouts: RefCell::default(), layouts: RefCell::default(),
string_literals: RefCell::default(),
arena, arena,
next_def_id: Cell::new(DefId(0)), next_def_id: Cell::new(DefId(0)),
}; };
@ -139,11 +151,25 @@ pub fn lower_translation_unit<'cx>(
Ok(ir) Ok(ir)
} }
#[derive(Debug)]
struct FnLoweringCtxt<'a, 'cx> { struct FnLoweringCtxt<'a, 'cx> {
scopes: Vec<FxHashMap<Symbol, VariableInfo<'cx>>>, scopes: Vec<FxHashMap<Symbol, VariableInfo<'cx>>>,
build: FuncBuilder<'a, 'cx>, build: FuncBuilder<'a, 'cx>,
lcx: &'a LoweringCx<'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> { 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>)> { fn lower_expr(&mut self, expr: &ast::Expr, span: Span) -> Result<(Operand, TyLayout<'cx>)> {
match expr { let op_tyl = match expr {
ast::Expr::Atom(ast::Atom::Char(c)) => Ok(( ast::Expr::Atom(ast::Atom::Char(c)) => (
Operand::Const(ConstValue::Int((*c).into())), Operand::Const(ConstValue::Int((*c).into())),
self.ty_layout(TyKind::Char), self.lcx.layout_of(self.types.char),
)), ),
ast::Expr::Atom(ast::Atom::Int(i)) => Ok(( ast::Expr::Atom(ast::Atom::Int(i)) => (
Operand::Const(ConstValue::Int(*i as _)), Operand::Const(ConstValue::Int(*i as _)),
self.ty_layout(TyKind::Integer(IntTy { self.lcx.layout_of(self.types.int.signed),
sign: IntTySignedness::Signed, ),
kind: IntTyKind::Int,
})),
)),
ast::Expr::Atom(ast::Atom::Float(_)) => todo!("no floats"), ast::Expr::Atom(ast::Atom::Float(_)) => todo!("no floats"),
ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) => { ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) => {
let Some(var) = self.resolve_ident(*ident) else { let Some(var) = self.resolve_ident(*ident) else {
@ -311,9 +334,15 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
}; };
let tyl = var.tyl; let tyl = var.tyl;
let op = self.build.load(var.tyl, var.ptr_to, span); 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 { ast::Expr::Unary(ast::ExprUnary {
op: op @ (ast::UnaryOp::Increment | ast::UnaryOp::Decrement), op: op @ (ast::UnaryOp::Increment | ast::UnaryOp::Decrement),
rhs: rhs_expr, rhs: rhs_expr,
@ -341,7 +370,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
.binary(bin_kind, Operand::Reg(lhs), rhs, span, self.dummy_tyl()); .binary(bin_kind, Operand::Reg(lhs), rhs, span, self.dummy_tyl());
self.build.store(lhs, rhs, self.dummy_tyl().layout, span); 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) => { ast::Expr::Unary(unary) => {
let rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?; 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()); 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 { ast::Expr::Binary(ast::ExprBinary {
lhs, lhs,
@ -372,7 +401,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
let ptr_to = self.expr_as_lvalue(&lhs.0)?; let ptr_to = self.expr_as_lvalue(&lhs.0)?;
self.build self.build
.store(ptr_to, rhs.0, self.dummy_tyl().layout, span); .store(ptr_to, rhs.0, self.dummy_tyl().layout, span);
Ok(rhs) rhs
} }
ast::Expr::Binary(binary) => { ast::Expr::Binary(binary) => {
let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?; let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?;
@ -408,7 +437,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
.build .build
.binary(kind, lhs.0, rhs.0, span, self.dummy_tyl()); .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) => { ast::Expr::Postfix(postfix) => {
let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?; let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?;
@ -420,7 +449,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
let reg = self.build.call(self.dummy_tyl(), lhs.0, args, span); 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::Member(_) => todo!("member expr"),
ast::PostfixOp::ArrowMember(_) => todo!("arrow member expr"), ast::PostfixOp::ArrowMember(_) => todo!("arrow member expr"),
@ -430,7 +459,8 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
ast::PostfixOp::Decrement => todo!(), ast::PostfixOp::Decrement => todo!(),
} }
} }
} };
Ok(op_tyl)
} }
} }
@ -461,6 +491,7 @@ fn lower_func<'cx>(
params.len().try_into().unwrap(), params.len().try_into().unwrap(),
), ),
lcx, lcx,
types: CommonTypes::new(lcx),
}; };
for param in params { for param in params {
@ -512,3 +543,22 @@ fn lower_func<'cx>(
Ok(cx.build.finish()) 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),
}
}
}

View file

@ -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<Coercions<'cx>> {
if from != to {
todo!("coerce.")
}
Ok(smallvec![])
}
// §6.3.1.1 Boolean, characters, and integers
fn promote(&self, ty: Ty<'cx>, span: Span) -> Result<Coercions<'cx>> {
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)
}

View file

@ -12,20 +12,17 @@ use parser::{
use crate::ir::DefId; use crate::ir::DefId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, Eq)]
pub struct Ty<'cx>(&'cx TyKind<'cx>); pub struct Ty<'cx>(&'cx TyKind<'cx>);
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TyKind<'cx> { pub enum TyKind<'cx> {
Void, Void,
Char, Char,
SChar,
UChar,
Integer(IntTy), Integer(IntTy),
Float, Float,
Double, Double,
LongDouble, LongDouble,
Bool,
Ptr(Ty<'cx>), Ptr(Ty<'cx>),
Union(UnionTy<'cx>), Union(UnionTy<'cx>),
Struct(StructTy<'cx>), Struct(StructTy<'cx>),
@ -84,14 +81,14 @@ impl Display for Ty<'_> {
match **self { match **self {
TyKind::Void => f.write_str("void"), TyKind::Void => f.write_str("void"),
TyKind::Char => f.write_str("char"), TyKind::Char => f.write_str("char"),
TyKind::SChar => f.write_str("signed char"),
TyKind::UChar => f.write_str("unsigned char"),
TyKind::Integer(int) => { TyKind::Integer(int) => {
match int.sign { match int.sign {
IntTySignedness::Signed => f.write_str("signed "), IntTySignedness::Signed => f.write_str("signed "),
IntTySignedness::Unsigned => f.write_str("unsigned "), IntTySignedness::Unsigned => f.write_str("unsigned "),
}?; }?;
match int.kind { match int.kind {
IntTyKind::Bool => f.write_str("_Bool"),
IntTyKind::Char => f.write_str("char"),
IntTyKind::Short => f.write_str("short"), IntTyKind::Short => f.write_str("short"),
IntTyKind::Int => f.write_str("int"), IntTyKind::Int => f.write_str("int"),
IntTyKind::Long => f.write_str("long"), IntTyKind::Long => f.write_str("long"),
@ -102,7 +99,6 @@ impl Display for Ty<'_> {
TyKind::Float => f.write_str("float"), TyKind::Float => f.write_str("float"),
TyKind::Double => f.write_str("double"), TyKind::Double => f.write_str("double"),
TyKind::LongDouble => f.write_str("long double"), TyKind::LongDouble => f.write_str("long double"),
TyKind::Bool => f.write_str("_Bool"),
TyKind::Ptr(ty) => { TyKind::Ptr(ty) => {
write!(f, "{ty}*") write!(f, "{ty}*")
} }
@ -113,11 +109,29 @@ impl Display for Ty<'_> {
} }
} }
impl<'cx> Ty<'cx> { impl PartialEq for Ty<'_> {
pub fn is_integral(self) -> bool { fn eq(&self, other: &Self) -> bool {
matches!( // Interning.
*self, std::ptr::eq(&self.0, &other.0)
TyKind::Char | TyKind::SChar | TyKind::UChar | TyKind::Integer(_) }
) }
impl Hash for Ty<'_> {
fn hash<H: Hasher>(&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}"),
}
} }
} }

View file

@ -17,7 +17,7 @@ pub enum Atom {
Ident(Ident), Ident(Ident),
Int(u128), Int(u128),
Float(f64), Float(f64),
String(String), String(Vec<u8>),
Char(u8), 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 { pub enum IntTyKind {
Bool,
Char,
Short, Short,
Int, Int,
Long, Long,
@ -175,13 +178,10 @@ pub struct IntTy {
pub enum TypeSpecifier { pub enum TypeSpecifier {
Void, Void,
Char, Char,
SChar,
UChar,
Integer(IntTy), Integer(IntTy),
Float, Float,
Double, Double,
LongDouble, LongDouble,
Bool,
// TODO // TODO
// complex // complex
// atomic-type-specifier // 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)
}
}

View file

@ -292,8 +292,10 @@ where
let ty = match token { let ty = match token {
Tok::Kw(Kw::Void) => TypeSpecifier::Void, Tok::Kw(Kw::Void) => TypeSpecifier::Void,
Tok::Kw(Kw::Char) => match signedness { Tok::Kw(Kw::Char) => match signedness {
Some(IntTySignedness::Signed) => TypeSpecifier::SChar, Some(signedness) => TypeSpecifier::Integer(IntTy {
Some(IntTySignedness::Unsigned) => TypeSpecifier::UChar, sign: signedness,
kind: IntTyKind::Char,
}),
None => TypeSpecifier::Char, None => TypeSpecifier::Char,
}, },
Tok::Kw(Kw::Short) => { Tok::Kw(Kw::Short) => {
@ -362,7 +364,10 @@ where
} }
Tok::Kw(Kw::Float) => TypeSpecifier::Float, Tok::Kw(Kw::Float) => TypeSpecifier::Float,
Tok::Kw(Kw::Double) => TypeSpecifier::Double, 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) => { Tok::Kw(Kw::Complex) => {
return Err(ParserError::new( return Err(ParserError::new(
span, span,

View file

@ -25,7 +25,9 @@ where
fn get_lhs(&mut self) -> Result<Spanned<Expr>> { fn get_lhs(&mut self) -> Result<Spanned<Expr>> {
let (typ, span) = match self.peek_t()? { let (typ, span) = match self.peek_t()? {
&(Tok::Ident(ident), span) => (Atom::Ident((Symbol::intern(ident), span)), span), &(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::Int(int)), span) => (Atom::Int(int), span),
&(Tok::Constant(Constant::Float(float)), span) => (Atom::Float(float), span), &(Tok::Constant(Constant::Float(float)), span) => (Atom::Float(float), span),
&(Tok::Constant(Constant::Char(char)), span) => (Atom::Char(char), span), &(Tok::Constant(Constant::Char(char)), span) => (Atom::Char(char), span),

View file

@ -231,8 +231,6 @@ impl<W: Write> PrettyPrinter<W> {
match spec { match spec {
TypeSpecifier::Void => self.string("void"), TypeSpecifier::Void => self.string("void"),
TypeSpecifier::Char => self.string("char"), TypeSpecifier::Char => self.string("char"),
TypeSpecifier::SChar => self.string("signed char"),
TypeSpecifier::UChar => self.string("unsigned char"),
TypeSpecifier::Integer(int) => { TypeSpecifier::Integer(int) => {
// prefix the unsignedness if desired // prefix the unsignedness if desired
if let IntTySignedness::Unsigned = int.sign { if let IntTySignedness::Unsigned = int.sign {
@ -240,6 +238,8 @@ impl<W: Write> PrettyPrinter<W> {
} }
match int.kind { match int.kind {
IntTyKind::Bool => self.string("_Bool"),
IntTyKind::Char => self.string("char"),
IntTyKind::Short => self.string("short"), IntTyKind::Short => self.string("short"),
IntTyKind::Int => self.string("int"), IntTyKind::Int => self.string("int"),
IntTyKind::Long => self.string("long"), IntTyKind::Long => self.string("long"),
@ -249,7 +249,6 @@ impl<W: Write> PrettyPrinter<W> {
TypeSpecifier::Float => self.string("float"), TypeSpecifier::Float => self.string("float"),
TypeSpecifier::Double => self.string("double"), TypeSpecifier::Double => self.string("double"),
TypeSpecifier::LongDouble => self.string("long double"), TypeSpecifier::LongDouble => self.string("long double"),
TypeSpecifier::Bool => self.string("_Bool"),
} }
} }
@ -316,7 +315,11 @@ impl<W: Write> PrettyPrinter<W> {
Atom::String(string) => { Atom::String(string) => {
self.string("\"")?; self.string("\"")?;
// bare attempt at escpaing // bare attempt at escpaing
self.string(&string.replace('\"', "\\\""))?; self.string(
&std::str::from_utf8(string)
.unwrap_or("<invalid utf-8>")
.replace('\"', "\\\""),
)?;
self.string("\"")?; self.string("\"")?;
Ok(()) Ok(())
} }