mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 08:35:08 +01:00
c what is this
This commit is contained in:
parent
ffd3dad040
commit
54226ad499
11 changed files with 305 additions and 57 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"] }
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ pub enum UnaryKind {
|
|||
pub enum ConstValue {
|
||||
Void,
|
||||
Int(u128),
|
||||
StaticPtr(DefId),
|
||||
}
|
||||
|
||||
impl Func<'_> {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
mod builder;
|
||||
mod typeck;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ type Result<T, E = Error> = std::result::Result<T, E>;
|
|||
struct LoweringCx<'cx> {
|
||||
tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>,
|
||||
layouts: RefCell<FxHashSet<&'cx Layout>>,
|
||||
string_literals: RefCell<FxHashMap<&'cx [u8], DefId>>,
|
||||
arena: &'cx bumpalo::Bump,
|
||||
next_def_id: Cell<DefId>,
|
||||
}
|
||||
|
|
@ -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<FxHashMap<Symbol, VariableInfo<'cx>>>,
|
||||
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::<Result<_, _>>()?;
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
160
analysis/src/lower/typeck.rs
Normal file
160
analysis/src/lower/typeck.rs
Normal 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)
|
||||
}
|
||||
|
|
@ -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<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}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub enum Atom {
|
|||
Ident(Ident),
|
||||
Int(u128),
|
||||
Float(f64),
|
||||
String(String),
|
||||
String(Vec<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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ where
|
|||
fn get_lhs(&mut self) -> Result<Spanned<Expr>> {
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -231,8 +231,6 @@ impl<W: Write> PrettyPrinter<W> {
|
|||
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<W: Write> PrettyPrinter<W> {
|
|||
}
|
||||
|
||||
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<W: Write> PrettyPrinter<W> {
|
|||
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<W: Write> PrettyPrinter<W> {
|
|||
Atom::String(string) => {
|
||||
self.string("\"")?;
|
||||
// bare attempt at escpaing
|
||||
self.string(&string.replace('\"', "\\\""))?;
|
||||
self.string(
|
||||
&std::str::from_utf8(string)
|
||||
.unwrap_or("<invalid utf-8>")
|
||||
.replace('\"', "\\\""),
|
||||
)?;
|
||||
self.string("\"")?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue