mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 16:45:07 +01:00
more stuff
This commit is contained in:
parent
77e18126e7
commit
c84fdfaf3a
12 changed files with 270 additions and 38 deletions
|
|
@ -32,19 +32,21 @@
|
|||
//! ```
|
||||
|
||||
mod pretty;
|
||||
mod validate;
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use parser::{Span, Symbol};
|
||||
pub use pretty::{func_to_string, ir_to_string};
|
||||
use rustc_hash::FxHashMap;
|
||||
pub use validate::validate;
|
||||
|
||||
use crate::ty::Ty;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct DefId(u32);
|
||||
pub struct DefId(pub u32);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TyLayout<'cx> {
|
||||
pub ty: Ty<'cx>,
|
||||
pub layout: &'cx Layout,
|
||||
|
|
@ -160,6 +162,11 @@ pub enum BinKind {
|
|||
Geq,
|
||||
Lt,
|
||||
Leq,
|
||||
Shl,
|
||||
Shr,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -212,3 +219,9 @@ impl Operand {
|
|||
Self::Const(ConstValue::u64(int))
|
||||
}
|
||||
}
|
||||
|
||||
impl Branch {
|
||||
pub fn dummy() -> Self {
|
||||
Branch::Goto(BbIdx(u32::MAX))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt::{Display, Formatter, Result, Write};
|
||||
|
||||
use super::{BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind, BbIdx};
|
||||
use super::{BbIdx, BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind};
|
||||
use crate::ir::Register;
|
||||
|
||||
pub fn ir_to_string(ir: &Ir<'_>) -> String {
|
||||
|
|
@ -21,7 +21,7 @@ pub struct PrettyPrinter<W> {
|
|||
|
||||
impl<W: Write> PrettyPrinter<W> {
|
||||
pub fn ir(&mut self, ir: &Ir<'_>) -> Result {
|
||||
for (_, func) in &ir.funcs {
|
||||
for func in ir.funcs.values() {
|
||||
self.func(func)?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -108,6 +108,11 @@ impl<W: Write> PrettyPrinter<W> {
|
|||
BinKind::Geq => "geq",
|
||||
BinKind::Lt => "gl",
|
||||
BinKind::Leq => "leq",
|
||||
BinKind::Shl => "shl",
|
||||
BinKind::Shr => "shr",
|
||||
BinKind::BitAnd => "bitand",
|
||||
BinKind::BitOr => "bitor",
|
||||
BinKind::BitXor => "bitxor",
|
||||
},
|
||||
print_op(lhs),
|
||||
print_op(rhs)
|
||||
|
|
|
|||
12
analysis/src/ir/validate.rs
Normal file
12
analysis/src/ir/validate.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use super::{Branch, Ir};
|
||||
use crate::ir::BbIdx;
|
||||
|
||||
pub fn validate(ir: &Ir<'_>) {
|
||||
for fun in ir.funcs.values() {
|
||||
for (i, bb) in fun.bbs.iter().enumerate() {
|
||||
if let Branch::Goto(BbIdx(u32::MAX)) = bb.term {
|
||||
panic!("found dummy term in {} in {}", BbIdx::from_usize(i), fun.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,17 @@ mod ty;
|
|||
pub use lower::lower_translation_unit;
|
||||
use parser::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
msg: String,
|
||||
span: Span,
|
||||
notes: Vec<Note>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Note {
|
||||
msg: String,
|
||||
span: Option<Span>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
|
@ -18,6 +26,15 @@ impl Error {
|
|||
Self {
|
||||
msg: msg.into(),
|
||||
span,
|
||||
notes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn note_spanned(mut self, msg: impl Into<String>, span: Span) -> Self {
|
||||
self.notes.push(Note {
|
||||
msg: msg.into(),
|
||||
span: Some(span),
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
mod builder;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use parser::{
|
||||
ast::{self, Atom, DeclAttr, Expr, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier},
|
||||
ast::{
|
||||
self, Atom, DeclAttr, Expr, ExprBinary, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier,
|
||||
},
|
||||
Span, Symbol,
|
||||
};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use self::builder::FuncBuilder;
|
||||
use crate::{
|
||||
ir::{BinKind, Branch, ConstValue, Func, Ir, Layout, Operand, Register, TyLayout},
|
||||
ir::{
|
||||
self, BbIdx, BinKind, Branch, ConstValue, DefId, Func, Ir, Layout, Operand, Register,
|
||||
TyLayout,
|
||||
},
|
||||
ty::{Ty, TyKind},
|
||||
Error,
|
||||
};
|
||||
|
|
@ -22,9 +27,15 @@ struct LoweringCx<'cx> {
|
|||
tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>,
|
||||
layouts: RefCell<FxHashSet<&'cx Layout>>,
|
||||
arena: &'cx bumpalo::Bump,
|
||||
next_def_id: Cell<DefId>,
|
||||
}
|
||||
|
||||
impl<'cx> LoweringCx<'cx> {
|
||||
fn next_def_id(&self) -> DefId {
|
||||
let def_id = self.next_def_id.get();
|
||||
self.next_def_id.set(DefId(def_id.0 + 1));
|
||||
def_id
|
||||
}
|
||||
fn lower_ty(&self, ty: &TypeSpecifier) -> Ty<'cx> {
|
||||
let kind = match ty {
|
||||
TypeSpecifier::Void => TyKind::Void,
|
||||
|
|
@ -94,10 +105,15 @@ pub fn lower_translation_unit<'cx>(
|
|||
arena: &'cx bumpalo::Bump,
|
||||
ast: &TranslationUnit,
|
||||
) -> Result<Ir<'cx>, Error> {
|
||||
let mut lcx = LoweringCx {
|
||||
let lcx = LoweringCx {
|
||||
tys: RefCell::default(),
|
||||
layouts: RefCell::default(),
|
||||
arena,
|
||||
next_def_id: Cell::new(DefId(0)),
|
||||
};
|
||||
|
||||
let mut ir = Ir {
|
||||
funcs: FxHashMap::default(),
|
||||
};
|
||||
|
||||
for (decl, _) in ast {
|
||||
|
|
@ -107,18 +123,21 @@ pub fn lower_translation_unit<'cx>(
|
|||
let decl = def.decl.uwnrap_normal();
|
||||
let body = &def.body;
|
||||
let ret_ty = lcx.lower_ty(&decl.decl_spec.ty);
|
||||
lower_body(
|
||||
&mut lcx,
|
||||
let func = lower_body(
|
||||
&lcx,
|
||||
body,
|
||||
decl.init_declarators[0].1,
|
||||
decl.init_declarators[0].0.declarator.decl.name().0,
|
||||
ret_ty,
|
||||
)?;
|
||||
ir.funcs.insert(lcx.next_def_id(), func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
todo!("building is not really")
|
||||
ir::validate(&ir);
|
||||
|
||||
Ok(ir)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -133,10 +152,12 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
self.scopes.iter().rev().find_map(|s| s.get(&ident))
|
||||
}
|
||||
|
||||
fn lower_body(&mut self, body: &[(Stmt, Span)]) -> Result<()> {
|
||||
fn lower_block(&mut self, body: &[(Stmt, Span)]) -> Result<()> {
|
||||
self.scopes.push(Default::default());
|
||||
for (stmt, stmt_span) in body {
|
||||
self.lower_stmt(stmt, *stmt_span)?;
|
||||
}
|
||||
self.scopes.pop();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -148,9 +169,9 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
let decl_attr = decl.decl_spec.attrs;
|
||||
|
||||
for (var, def_span) in &decl.init_declarators {
|
||||
let tyl = self.lcx.layout_of(ty.clone());
|
||||
let (name, _) = var.declarator.decl.name();
|
||||
let ptr_to = self.build.alloca(&tyl.layout, Some(name), stmt_span);
|
||||
let tyl = self.lcx.layout_of(ty);
|
||||
let (name, name_span) = var.declarator.decl.name();
|
||||
let ptr_to = self.build.alloca(tyl.layout, Some(name), stmt_span);
|
||||
|
||||
let variable_info = VariableInfo {
|
||||
def_span: *def_span,
|
||||
|
|
@ -158,7 +179,14 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
decl_attr,
|
||||
tyl: tyl.clone(),
|
||||
};
|
||||
self.scopes.last_mut().unwrap().insert(name, variable_info);
|
||||
let predeclared = self.scopes.last_mut().unwrap().insert(name, variable_info);
|
||||
if let Some(predeclared) = predeclared {
|
||||
return Err(Error::new(
|
||||
format!("variable {name} has already been declared"),
|
||||
name_span,
|
||||
)
|
||||
.note_spanned("already declared here", predeclared.def_span));
|
||||
}
|
||||
if let Some((init, init_span)) = &var.init {
|
||||
let init = self.lower_expr(init, *init_span)?;
|
||||
self.build.store(ptr_to, init, tyl.layout, *init_span);
|
||||
|
|
@ -166,7 +194,9 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
}
|
||||
}
|
||||
Stmt::Labeled { .. } => todo!("labels are not implemented"),
|
||||
Stmt::Compound(_) => todo!("blocks are not implemented"),
|
||||
Stmt::Compound(block) => {
|
||||
self.lower_block(block)?;
|
||||
}
|
||||
Stmt::If {
|
||||
cond,
|
||||
then: then_body,
|
||||
|
|
@ -181,13 +211,13 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
let cont = self.build.new_block();
|
||||
|
||||
self.build.current_bb = then;
|
||||
self.lower_body(&then_body)?;
|
||||
self.lower_block(then_body)?;
|
||||
self.build.cur_bb_mut().term = Branch::Goto(cont);
|
||||
|
||||
let false_branch = match els {
|
||||
Some((otherwise, els)) => {
|
||||
self.build.current_bb = els;
|
||||
self.lower_body(&otherwise)?;
|
||||
self.lower_block(otherwise)?;
|
||||
self.build.cur_bb_mut().term = Branch::Goto(cont);
|
||||
els
|
||||
}
|
||||
|
|
@ -212,7 +242,13 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
Stmt::Goto(_) => todo!(),
|
||||
Stmt::Continue => todo!(),
|
||||
Stmt::Break => todo!(),
|
||||
Stmt::Return(_) => todo!(),
|
||||
Stmt::Return(expr) => {
|
||||
let ret = match expr {
|
||||
Some(expr) => self.lower_expr(&expr.0, expr.1)?,
|
||||
None => Operand::Const(ConstValue::Void),
|
||||
};
|
||||
self.build.cur_bb_mut().term = Branch::Ret(ret);
|
||||
}
|
||||
Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
|
||||
op: ast::BinaryOp::Assign(assign),
|
||||
lhs,
|
||||
|
|
@ -243,9 +279,43 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
ast::Expr::Atom(Atom::Char(c)) => Ok(Operand::Const(ConstValue::Int((*c).into()))),
|
||||
ast::Expr::Atom(Atom::Int(i)) => Ok(Operand::Const(ConstValue::Int(*i as _))),
|
||||
ast::Expr::Atom(Atom::Float(_)) => todo!("no floats"),
|
||||
ast::Expr::Atom(Atom::Ident(_)) => todo!("no idents"),
|
||||
ast::Expr::Atom(Atom::Ident((ident, ident_span))) => {
|
||||
let Some(var) = self.resolve_ident(*ident) else {
|
||||
return Err(Error::new(format!("cannot find variable {ident}"), *ident_span));
|
||||
};
|
||||
let op = self.build.load(var.tyl, var.ptr_to, span);
|
||||
Ok(Operand::Reg(op))
|
||||
}
|
||||
ast::Expr::Atom(Atom::String(_)) => todo!("no string literals"),
|
||||
ast::Expr::Unary(_) => todo!("no unaries"),
|
||||
ast::Expr::Unary(unary) => {
|
||||
let _rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?;
|
||||
match unary.op {
|
||||
ast::UnaryOp::AddrOf => todo!("addr of"),
|
||||
ast::UnaryOp::Deref => todo!("deref?"),
|
||||
ast::UnaryOp::Plus => todo!("unary plus lol"),
|
||||
ast::UnaryOp::Minus => todo!("unary minus!"),
|
||||
ast::UnaryOp::Tilde => todo!("tilde"),
|
||||
ast::UnaryOp::Bang => todo!("bang bang bang"),
|
||||
}
|
||||
}
|
||||
ast::Expr::Binary(ExprBinary {
|
||||
lhs,
|
||||
rhs,
|
||||
op: ast::BinaryOp::Assign(assign),
|
||||
}) => {
|
||||
if assign.is_some() {
|
||||
todo!("assign operation");
|
||||
}
|
||||
let rhs = self.lower_expr(&rhs.0, rhs.1)?;
|
||||
let (Expr::Atom(ast::Atom::Ident((ident, ident_span))), _) = **lhs else {
|
||||
todo!("complex assignments")
|
||||
};
|
||||
let Some(var) = self.resolve_ident(ident) else {
|
||||
return Err(Error::new(format!("cannot find variable {ident}"), ident_span));
|
||||
};
|
||||
self.build.store(var.ptr_to, rhs, var.tyl.layout, span);
|
||||
Ok(rhs)
|
||||
}
|
||||
ast::Expr::Binary(binary) => {
|
||||
let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?;
|
||||
let rhs = self.lower_expr(&binary.rhs.0, binary.rhs.1)?;
|
||||
|
|
@ -255,11 +325,11 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
ast::BinaryOp::Arith(ast::ArithOpKind::Mod) => BinKind::Mod,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::Add) => BinKind::Add,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::Sub) => BinKind::Sub,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::Shl) => todo!("shl"),
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => todo!("shr"),
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => todo!("&"),
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => todo!("^"),
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => todo!("|"),
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::Shl) => BinKind::Shl,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => BinKind::Shr,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => BinKind::BitAnd,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => BinKind::BitXor,
|
||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => BinKind::BitOr,
|
||||
ast::BinaryOp::LogicalAnd => todo!("no logical or"),
|
||||
ast::BinaryOp::LogicalOr => todo!("no logical and"),
|
||||
ast::BinaryOp::Comparison(ast::ComparisonKind::Lt) => BinKind::Lt,
|
||||
|
|
@ -268,9 +338,12 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
|||
ast::BinaryOp::Comparison(ast::ComparisonKind::GtEq) => BinKind::Geq,
|
||||
ast::BinaryOp::Comparison(ast::ComparisonKind::Eq) => BinKind::Eq,
|
||||
ast::BinaryOp::Comparison(ast::ComparisonKind::Neq) => BinKind::Neq,
|
||||
ast::BinaryOp::Comma => todo!("no comma"),
|
||||
ast::BinaryOp::Comma => {
|
||||
// Discard the lhs, evaluate to the rhs.
|
||||
return Ok(rhs);
|
||||
}
|
||||
ast::BinaryOp::Index => todo!("no index"),
|
||||
ast::BinaryOp::Assign(_) => todo!("no assign"),
|
||||
ast::BinaryOp::Assign(_) => unreachable!("assign handled above"),
|
||||
};
|
||||
|
||||
let reg = self.build.binary(
|
||||
|
|
@ -329,12 +402,16 @@ fn lower_body<'cx>(
|
|||
ret_ty: Ty<'cx>,
|
||||
) -> Result<Func<'cx>, Error> {
|
||||
let mut cx = FnLoweringCtxt {
|
||||
scopes: vec![FxHashMap::default()],
|
||||
scopes: vec![],
|
||||
build: FuncBuilder::new(name, def_span, ret_ty, lcx),
|
||||
lcx,
|
||||
};
|
||||
|
||||
cx.lower_body(body)?;
|
||||
cx.lower_block(body)?;
|
||||
|
||||
if let Branch::Goto(BbIdx(u32::MAX)) = cx.build.cur_bb_mut().term {
|
||||
cx.build.cur_bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
|
||||
}
|
||||
|
||||
Ok(cx.build.finish())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
|
|||
regs: Vec::new(),
|
||||
bbs: vec![BasicBlock {
|
||||
statements: Vec::new(),
|
||||
term: Branch::Goto(BbIdx(0)),
|
||||
term: Branch::dummy(),
|
||||
}],
|
||||
name,
|
||||
def_span,
|
||||
|
|
@ -134,14 +134,12 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
|
|||
pub fn new_block(&mut self) -> BbIdx {
|
||||
self.ir.bbs.push(BasicBlock {
|
||||
statements: vec![],
|
||||
term: Branch::Goto(BbIdx(0)),
|
||||
term: Branch::dummy(),
|
||||
});
|
||||
BbIdx::from_usize(self.ir.bbs.len() - 1)
|
||||
}
|
||||
|
||||
pub fn finish(mut self) -> Func<'cx> {
|
||||
self.cur_bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
|
||||
|
||||
pub fn finish(self) -> Func<'cx> {
|
||||
println!("{}", ir::func_to_string(&self.ir));
|
||||
|
||||
self.ir
|
||||
|
|
|
|||
|
|
@ -484,6 +484,16 @@ where
|
|||
return self.if_statement();
|
||||
}
|
||||
|
||||
if let Some((_, span)) = eat!(self, Tok::Kw(Kw::Return)) {
|
||||
if let Some((_, semi_span)) = eat!(self, Tok::Punct(P::Semicolon)) {
|
||||
return Ok((Stmt::Return(None), span.extend(semi_span)));
|
||||
} else {
|
||||
let expr = self.expr()?;
|
||||
let semi_span = expect!(self, Tok::Punct(P::Semicolon));
|
||||
return Ok((Stmt::Return(Some(expr)), span.extend(semi_span)));
|
||||
}
|
||||
}
|
||||
|
||||
// it must be an expression stmt
|
||||
let (expr, span) = self.expr()?;
|
||||
expect!(self, Tok::Punct(P::Semicolon));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
source: parser/src/parser/tests.rs
|
||||
expression: "(parsed_pretty, pretty_printed_source)"
|
||||
---
|
||||
(
|
||||
Ok([
|
||||
(
|
||||
FunctionDef(FunctionDef {
|
||||
decl: Normal(NormalDecl {
|
||||
decl_spec: DeclSpec {
|
||||
ty: Integer(IntTy { sign: Signed, kind: Int }),
|
||||
attrs: "(empty)",
|
||||
},
|
||||
init_declarators: [
|
||||
(
|
||||
InitDecl {
|
||||
declarator: Declarator {
|
||||
decl: WithParams {
|
||||
ident: (main, 5..9),
|
||||
params: [],
|
||||
},
|
||||
pointer: false,
|
||||
},
|
||||
init: None,
|
||||
},
|
||||
5..9,
|
||||
),
|
||||
],
|
||||
}),
|
||||
body: [(Return(None), 18..25)],
|
||||
}),
|
||||
1..27,
|
||||
),
|
||||
]),
|
||||
"int main() {\n return\n}\n",
|
||||
)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
source: parser/src/parser/tests.rs
|
||||
expression: "(parsed_pretty, pretty_printed_source)"
|
||||
---
|
||||
(
|
||||
Ok([
|
||||
(
|
||||
FunctionDef(FunctionDef {
|
||||
decl: Normal(NormalDecl {
|
||||
decl_spec: DeclSpec {
|
||||
ty: Integer(IntTy { sign: Signed, kind: Int }),
|
||||
attrs: "(empty)",
|
||||
},
|
||||
init_declarators: [
|
||||
(
|
||||
InitDecl {
|
||||
declarator: Declarator {
|
||||
decl: WithParams {
|
||||
ident: (main, 5..9),
|
||||
params: [],
|
||||
},
|
||||
pointer: false,
|
||||
},
|
||||
init: None,
|
||||
},
|
||||
5..9,
|
||||
),
|
||||
],
|
||||
}),
|
||||
body: [(Return(Some((Atom(Int(0)), 25..26))), 18..27)],
|
||||
}),
|
||||
1..29,
|
||||
),
|
||||
]),
|
||||
"int main() {\n return 0\n}\n",
|
||||
)
|
||||
|
|
@ -202,3 +202,25 @@ int main() {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_empty() {
|
||||
parse_test!(
|
||||
r#"
|
||||
int main() {
|
||||
return;
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_expr() {
|
||||
parse_test!(
|
||||
r#"
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ impl CLexExt for u8 {
|
|||
}
|
||||
|
||||
fn is_c_identifier_digit(&self) -> bool {
|
||||
matches!(self, b'0'..=b'9')
|
||||
self.is_ascii_digit()
|
||||
}
|
||||
|
||||
fn is_c_whitespace(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -17,5 +17,11 @@ fn main() {
|
|||
|
||||
let arena = bumpalo::Bump::new();
|
||||
|
||||
let _ = analysis::lower_translation_unit(&arena, &ast);
|
||||
let ir = analysis::lower_translation_unit(&arena, &ast);
|
||||
match ir {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
dbg!(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue