Format and stuff

This commit is contained in:
Janggun Lee
2025-01-23 19:11:43 +09:00
parent fcb6ca2538
commit 00c64a5297
22 changed files with 201 additions and 163 deletions

View File

@@ -1,7 +1,7 @@
use clap::Parser;
use std::path::Path; use std::path::Path;
use clap::Parser;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[clap(name = "fuzz", version, author, about)] #[clap(name = "fuzz", version, author, about)]
struct FuzzCli { struct FuzzCli {

View File

@@ -1,18 +1,16 @@
use clap::Parser;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io::Write; use std::io::Write;
use std::os::unix::io::{FromRawFd, IntoRawFd}; use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::path::Path; use std::path::Path;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use lang_c::ast::TranslationUnit; use clap::Parser;
use tempfile::tempdir;
use kecc::{ use kecc::{
ir, ok_or_exit, write, Asmgen, Deadcode, Gvn, IrParse, IrVisualizer, Irgen, Mem2reg, Optimize, ir, ok_or_exit, write, Asmgen, Deadcode, Gvn, IrParse, IrVisualizer, Irgen, Mem2reg, Optimize,
Parse, SimplifyCfg, Translate, O1, Parse, SimplifyCfg, Translate, O1,
}; };
use lang_c::ast::TranslationUnit;
use tempfile::tempdir;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[clap(name = "kecc", version, author, about)] #[clap(name = "kecc", version, author, about)]

View File

@@ -1,10 +1,10 @@
mod write_asm; mod write_asm;
use crate::ir;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use crate::ir;
/// An assembly file. /// An assembly file.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Asm { pub struct Asm {

View File

@@ -1,15 +1,24 @@
use crate::asm; use std::collections::{HashMap, HashSet, VecDeque};
use crate::ir;
use crate::Translate;
#[derive(Default, Clone, Copy, Debug)] use lang_c::ast;
use crate::ir::HasDtype;
use crate::{asm, ir, Translate};
#[derive(Debug)]
pub struct Asmgen {} pub struct Asmgen {}
impl Default for Asmgen {
fn default() -> Self {
todo!()
}
}
impl Translate<ir::TranslationUnit> for Asmgen { impl Translate<ir::TranslationUnit> for Asmgen {
type Target = asm::Asm; type Target = asm::Asm;
type Error = (); type Error = ();
fn translate(&mut self, _source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> { fn translate(&mut self, source: &ir::TranslationUnit) -> Result<Self::Target, Self::Error> {
todo!("Homework: Assembly Generation") todo!()
} }
} }

View File

@@ -8,14 +8,14 @@ use lang_c::span::Node;
use crate::utils::AssertSupported; use crate::utils::AssertSupported;
use crate::Translate; use crate::Translate;
/// TODO(document) /// Parse Error
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
ParseError(ParseError), ParseError(ParseError),
Unsupported, Unsupported,
} }
/// TODO(document) /// C file Parser.
#[derive(Default, Clone, Copy, Debug)] #[derive(Default, Clone, Copy, Debug)]
pub struct Parse; pub struct Parse;

View File

@@ -1,9 +1,8 @@
use std::io::{Result, Write};
use lang_c::ast::*; use lang_c::ast::*;
use lang_c::span::Node; use lang_c::span::Node;
use core::ops::Deref;
use std::io::{Result, Write};
use crate::write_base::*; use crate::write_base::*;
impl<T: WriteLine> WriteLine for Node<T> { impl<T: WriteLine> WriteLine for Node<T> {
@@ -19,8 +18,8 @@ impl<T: WriteString> WriteString for Node<T> {
} }
impl WriteLine for TranslationUnit { impl WriteLine for TranslationUnit {
fn write_line(&self, _indent: usize, _write: &mut dyn Write) -> Result<()> { fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()> {
todo!("Homework: write C") todo!()
} }
} }

View File

@@ -1,13 +1,13 @@
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::ops::Deref; use core::ops::Deref;
use lang_c::ast;
use lang_c::span::Node;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::hash::Hash; use std::hash::Hash;
use thiserror::Error;
use itertools::izip; use itertools::izip;
use lang_c::ast;
use lang_c::span::Node;
use thiserror::Error;
use crate::ir::*; use crate::ir::*;
use crate::some_or; use crate::some_or;

View File

@@ -1,11 +1,9 @@
use core::fmt; use core::{fmt, iter, mem};
use core::iter;
use core::mem;
use ordered_float::OrderedFloat;
use std::collections::HashMap; use std::collections::HashMap;
use thiserror::Error;
use itertools::izip; use itertools::izip;
use ordered_float::OrderedFloat;
use thiserror::Error;
use crate::ir::*; use crate::ir::*;
use crate::*; use crate::*;
@@ -410,10 +408,12 @@ impl<'i> StackFrame<'i> {
} }
mod calculator { mod calculator {
use std::cmp::Ordering;
use lang_c::ast;
use super::Value; use super::Value;
use crate::ir::*; use crate::ir::*;
use lang_c::ast;
use std::cmp::Ordering;
fn calculate_integer_binary_operator_expression( fn calculate_integer_binary_operator_expression(
op: &ast::BinaryOperator, op: &ast::BinaryOperator,

View File

@@ -10,15 +10,15 @@ mod write_ir;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use hexf_parse::{parse_hexf32, parse_hexf64};
use itertools::Itertools;
use lang_c::ast;
use ordered_float::OrderedFloat;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
pub use dtype::{Dtype, DtypeError, HasDtype}; pub use dtype::{Dtype, DtypeError, HasDtype};
use hexf_parse::{parse_hexf32, parse_hexf64};
pub use interp::{interp, Value}; pub use interp::{interp, Value};
use itertools::Itertools;
use lang_c::ast;
use ordered_float::OrderedFloat;
pub use parse::Parse; pub use parse::Parse;
pub use visualize::Visualizer; pub use visualize::Visualizer;

View File

@@ -5,8 +5,7 @@ use lang_c::*;
use crate::ir::*; use crate::ir::*;
use crate::utils::AssertSupported; use crate::utils::AssertSupported;
use crate::Translate; use crate::{Translate, *};
use crate::*;
peg::parser! { peg::parser! {
grammar ir_parse() for str { grammar ir_parse() for str {

View File

@@ -3,8 +3,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::ir::*; use crate::ir::*;
use crate::some_or; use crate::{some_or, Translate};
use crate::Translate;
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Visualizer { pub struct Visualizer {

View File

@@ -1,7 +1,6 @@
use crate::ir::*;
use std::io::{Result, Write}; use std::io::{Result, Write};
use crate::ir::*;
use crate::write_base::*; use crate::write_base::*;
use crate::*; use crate::*;

View File

@@ -34,23 +34,22 @@
//! [irgen-stmt-1]: https://youtu.be/jFahkyxm994 //! [irgen-stmt-1]: https://youtu.be/jFahkyxm994
//! [irgen-stmt-2]: https://youtu.be/UkaXaNw462U //! [irgen-stmt-2]: https://youtu.be/UkaXaNw462U
//! [github-qna-irgen]: https://github.com/kaist-cp/cs420/labels/homework%20-%20irgen //! [github-qna-irgen]: https://github.com/kaist-cp/cs420/labels/homework%20-%20irgen
#![allow(dead_code)] use core::cmp::Ordering;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::{fmt, mem};
use core::mem;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::ops::Deref; use std::ops::Deref;
use itertools::izip;
use lang_c::ast::*; use lang_c::ast::*;
use lang_c::driver::Parse; use lang_c::driver::Parse;
use lang_c::span::Node; use lang_c::span::Node;
use thiserror::Error; use thiserror::Error;
use crate::ir::{DtypeError, HasDtype, Named}; use crate::ir::{DtypeError, HasDtype, Named};
use crate::write_base::WriteString;
use crate::*; use crate::*;
use itertools::izip;
#[derive(Debug)] #[derive(Debug)]
pub struct IrgenError { pub struct IrgenError {
pub code: String, pub code: String,
@@ -69,6 +68,9 @@ impl fmt::Display for IrgenError {
} }
} }
/// Error format when a compiler error happens.
///
/// Feel free to add more kinds of errors.
#[derive(Debug, PartialEq, Eq, Error)] #[derive(Debug, PartialEq, Eq, Error)]
pub enum IrgenErrorMessage { pub enum IrgenErrorMessage {
/// For uncommon error /// For uncommon error
@@ -89,11 +91,17 @@ pub enum IrgenErrorMessage {
RequireLvalue { message: String }, RequireLvalue { message: String },
} }
/// A C file going through IR generation.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Irgen { pub struct Irgen {
/// Declarations made in the C file (e.g, global variables and functions)
decls: BTreeMap<String, ir::Declaration>, decls: BTreeMap<String, ir::Declaration>,
/// Type definitions made in the C file (e.g, typedef my_type = int;)
typedefs: HashMap<String, ir::Dtype>, typedefs: HashMap<String, ir::Dtype>,
/// Structs defined in the C file,
// TODO: explain how to use this.
structs: HashMap<String, Option<ir::Dtype>>, structs: HashMap<String, Option<ir::Dtype>>,
/// Temporary counter for anonymous structs. One should not need to use this any more.
struct_tempid_counter: usize, struct_tempid_counter: usize,
} }
@@ -112,14 +120,14 @@ impl Translate<TranslationUnit> for Irgen {
fn translate(&mut self, source: &TranslationUnit) -> Result<Self::Target, Self::Error> { fn translate(&mut self, source: &TranslationUnit) -> Result<Self::Target, Self::Error> {
for ext_decl in &source.0 { for ext_decl in &source.0 {
match ext_decl.node { match &ext_decl.node {
ExternalDeclaration::Declaration(ref var) => { ExternalDeclaration::Declaration(var) => {
self.add_declaration(&var.node)?; self.add_declaration(&var.node)?;
} }
ExternalDeclaration::StaticAssert(_) => { ExternalDeclaration::StaticAssert(_) => {
panic!("ExternalDeclaration::StaticAssert is unsupported") panic!("ExternalDeclaration::StaticAssert is unsupported")
} }
ExternalDeclaration::FunctionDefinition(ref func) => { ExternalDeclaration::FunctionDefinition(func) => {
self.add_function_definition(&func.node)?; self.add_function_definition(&func.node)?;
} }
} }
@@ -513,9 +521,10 @@ impl IrgenFunc<'_> {
} }
/// Create a new allocation with type given by `alloc`. /// Create a new allocation with type given by `alloc`.
fn insert_alloc(&mut self, alloc: Named<ir::Dtype>) -> usize { fn insert_alloc(&mut self, alloc: Named<ir::Dtype>) -> ir::RegisterId {
self.allocations.push(alloc); self.allocations.push(alloc);
self.allocations.len() - 1 let id = self.allocations.len() - 1;
ir::RegisterId::local(id)
} }
/// Insert a new block `context` with exit instruction `exit`. /// Insert a new block `context` with exit instruction `exit`.
@@ -551,6 +560,7 @@ impl IrgenFunc<'_> {
/// Panics if there are no scopes to exit, i.e, the function has a unmatched `}`. /// Panics if there are no scopes to exit, i.e, the function has a unmatched `}`.
fn exit_scope(&mut self) { fn exit_scope(&mut self) {
let _unused = self.symbol_table.pop().unwrap(); let _unused = self.symbol_table.pop().unwrap();
debug_assert!(!self.symbol_table.is_empty())
} }
/// Inserts `var` with `value` to the current symbol table. /// Inserts `var` with `value` to the current symbol table.
@@ -576,15 +586,15 @@ impl IrgenFunc<'_> {
/// `bid_continue` and break block `bid_break`. /// `bid_continue` and break block `bid_break`.
fn translate_stmt( fn translate_stmt(
&mut self, &mut self,
_stmt: &Statement, stmt: &Statement,
_context: &mut Context, context: &mut Context,
_bid_continue: Option<ir::BlockId>, bid_continue: Option<ir::BlockId>,
_bid_break: Option<ir::BlockId>, bid_break: Option<ir::BlockId>,
) -> Result<(), IrgenError> { ) -> Result<(), IrgenError> {
todo!("Homework: IR Generation") todo!()
} }
/// Translate parameter declaration of the functions to IR. /// Translate initial parameter declarations of the functions to IR.
/// ///
/// For example, given the following C function from [`foo.c`][foo]: /// For example, given the following C function from [`foo.c`][foo]:
/// ///
@@ -610,9 +620,11 @@ impl IrgenFunc<'_> {
/// %b0:p0:i32:x /// %b0:p0:i32:x
/// %b0:p1:i32:y /// %b0:p1:i32:y
/// %b0:p2:i32:z /// %b0:p2:i32:z
/// ...
/// ``` /// ```
/// ///
/// With the following arguments : /// With the following arguments :
///
/// ```ignore /// ```ignore
/// signature = FunctionSignature { ret: ir::INT, params: vec![ir::INT, ir::INT, ir::INT] } /// signature = FunctionSignature { ret: ir::INT, params: vec![ir::INT, ir::INT, ir::INT] }
/// bid_init = 0 /// bid_init = 0
@@ -638,6 +650,7 @@ impl IrgenFunc<'_> {
/// %b0:i0:unit = store %b0:p0:i32 %l0:i32* /// %b0:i0:unit = store %b0:p0:i32 %l0:i32*
/// %b0:i1:unit = store %b0:p1:i32 %l1:i32* /// %b0:i1:unit = store %b0:p1:i32 %l1:i32*
/// %b0:i2:unit = store %b0:p2:i32 %l2:i32* /// %b0:i2:unit = store %b0:p2:i32 %l2:i32*
/// ...
/// ``` /// ```
/// ///
/// In particular, note that it is added to the local allocation list and store them to the /// In particular, note that it is added to the local allocation list and store them to the
@@ -649,12 +662,12 @@ impl IrgenFunc<'_> {
/// [foo]: https://github.com/kaist-cp/kecc-public/blob/main/examples/c/foo.c /// [foo]: https://github.com/kaist-cp/kecc-public/blob/main/examples/c/foo.c
fn translate_parameter_decl( fn translate_parameter_decl(
&mut self, &mut self,
_signature: &ir::FunctionSignature, signature: &ir::FunctionSignature,
_bid_init: ir::BlockId, bid_init: ir::BlockId,
_name_of_params: &[String], name_of_params: &[String],
_context: &mut Context, context: &mut Context,
) -> Result<(), IrgenErrorMessage> { ) -> Result<(), IrgenErrorMessage> {
todo!("Homework: IR Generation") todo!()
} }
} }

View File

@@ -5,45 +5,50 @@
#![deny(warnings)] #![deny(warnings)]
// Tries to deny all rustc allow lints. // Tries to deny all rustc allow lints.
// <https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html> // <https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html>
#![deny(absolute_paths_not_starting_with_crate)] #![deny(
// Old, historical lint absolute_paths_not_starting_with_crate,
// #![deny(box_pointers)] // Old, historical lint
#![deny(elided_lifetimes_in_paths)] // box_pointers,
#![deny(explicit_outlives_requirements)] elided_lifetimes_in_paths,
#![deny(keyword_idents)] explicit_outlives_requirements,
#![deny(let_underscore_drop)] keyword_idents,
#![deny(macro_use_extern_crate)] let_underscore_drop,
#![deny(meta_variable_misuse)] macro_use_extern_crate,
#![deny(missing_abi)] meta_variable_misuse,
#![deny(missing_copy_implementations)] missing_abi,
#![deny(missing_debug_implementations)] // Most stuff are reasonably not copy.
// TODO // missing_copy_implementations,
// #![deny(missing_docs)] missing_debug_implementations,
#![deny(non_ascii_idents)] // TODO
#![deny(noop_method_call)] // missing_docs
#![deny(rust_2021_incompatible_closure_captures)] non_ascii_idents,
#![deny(rust_2021_incompatible_or_patterns)] noop_method_call,
#![deny(rust_2021_prefixes_incompatible_syntax)] rust_2021_incompatible_closure_captures,
#![deny(rust_2021_prelude_collisions)] rust_2021_incompatible_or_patterns,
// Necessary for skeleton code. rust_2021_prefixes_incompatible_syntax,
// #![deny(single_use_lifetimes)] rust_2021_prelude_collisions,
#![deny(trivial_casts)] // Necessary for skeleton code.
#![deny(trivial_numeric_casts)] // single_use_lifetimes,
// Necessary for skeleton code. trivial_casts,
// #![deny(unreachable_pub)] trivial_numeric_casts,
#![deny(unsafe_code)] // Necessary for skeleton code.
#![deny(unsafe_op_in_unsafe_fn)] // unreachable_pub,
#![deny(unstable_features)] unsafe_code,
// Necessary for `build-bin` trick. unsafe_op_in_unsafe_fn,
// #![deny(unused_crate_dependencies)] unstable_features,
#![deny(unused_extern_crates)] // Necessary for `build-bin` trick.
#![deny(unused_import_braces)] // unused_crate_dependencies,
#![deny(unused_lifetimes)] unused_extern_crates,
#![deny(unused_macro_rules)] unused_import_braces,
#![deny(unused_qualifications)] unused_lifetimes,
#![deny(unused_results)] unused_macro_rules,
// Allowed for more flexible variants. unused_qualifications,
// #![deny(variant_size_differences)] unused_results,
// Allowed for more flexible variants.
// variant_size_differences,
)]
// For skeleton code.
#![allow(unused)]
mod tests; mod tests;
mod utils; mod utils;
@@ -57,17 +62,14 @@ mod asmgen;
mod irgen; mod irgen;
mod opt; mod opt;
pub use tests::*;
pub use utils::*;
pub use write_base::write;
pub use c::Parse;
pub use ir::Parse as IrParse;
pub use ir::Visualizer as IrVisualizer;
pub use asmgen::Asmgen; pub use asmgen::Asmgen;
pub use c::Parse;
pub use ir::{Parse as IrParse, Visualizer as IrVisualizer};
pub use irgen::Irgen; pub use irgen::Irgen;
pub use opt::{ pub use opt::{
Deadcode, FunctionPass, Gvn, Mem2reg, Optimize, Repeat, SimplifyCfg, SimplifyCfgConstProp, Deadcode, FunctionPass, Gvn, Mem2reg, Optimize, Repeat, SimplifyCfg, SimplifyCfgConstProp,
SimplifyCfgEmpty, SimplifyCfgMerge, SimplifyCfgReach, O0, O1, SimplifyCfgEmpty, SimplifyCfgMerge, SimplifyCfgReach, O0, O1,
}; };
pub use tests::*;
pub use utils::*;
pub use write_base::write;

View File

@@ -1,6 +1,9 @@
use core::ops::Deref;
use std::collections::{HashMap, HashSet};
use crate::ir::*; use crate::ir::*;
use crate::opt::FunctionPass; use crate::opt::opt_utils::*;
use crate::*; use crate::opt::*;
pub type Deadcode = FunctionPass<Repeat<DeadcodeInner>>; pub type Deadcode = FunctionPass<Repeat<DeadcodeInner>>;
@@ -8,7 +11,7 @@ pub type Deadcode = FunctionPass<Repeat<DeadcodeInner>>;
pub struct DeadcodeInner {} pub struct DeadcodeInner {}
impl Optimize<FunctionDefinition> for DeadcodeInner { impl Optimize<FunctionDefinition> for DeadcodeInner {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Deadcode Elimination") todo!()
} }
} }

View File

@@ -1,13 +1,20 @@
use crate::opt::FunctionPass; use core::ops::Deref;
use crate::*; use std::collections::HashMap;
use itertools::izip;
use lang_c::ast;
use crate::ir::*;
use crate::opt::opt_utils::*;
use crate::opt::*;
pub type Gvn = FunctionPass<GvnInner>; pub type Gvn = FunctionPass<GvnInner>;
#[derive(Default, Clone, Copy, Debug)] #[derive(Default, Clone, Copy, Debug)]
pub struct GvnInner {} pub struct GvnInner {}
impl Optimize<ir::FunctionDefinition> for GvnInner { impl Optimize<FunctionDefinition> for GvnInner {
fn optimize(&mut self, _code: &mut ir::FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Global Variable Numbering") todo!()
} }
} }

View File

@@ -1,6 +1,9 @@
use core::ops::{Deref, DerefMut};
use std::collections::{BTreeMap, HashMap, HashSet};
use crate::ir::*; use crate::ir::*;
use crate::opt::FunctionPass; use crate::opt::opt_utils::*;
use crate::*; use crate::opt::*;
pub type Mem2reg = FunctionPass<Mem2regInner>; pub type Mem2reg = FunctionPass<Mem2regInner>;
@@ -8,7 +11,7 @@ pub type Mem2reg = FunctionPass<Mem2regInner>;
pub struct Mem2regInner {} pub struct Mem2regInner {}
impl Optimize<FunctionDefinition> for Mem2regInner { impl Optimize<FunctionDefinition> for Mem2regInner {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Register Promotion") todo!()
} }
} }

View File

@@ -1,5 +1,5 @@
//! Utilities for implementing optimizations. //! Utilities for implementing optimizations.
//! //!
//! You can add here utilities commonly used in the implementation of multiple optimizations. //! You can freely add utilities commonly used in the implementation of multiple optimizations here.
#![allow(dead_code)] #![allow(dead_code)]

View File

@@ -1,6 +1,11 @@
use std::collections::{HashMap, HashSet};
use std::ops::Deref;
use itertools::izip;
use crate::ir::*; use crate::ir::*;
use crate::opt::FunctionPass; use crate::opt::opt_utils::*;
use crate::*; use crate::opt::*;
pub type SimplifyCfg = FunctionPass< pub type SimplifyCfg = FunctionPass<
Repeat<( Repeat<(
@@ -26,25 +31,25 @@ pub struct SimplifyCfgMerge {}
pub struct SimplifyCfgEmpty {} pub struct SimplifyCfgEmpty {}
impl Optimize<FunctionDefinition> for SimplifyCfgConstProp { impl Optimize<FunctionDefinition> for SimplifyCfgConstProp {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG") todo!()
} }
} }
impl Optimize<FunctionDefinition> for SimplifyCfgReach { impl Optimize<FunctionDefinition> for SimplifyCfgReach {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG") todo!()
} }
} }
impl Optimize<FunctionDefinition> for SimplifyCfgMerge { impl Optimize<FunctionDefinition> for SimplifyCfgMerge {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG") todo!()
} }
} }
impl Optimize<FunctionDefinition> for SimplifyCfgEmpty { impl Optimize<FunctionDefinition> for SimplifyCfgEmpty {
fn optimize(&mut self, _code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!("Homework: Simplify CFG") todo!()
} }
} }

View File

@@ -1,9 +1,10 @@
use lang_c::*;
use rand::Rng;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{stderr, Read, Write}; use std::io::{stderr, Read, Write};
use std::path::Path; use std::path::Path;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use lang_c::*;
use rand::Rng;
use tempfile::tempdir; use tempfile::tempdir;
use wait_timeout::ChildExt; use wait_timeout::ChildExt;

View File

@@ -1,11 +1,7 @@
use itertools::izip;
use core::ops::Deref;
#[macro_export] #[macro_export]
/// Ok or executing the given expression. /// Ok or executing the given expression.
macro_rules! ok_or { macro_rules! ok_or {
($e:expr, $err:expr) => {{ ($e:expr_2021, $err:expr_2021) => {{
match $e { match $e {
Ok(r) => r, Ok(r) => r,
Err(_) => $err, Err(_) => $err,
@@ -16,7 +12,7 @@ macro_rules! ok_or {
#[macro_export] #[macro_export]
/// Some or executing the given expression. /// Some or executing the given expression.
macro_rules! some_or { macro_rules! some_or {
($e:expr, $err:expr) => {{ ($e:expr_2021, $err:expr_2021) => {{
match $e { match $e {
Some(r) => r, Some(r) => r,
None => $err, None => $err,
@@ -27,7 +23,7 @@ macro_rules! some_or {
#[macro_export] #[macro_export]
/// Ok or exiting the process. /// Ok or exiting the process.
macro_rules! ok_or_exit { macro_rules! ok_or_exit {
($e:expr, $code:expr) => {{ ($e:expr_2021, $code:expr_2021) => {{
match $e { match $e {
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => {
@@ -41,7 +37,7 @@ macro_rules! ok_or_exit {
#[macro_export] #[macro_export]
/// Ok or exiting the process. /// Ok or exiting the process.
macro_rules! some_or_exit { macro_rules! some_or_exit {
($e:expr, $code:expr) => {{ ($e:expr_2021, $code:expr_2021) => {{
match $e { match $e {
Some(r) => r, Some(r) => r,
None => ::std::process::exit($code), None => ::std::process::exit($code),
@@ -49,33 +45,41 @@ macro_rules! some_or_exit {
}}; }};
} }
/// TODO(document) /// Translates `S` to [`Translate::Target`].
// TODO: Should this be in utils?
pub trait Translate<S> { pub trait Translate<S> {
/// TODO(document) /// The type to translate to.
type Target; type Target;
/// TODO(document) /// The error type.
type Error; type Error;
/// TODO(document) /// Translate `source` to `Self::Target`.
fn translate(&mut self, source: &S) -> Result<Self::Target, Self::Error>; fn translate(&mut self, source: &S) -> Result<Self::Target, Self::Error>;
} }
/// TODO(document) /// Trait to check if a type can be translated.
pub trait AssertSupported { pub trait AssertSupported {
/// TODO(document) /// Assert that the type can be translated.
///
/// # Panics
///
/// Panics if the type can't be translated.
// TODO: should return a boolean.
fn assert_supported(&self); fn assert_supported(&self);
} }
/// TODO(document) /// Essentially the same as [`PartialEq`].
///
/// Exists to check equaility on some foreign types.
pub trait IsEquiv { pub trait IsEquiv {
/// TODO(document) /// See [`PartialEq::eq`].
fn is_equiv(&self, other: &Self) -> bool; fn is_equiv(&self, other: &Self) -> bool;
} }
impl<T: IsEquiv> IsEquiv for Box<T> { impl<T: IsEquiv> IsEquiv for Box<T> {
fn is_equiv(&self, other: &Self) -> bool { fn is_equiv(&self, other: &Self) -> bool {
self.deref().is_equiv(other.deref()) (**self).is_equiv(&**other)
} }
} }
@@ -97,6 +101,6 @@ impl<T: IsEquiv> IsEquiv for Option<T> {
impl<T: IsEquiv> IsEquiv for Vec<T> { impl<T: IsEquiv> IsEquiv for Vec<T> {
fn is_equiv(&self, other: &Self) -> bool { fn is_equiv(&self, other: &Self) -> bool {
self.len() == other.len() && izip!(self, other).all(|(lhs, rhs)| lhs.is_equiv(rhs)) self.len() == other.len() && self.iter().zip(other).all(|(lhs, rhs)| lhs.is_equiv(rhs))
} }
} }

View File

@@ -1,7 +1,6 @@
use std::io::{Result, Write}; use std::io::{Result, Write};
/// Write `indent` number of double spaces to `write`. /// Write `indent` number of double spaces to `write`.
#[inline]
pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> { pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
write!(write, "{}", " ".repeat(indent)) write!(write, "{}", " ".repeat(indent))
} }
@@ -9,24 +8,21 @@ pub fn write_indent(indent: usize, write: &mut dyn Write) -> Result<()> {
/// A trait for writing a type to a `Write` stream with a new line. /// A trait for writing a type to a `Write` stream with a new line.
pub trait WriteLine { pub trait WriteLine {
/// Write `self` to `write`, starting at `indent` number of double spaces, with a newline at the /// Write `self` to `write`, starting at `indent` number of double spaces, with a newline at the
/// ned. /// end.
fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()>; fn write_line(&self, indent: usize, write: &mut dyn Write) -> Result<()>;
} }
/// Format types to a String. /// Essentially the same as [`ToString`].
/// ///
/// Most cases, `fmt::Display` is used to format a type to a string. However, in some cases, we /// Exists to make some foreign types into a string.
/// can't implement `fmt::Display` for a type as it is defined in another crate. In such cases, we
/// can implement this trait to format the type to a string.
pub trait WriteString { pub trait WriteString {
/// Change a type into a String. /// See [`ToString::to_string`].
fn write_string(&self) -> String; fn write_string(&self) -> String;
} }
impl<T: WriteString> WriteString for Box<T> { impl<T: WriteString> WriteString for Box<T> {
fn write_string(&self) -> String { fn write_string(&self) -> String {
use core::ops::Deref; (**self).write_string()
self.deref().write_string()
} }
} }
@@ -36,6 +32,7 @@ impl<T: WriteString> WriteString for &T {
} }
} }
// Might be useful for debugging.
impl<T: WriteString> WriteString for Option<T> { impl<T: WriteString> WriteString for Option<T> {
fn write_string(&self) -> String { fn write_string(&self) -> String {
if let Some(this) = self { if let Some(this) = self {