├── .gitignore ├── src ├── driver │ ├── mod.rs │ ├── cli.rs │ └── command.rs ├── main.rs ├── analyze │ ├── mod.rs │ ├── unify.rs │ └── diagnostic.rs ├── utils │ ├── mod.rs │ ├── padding.rs │ ├── ident.rs │ ├── intern.rs │ └── env_map.rs ├── backend │ ├── mod.rs │ ├── tac.rs │ ├── interp.rs │ └── lowering.rs ├── syntax │ ├── mod.rs │ ├── lexer.rs │ ├── ast.rs │ ├── prim.rs │ └── rename.rs ├── lib.rs └── core │ ├── mod.rs │ ├── cps.rs │ ├── printer.rs │ ├── rename.rs │ ├── pattern.rs │ ├── closure.rs │ ├── parser.rs │ ├── inline.rs │ └── optimize.rs ├── README.md ├── tests ├── game2048.rs └── examples.rs ├── examples ├── Trivial.nr ├── Reference.nr ├── Curried.nr ├── RecFib.nr ├── PolyFunc.nr ├── Pattern.nr ├── RecordOpt.nr ├── LoopFib.nr ├── Fields.nr ├── FieldMut.nr └── Game2048.nr ├── Cargo.toml └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /src/driver/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; 2 | pub mod command; 3 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | norem_lang::driver::cli::run_cli(); 3 | } 4 | -------------------------------------------------------------------------------- /src/analyze/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod check; 2 | pub mod diagnostic; 3 | pub mod unify; 4 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod env_map; 2 | pub mod ident; 3 | pub mod intern; 4 | pub mod padding; 5 | -------------------------------------------------------------------------------- /src/backend/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod codegen_c; 2 | pub mod interp; 3 | pub mod lowering; 4 | pub mod tac; 5 | -------------------------------------------------------------------------------- /src/syntax/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod lexer; 3 | pub mod parser; 4 | pub mod prim; 5 | pub mod rename; 6 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod analyze; 2 | pub mod backend; 3 | pub mod core; 4 | pub mod driver; 5 | pub mod syntax; 6 | pub mod utils; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # norem-lang 2 | 3 | Norem is a modern functional programming language with effect system.\ 4 | The word "norem" stands for "Not Really Monadic". 5 | -------------------------------------------------------------------------------- /tests/game2048.rs: -------------------------------------------------------------------------------- 1 | mod examples; 2 | 3 | #[test] 4 | #[ignore = "it's interactive!"] 5 | fn test_game2048() { 6 | examples::test_file("Game2048"); 7 | } 8 | -------------------------------------------------------------------------------- /examples/Trivial.nr: -------------------------------------------------------------------------------- 1 | module Trivial where 2 | function add(x: Int, y: Int) -> Int 3 | begin 4 | x + y 5 | end 6 | function main() -> Int 7 | begin 8 | add(40, 2) 9 | end 10 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod closure; 2 | pub mod cps; 3 | pub mod cps_trans; 4 | pub mod inline; 5 | pub mod optimize; 6 | pub mod parser; 7 | pub mod pattern; 8 | pub mod printer; 9 | pub mod rename; 10 | -------------------------------------------------------------------------------- /examples/Reference.nr: -------------------------------------------------------------------------------- 1 | module Reference where 2 | function main() -> Int 3 | begin 4 | let r = ref 42; 5 | r <- 43; 6 | let a = ^r; 7 | r <- 44; 8 | let b = ^r; 9 | a + b 10 | end 11 | -------------------------------------------------------------------------------- /examples/Curried.nr: -------------------------------------------------------------------------------- 1 | module Curried where 2 | function main() -> Int 3 | begin 4 | let f = fn(x) => begin 5 | fn(y) => begin 6 | x + y 7 | end 8 | end; 9 | let g = f(1); 10 | let res = g(2); 11 | res 12 | end 13 | -------------------------------------------------------------------------------- /examples/RecFib.nr: -------------------------------------------------------------------------------- 1 | module RecFib where 2 | function fib(n: Int) -> Int 3 | begin 4 | if n < 1 then 5 | 0 6 | else if n == 1 then 7 | 1 8 | else 9 | fib(n - 1) + fib(n - 2) 10 | end 11 | function main() -> Int 12 | begin 13 | fib(10) 14 | end 15 | -------------------------------------------------------------------------------- /examples/PolyFunc.nr: -------------------------------------------------------------------------------- 1 | module PolyFunc where 2 | function id[T](x: T) -> T begin 3 | x 4 | end 5 | function fst[T, U](x: T, y: U) -> T begin 6 | x 7 | end 8 | function snd[T, U](x: T, y: U) -> U begin 9 | y 10 | end 11 | function main() -> Int 12 | begin 13 | id(1) + fst(2, 3.0) + snd(4.0, 5) 14 | end 15 | -------------------------------------------------------------------------------- /examples/Pattern.nr: -------------------------------------------------------------------------------- 1 | module Pattern where 2 | datatype List[T] where 3 | | Nil 4 | | Cons(T, List[T]) 5 | end 6 | function length[T](xs: List[T]) -> Int 7 | begin 8 | match xs with 9 | | Nil => 0 10 | | Cons(x, xs) => length(xs) + 1 11 | end 12 | end 13 | function main() -> Int 14 | begin 15 | length(Cons(1, Cons(2, Cons(3, Nil)))) 16 | end 17 | -------------------------------------------------------------------------------- /examples/RecordOpt.nr: -------------------------------------------------------------------------------- 1 | module RecordOpt where 2 | 3 | datatype Foo where 4 | | Foo { val: mut Int } 5 | end 6 | 7 | datatype Bar where 8 | | Bar { val: Foo } 9 | end 10 | 11 | function main() -> Int 12 | begin 13 | let foo = Foo { val: 42 }; 14 | let bar = Bar { val: foo }; 15 | bar.val.val := 43; 16 | let res = foo.val; 17 | res 18 | end 19 | -------------------------------------------------------------------------------- /examples/LoopFib.nr: -------------------------------------------------------------------------------- 1 | module LoopFib where 2 | function fib(n: Int) -> Int 3 | begin 4 | let this = ref 1; 5 | let last = ref 0; 6 | let i = ref 1; 7 | while ^i < n do 8 | let temp = ^this + ^last; 9 | last <- ^this; 10 | this <- temp; 11 | i <- ^i + 1; 12 | end; 13 | ^this 14 | end 15 | function main() -> Int 16 | begin 17 | fib(10) 18 | end 19 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "norem-lang" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | logos = "0.13.0" 10 | once_cell = "1.18.0" 11 | itertools = "0.12.0" 12 | nom = "7.1.3" 13 | clap = { version = "4.4.18", features = ["derive", "cargo"] } 14 | tempfile = "3.10.1" 15 | expect-test = "1.4.1" 16 | snailquote = "0.3.1" 17 | -------------------------------------------------------------------------------- /examples/Fields.nr: -------------------------------------------------------------------------------- 1 | module Fields where 2 | 3 | datatype Foo where 4 | | Foo1 { a: Int, b: Int } 5 | | Foo2 { c: Int, d: Int } 6 | end 7 | 8 | function read_fst(x: Foo) -> Int 9 | begin 10 | match x with 11 | | Foo1 { a, b } as foo => foo.a 12 | | Foo2 { c, d } as foo => foo.c 13 | end 14 | end 15 | 16 | datatype Bar where 17 | | Bar { a: Int, b: Int } 18 | end 19 | 20 | function main() -> Int 21 | begin 22 | let foo1 = Foo1 { a: 1, b: 2 }; 23 | let foo2 = Foo2 { c: 3, d: 4 }; 24 | let bar = Bar { a: 5, b: 6 }; 25 | read_fst(foo1) + read_fst(foo2) + bar.a 26 | end 27 | 28 | -------------------------------------------------------------------------------- /examples/FieldMut.nr: -------------------------------------------------------------------------------- 1 | module FieldMut where 2 | 3 | datatype Foo where 4 | | Foo1 { a: mut Int, b: Int } 5 | | Foo2 { c: mut Int, d: Int } 6 | end 7 | 8 | function read_fst(x: Foo) -> Int 9 | begin 10 | match x with 11 | | Foo1 { a, b } as foo => foo.a 12 | | Foo2 { c, d } as foo => foo.c 13 | end 14 | end 15 | 16 | function write_fst(x: Foo) 17 | begin 18 | match x with 19 | | Foo1 { a, b } as foo => 20 | begin 21 | foo.a := 42; 22 | end 23 | | Foo2 { c, d } as foo => 24 | begin 25 | foo.c := 43; 26 | end 27 | end 28 | end 29 | 30 | function main() -> Int 31 | begin 32 | let foo1 = Foo1 { a: 1, b: 2 }; 33 | let foo2 = Foo2 { c: 3, d: 4 }; 34 | write_fst(foo1); 35 | write_fst(foo2); 36 | read_fst(foo1) + read_fst(foo2) 37 | end 38 | -------------------------------------------------------------------------------- /src/utils/padding.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Debug, Display}; 2 | 3 | use std::sync::atomic; 4 | 5 | static mut INDT_LEVEL: atomic::AtomicUsize = atomic::AtomicUsize::new(0); 6 | 7 | pub struct INDT; 8 | pub struct DEDT; 9 | pub struct NWLN; 10 | 11 | impl Display for INDT { 12 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { 13 | unsafe { INDT_LEVEL.fetch_add(1, atomic::Ordering::Relaxed) }; 14 | Ok(()) 15 | } 16 | } 17 | 18 | impl Display for DEDT { 19 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 | unsafe { INDT_LEVEL.fetch_sub(1, atomic::Ordering::Relaxed) }; 21 | Ok(()) 22 | } 23 | } 24 | 25 | impl Display for NWLN { 26 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 | let level = unsafe { INDT_LEVEL.load(atomic::Ordering::Relaxed) }; 28 | write!(f, "\n{:width$}", "", width = level * 2) 29 | } 30 | } 31 | 32 | impl Debug for INDT { 33 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 34 | writeln!(f, "{}", self) 35 | } 36 | } 37 | 38 | impl Debug for DEDT { 39 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 40 | writeln!(f, "{}", self) 41 | } 42 | } 43 | 44 | impl Debug for NWLN { 45 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 46 | writeln!(f, "{}", self) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/driver/cli.rs: -------------------------------------------------------------------------------- 1 | use clap::{command, Arg, ArgAction}; 2 | use std::path; 3 | 4 | use crate::driver::command::{Backend, CompilerFlag}; 5 | 6 | pub fn run_cli() { 7 | let matches = command!() 8 | .arg(Arg::new("input").required(true)) 9 | // .arg(Arg::new("compile").short('c').long("compile")) 10 | .arg(Arg::new("output").short('o').long("output")) 11 | .arg( 12 | Arg::new("verbose") 13 | .short('v') 14 | .long("verbose") 15 | .default_value("10"), 16 | ) 17 | .arg( 18 | Arg::new("debug") 19 | .short('d') 20 | .long("debug") 21 | .action(ArgAction::SetTrue), 22 | ) 23 | .arg( 24 | Arg::new("backend") 25 | .short('b') 26 | .long("backend") 27 | .default_value("c"), 28 | ) 29 | .get_matches(); 30 | 31 | let input = matches.get_one::("input").unwrap(); 32 | let output = matches.get_one::("output"); 33 | // let compile = matches.get_one::("compile").unwrap(); 34 | let verbose = matches 35 | .get_one::("verbose") 36 | .unwrap() 37 | .parse::() 38 | .unwrap(); 39 | let debug = matches.get_flag("debug"); 40 | 41 | let backend = matches.get_one::("backend").unwrap(); 42 | let backend = match &backend[..] { 43 | "c" => Backend::C, 44 | "interp" => Backend::Interp, 45 | _ => panic!("unknown backend!"), 46 | }; 47 | 48 | let flag = CompilerFlag { 49 | debug_mode: debug, 50 | verbose: verbose as u8, 51 | input: path::Path::new(input).into(), 52 | output: output.map(|out| path::Path::new(out).into()), 53 | backend, 54 | }; 55 | 56 | let path = std::path::Path::new(&input); 57 | 58 | let res = crate::driver::command::compile_file(path, &flag, &mut std::io::stdout()); 59 | match res { 60 | Ok(()) => { 61 | println!("compilation successed!"); 62 | } 63 | Err(_) => { 64 | println!("compilation failed!"); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/utils/ident.rs: -------------------------------------------------------------------------------- 1 | use super::intern::InternStr; 2 | use std::fmt; 3 | use std::sync::atomic; 4 | 5 | // counter zero is reserved for dummy ident 6 | static mut COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(1); 7 | 8 | #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] 9 | pub struct Ident { 10 | name: InternStr, 11 | index: usize, 12 | } 13 | 14 | impl Ident { 15 | pub fn fresh>(s: &S) -> Ident { 16 | unsafe { 17 | let name = InternStr::new(s.as_ref()); 18 | let index = COUNTER.fetch_add(1, atomic::Ordering::Relaxed); 19 | Ident { name, index } 20 | } 21 | } 22 | 23 | pub fn dummy>(s: &S) -> Ident { 24 | let name = InternStr::new(s.as_ref()); 25 | Ident { name, index: 0 } 26 | } 27 | 28 | pub fn is_dummy(&self) -> bool { 29 | self.index == 0 30 | } 31 | 32 | pub fn uniquify(&self) -> Ident { 33 | unsafe { 34 | let name = self.name; 35 | let index = COUNTER.fetch_add(1, atomic::Ordering::Relaxed); 36 | Ident { name, index } 37 | } 38 | } 39 | 40 | pub fn as_str(&self) -> &'static str { 41 | self.name.as_str() 42 | } 43 | } 44 | 45 | impl fmt::Debug for Ident { 46 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 47 | if self.is_dummy() { 48 | write!(f, "{}", self.name) 49 | } else { 50 | write!(f, "{}_{}", self.name, self.index) 51 | } 52 | } 53 | } 54 | 55 | impl fmt::Display for Ident { 56 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 57 | if self.is_dummy() { 58 | write!(f, "{}", self.name) 59 | } else { 60 | write!(f, "{}_{}", self.name, self.index) 61 | } 62 | } 63 | } 64 | 65 | impl AsRef for Ident { 66 | fn as_ref(&self) -> &str { 67 | self.name.as_str() 68 | } 69 | } 70 | 71 | #[test] 72 | fn uniquify_test() { 73 | // test function `Ident::uniquify` 74 | let baz: &str = "baz"; 75 | let s1 = InternStr::new(&baz); 76 | let x1 = Ident::fresh(&s1); 77 | let x2 = x1.uniquify(); 78 | assert_ne!(x1, x2); 79 | assert_eq!(x1.name, x2.name); 80 | } 81 | -------------------------------------------------------------------------------- /src/utils/intern.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use std::collections::HashMap; 3 | use std::fmt; 4 | use std::sync; 5 | 6 | static INTERNER: Lazy> = Lazy::new(|| { 7 | let interner = Interner { 8 | str_to_idx: HashMap::new(), 9 | idx_to_str: Vec::new(), 10 | }; 11 | sync::Mutex::new(interner) 12 | }); 13 | 14 | struct Interner { 15 | str_to_idx: HashMap, 16 | idx_to_str: Vec<&'static str>, 17 | } 18 | 19 | #[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord)] 20 | pub struct InternStr(usize); 21 | 22 | impl InternStr { 23 | pub fn new>(s: S) -> InternStr { 24 | let mut interner = INTERNER.lock().unwrap(); 25 | if let Some(idx) = interner.str_to_idx.get(s.as_ref()) { 26 | InternStr(*idx) 27 | } else { 28 | let s = s.as_ref().to_string(); 29 | let idx = interner.idx_to_str.len(); 30 | interner.str_to_idx.insert(s.clone(), idx); 31 | interner.idx_to_str.push(Box::leak(Box::new(s))); 32 | InternStr(idx) 33 | } 34 | } 35 | 36 | pub fn as_str(&self) -> &'static str { 37 | let interner = INTERNER.lock().unwrap(); 38 | &interner.idx_to_str[self.0] 39 | } 40 | } 41 | 42 | impl fmt::Debug for InternStr { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 | write!(f, "{}", self.as_str()) 45 | } 46 | } 47 | 48 | impl fmt::Display for InternStr { 49 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 50 | write!(f, "{}", self.as_str()) 51 | } 52 | } 53 | 54 | impl AsRef for InternStr { 55 | fn as_ref(&self) -> &str { 56 | self.as_str() 57 | } 58 | } 59 | 60 | #[test] 61 | fn intern_test() { 62 | // test function InternStr::new() 63 | let foo1: &str = "foo"; 64 | let foo2: String = "foo".to_string(); 65 | let bar1: &str = "bar"; 66 | let bar2: String = "bar".to_string(); 67 | 68 | let s1 = InternStr::new(&foo1); 69 | let s2 = InternStr::new(&foo2); 70 | let s3 = InternStr::new(&bar1); 71 | let s4 = InternStr::new(&bar2); 72 | 73 | assert_eq!(s1, s2); 74 | assert_eq!(s3, s4); 75 | assert_ne!(s1, s3); 76 | assert_ne!(s2, s4); 77 | 78 | assert_eq!(format!("{}", s1), "foo"); 79 | assert_eq!(format!("{}", s2), "foo"); 80 | assert_eq!(format!("{}", s3), "bar"); 81 | assert_eq!(format!("{}", s4), "bar"); 82 | } 83 | -------------------------------------------------------------------------------- /tests/examples.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Seek}; 2 | use std::path; 3 | 4 | use norem_lang::driver::command; 5 | pub fn test_file>(module: S) -> String { 6 | let mut input = path::PathBuf::new(); 7 | input.push("examples"); 8 | input.push(module); 9 | input.set_extension("nr"); 10 | let flag = command::CompilerFlag { 11 | debug_mode: false, 12 | verbose: 10, 13 | backend: command::Backend::Interp, 14 | input: input.clone().into(), 15 | output: None, 16 | }; 17 | let mut cout = tempfile::tempfile().unwrap(); 18 | let _ = command::compile_file(&input, &flag, &mut cout); 19 | cout.rewind().unwrap(); 20 | let mut actual = String::new(); 21 | cout.read_to_string(&mut actual).unwrap(); 22 | actual 23 | } 24 | 25 | #[test] 26 | fn test_curried() { 27 | let actual = test_file("Curried"); 28 | let expect = expect_test::expect![[r#" 29 | Int(3) 30 | "#]]; 31 | expect.assert_eq(&actual) 32 | } 33 | 34 | #[test] 35 | fn test_field_mut() { 36 | let actual = test_file("FieldMut"); 37 | let expect = expect_test::expect![[r#" 38 | Int(85) 39 | "#]]; 40 | expect.assert_eq(&actual) 41 | } 42 | 43 | #[test] 44 | fn test_fields() { 45 | let actual = test_file("Fields"); 46 | let expect = expect_test::expect![[r#" 47 | Int(9) 48 | "#]]; 49 | expect.assert_eq(&actual) 50 | } 51 | #[test] 52 | fn test_loop_fib() { 53 | let actual = test_file("LoopFib"); 54 | let expect = expect_test::expect![[r#" 55 | Int(55) 56 | "#]]; 57 | expect.assert_eq(&actual) 58 | } 59 | 60 | #[test] 61 | fn test_pattern() { 62 | let actual = test_file("Pattern"); 63 | let expect = expect_test::expect![[r#" 64 | Int(3) 65 | "#]]; 66 | expect.assert_eq(&actual) 67 | } 68 | 69 | #[test] 70 | fn test_poly_func() { 71 | let actual = test_file("PolyFunc"); 72 | let expect = expect_test::expect![[r#" 73 | Int(8) 74 | "#]]; 75 | expect.assert_eq(&actual) 76 | } 77 | 78 | #[test] 79 | fn test_rec_fib() { 80 | let actual = test_file("RecFib"); 81 | let expect = expect_test::expect![[r#" 82 | Int(55) 83 | "#]]; 84 | expect.assert_eq(&actual) 85 | } 86 | 87 | #[test] 88 | fn test_record_opt() { 89 | let actual = test_file("RecordOpt"); 90 | let expect = expect_test::expect![[r#" 91 | Int(43) 92 | "#]]; 93 | expect.assert_eq(&actual) 94 | } 95 | 96 | #[test] 97 | fn test_reference() { 98 | let actual = test_file("Reference"); 99 | let expect = expect_test::expect![[r#" 100 | Int(87) 101 | "#]]; 102 | expect.assert_eq(&actual) 103 | } 104 | 105 | #[test] 106 | fn test_trivial() { 107 | let actual = test_file("Trivial"); 108 | let expect = expect_test::expect![[r#" 109 | Int(42) 110 | "#]]; 111 | expect.assert_eq(&actual) 112 | } 113 | -------------------------------------------------------------------------------- /src/core/cps.rs: -------------------------------------------------------------------------------- 1 | use crate::syntax::ast; 2 | use crate::syntax::prim::Prim; 3 | use crate::utils::ident::Ident; 4 | 5 | #[derive(Copy, Clone, Debug, PartialEq)] 6 | pub enum Atom { 7 | Var(Ident), 8 | Int(i64), 9 | Float(f64), 10 | Bool(bool), 11 | Char(char), 12 | Unit, 13 | } 14 | 15 | impl Atom { 16 | pub fn is_var(&self) -> bool { 17 | match self { 18 | Atom::Var(_) => true, 19 | _ => false, 20 | } 21 | } 22 | pub fn is_lit(&self) -> bool { 23 | match self { 24 | Atom::Int(_) => true, 25 | Atom::Float(_) => true, 26 | Atom::Bool(_) => true, 27 | Atom::Char(_) => true, 28 | Atom::Unit => true, 29 | _ => false, 30 | } 31 | } 32 | pub fn unwrap_var(self) -> Ident { 33 | match self { 34 | Atom::Var(x) => x, 35 | _ => panic!("Failed to unwrap variable!"), 36 | } 37 | } 38 | pub fn unwrap_int(self) -> i64 { 39 | match self { 40 | Atom::Int(x) => x, 41 | _ => panic!("Failed to unwrap integer!"), 42 | } 43 | } 44 | } 45 | 46 | impl From for Atom { 47 | fn from(lit: ast::LitVal) -> Self { 48 | match lit { 49 | ast::LitVal::Int(x) => Atom::Int(x), 50 | ast::LitVal::Float(x) => Atom::Float(x), 51 | ast::LitVal::Bool(x) => Atom::Bool(x), 52 | ast::LitVal::Char(x) => Atom::Char(x), 53 | ast::LitVal::Unit => Atom::Unit, 54 | } 55 | } 56 | } 57 | 58 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 59 | pub enum IfCond { 60 | BTrue, 61 | BFalse, 62 | ICmpGr, 63 | ICmpEq, 64 | ICmpLs, 65 | } 66 | 67 | impl IfCond { 68 | pub fn get_arity(&self) -> Option { 69 | match self { 70 | IfCond::BTrue => Some(1), 71 | IfCond::BFalse => Some(1), 72 | IfCond::ICmpGr => Some(2), 73 | IfCond::ICmpEq => Some(2), 74 | IfCond::ICmpLs => Some(2), 75 | } 76 | } 77 | } 78 | 79 | #[derive(Clone, Debug)] 80 | pub struct FuncDecl { 81 | pub func: Ident, 82 | pub cont: Ident, 83 | pub pars: Vec, 84 | pub body: Expr, 85 | } 86 | 87 | #[derive(Clone, Debug)] 88 | pub struct ContDecl { 89 | pub cont: Ident, 90 | pub pars: Vec, 91 | pub body: Expr, 92 | } 93 | 94 | #[derive(Clone, Debug)] 95 | pub enum Expr { 96 | Decls { 97 | funcs: Vec, 98 | conts: Vec, 99 | body: Box, 100 | }, 101 | Prim { 102 | bind: Ident, 103 | prim: Prim, 104 | args: Vec, 105 | rest: Box, 106 | }, 107 | Record { 108 | bind: Ident, 109 | args: Vec<(bool, Atom)>, 110 | rest: Box, 111 | }, 112 | Select { 113 | bind: Ident, 114 | rec: Atom, 115 | idx: usize, 116 | rest: Box, 117 | }, 118 | Update { 119 | rec: Atom, 120 | idx: usize, 121 | arg: Atom, 122 | rest: Box, 123 | }, 124 | Call { 125 | func: Ident, 126 | cont: Ident, 127 | args: Vec, 128 | }, 129 | Jump { 130 | cont: Ident, 131 | args: Vec, 132 | }, 133 | Ifte { 134 | cond: IfCond, 135 | args: Vec, 136 | trbr: Box, 137 | flbr: Box, 138 | }, 139 | Switch { 140 | arg: Atom, 141 | brchs: Vec<(usize, Expr)>, 142 | dflt: Option>, 143 | }, 144 | Retn { 145 | res: Atom, 146 | }, 147 | } 148 | 149 | #[derive(Clone, Debug)] 150 | pub struct Module { 151 | pub name: Ident, 152 | pub decls: Vec, 153 | } 154 | -------------------------------------------------------------------------------- /src/driver/command.rs: -------------------------------------------------------------------------------- 1 | use crate::analyze::diagnostic::Diagnostic; 2 | use crate::backend::tac; 3 | use crate::{analyze, backend, core, syntax}; 4 | use std::{fs, io, path, vec}; 5 | 6 | #[derive(Clone, Debug)] 7 | pub enum Backend { 8 | Interp, 9 | C, 10 | } 11 | 12 | #[derive(Clone, Debug)] 13 | pub struct CompilerFlag { 14 | pub debug_mode: bool, 15 | pub verbose: u8, 16 | pub input: Box, 17 | pub output: Option>, 18 | pub backend: Backend, 19 | } 20 | 21 | #[derive(Debug)] 22 | pub enum CompileError { 23 | SyntaxError, 24 | ScopeError, 25 | SemanticError, 26 | IOError(std::io::Error), 27 | } 28 | 29 | impl From for CompileError { 30 | fn from(value: std::io::Error) -> Self { 31 | CompileError::IOError(value) 32 | } 33 | } 34 | 35 | pub fn compile_file( 36 | path: &path::Path, 37 | flag: &CompilerFlag, 38 | cout: &mut T, 39 | ) -> Result<(), CompileError> 40 | where 41 | T: io::Write, 42 | { 43 | let src = fs::read_to_string(&path)?; 44 | let mut diags: Vec = Vec::new(); 45 | let res = compile_with(&src, flag, &mut diags); 46 | for diag in diags.iter() { 47 | writeln!(cout, "{}", diag.report(&src, flag.verbose))?; 48 | println!("{}", diag.report(&src, flag.verbose)); 49 | } 50 | let modl = res?; 51 | match flag.backend { 52 | Backend::Interp => { 53 | let entry = modl 54 | .funcs 55 | .iter() 56 | .map(|(name, _)| name) 57 | .find(|name| name.as_str() == "main") 58 | .unwrap(); 59 | let mut eval = backend::interp::Interpreter::new(&modl); 60 | let res = unsafe { eval.run(*entry, vec![backend::interp::Value::Unit]) }; 61 | writeln!(cout, "{res:?}")?; 62 | println!("{res:?}"); 63 | Ok(()) 64 | } 65 | Backend::C => { 66 | let s = backend::codegen_c::Codegen::run(&modl); 67 | let out = flag 68 | .output 69 | .clone() 70 | .unwrap_or_else(|| flag.input.clone().with_extension("c").into()); 71 | fs::write(out, s)?; 72 | Ok(()) 73 | } 74 | } 75 | } 76 | 77 | pub fn compile_with<'src>( 78 | src: &'src str, 79 | flag: &CompilerFlag, 80 | diags: &mut Vec, 81 | ) -> Result { 82 | let mut modl = syntax::parser::parse_module(&src, diags).ok_or(CompileError::SyntaxError)?; 83 | if flag.debug_mode { 84 | println!("parser:\n{modl:#?}"); 85 | } 86 | syntax::rename::rename_module(&mut modl, diags).map_err(|_| CompileError::ScopeError)?; 87 | analyze::check::check_module(&mut modl, diags).map_err(|_| CompileError::SemanticError)?; 88 | 89 | let modl = core::cps_trans::Translator::run(&modl); 90 | if flag.debug_mode { 91 | println!("cps_trans:\n{modl}"); 92 | } 93 | let modl = core::optimize::Optimizer::run(modl); 94 | if flag.debug_mode { 95 | println!("optimize:\n{modl}"); 96 | } 97 | /* 98 | let mark = core::inline::InlineScan::run(&modl); 99 | let modl = core::inline::InlinePerform::run(modl, mark); 100 | if flag.debug_mode { 101 | println!("inline:\n{modl}"); 102 | } 103 | */ 104 | let modl = core::optimize::Optimizer::run(modl); 105 | if flag.debug_mode { 106 | println!("optimize:\n{modl}"); 107 | } 108 | let modl = core::closure::ClosConv::run(modl); 109 | if flag.debug_mode { 110 | println!("clos_conv:\n{modl}"); 111 | } 112 | let modl = core::optimize::Optimizer::run(modl); 113 | if flag.debug_mode { 114 | println!("optimize:\n{modl}"); 115 | } 116 | let modl = backend::lowering::Lowering::run(&modl); 117 | if flag.debug_mode { 118 | println!("lowering:\n{modl}"); 119 | } 120 | Ok(modl) 121 | } 122 | -------------------------------------------------------------------------------- /src/backend/tac.rs: -------------------------------------------------------------------------------- 1 | use itertools::Itertools; 2 | 3 | use crate::syntax::prim::Compare; 4 | use crate::utils::ident::Ident; 5 | use core::fmt; 6 | use std::collections::HashMap; 7 | 8 | #[derive(Clone, Debug)] 9 | pub enum Instr { 10 | LitI(Ident, i64), 11 | LitF(Ident, f64), 12 | LitB(Ident, bool), 13 | LitC(Ident, char), 14 | LitA(Ident, Ident), 15 | IAdd(Ident, Ident, Ident), 16 | ISub(Ident, Ident, Ident), 17 | IMul(Ident, Ident, Ident), 18 | IDiv(Ident, Ident, Ident), 19 | IRem(Ident, Ident, Ident), 20 | INeg(Ident, Ident), 21 | FAdd(Ident, Ident, Ident), 22 | FSub(Ident, Ident, Ident), 23 | FMul(Ident, Ident, Ident), 24 | FDiv(Ident, Ident, Ident), 25 | FNeg(Ident, Ident), 26 | BAnd(Ident, Ident, Ident), 27 | BOr(Ident, Ident, Ident), 28 | BNot(Ident, Ident), 29 | ICmp(Compare, Ident, Ident, Ident), 30 | FCmp(Compare, Ident, Ident, Ident), 31 | Move(Ident, Ident), 32 | Alloc(Ident, Ident), 33 | Load(Ident, Ident, Ident), 34 | Store(Ident, Ident, Ident), 35 | IPrint(Ident), 36 | IScan(Ident), 37 | FPrint(Ident), 38 | FScan(Ident), 39 | CPrint(Ident), 40 | CScan(Ident), 41 | Assert(Ident), 42 | } 43 | 44 | #[derive(Clone, Debug)] 45 | pub enum LastInstr { 46 | TailCall(Ident, Vec), 47 | // Call(bind, func, cont, args) 48 | Call(Ident, Ident, Ident, Vec), 49 | Return(Ident), 50 | Jump(Ident), 51 | BrIf(Ident, Ident, Ident), 52 | } 53 | 54 | #[derive(Clone, Debug)] 55 | pub struct BasicBlock { 56 | pub name: Ident, 57 | pub codes: Vec, 58 | pub last: Option, 59 | } 60 | 61 | impl BasicBlock { 62 | pub fn new(name: Ident) -> BasicBlock { 63 | BasicBlock { 64 | name, 65 | codes: Vec::new(), 66 | last: None, 67 | } 68 | } 69 | pub fn push(&mut self, code: Instr) { 70 | self.codes.push(code); 71 | } 72 | pub fn seal(&mut self, brch: LastInstr) { 73 | assert!(self.last.is_none()); 74 | self.last = Some(brch); 75 | } 76 | pub fn is_sealed(&self) -> bool { 77 | self.last.is_some() 78 | } 79 | } 80 | 81 | #[derive(Clone, Debug)] 82 | pub struct Function { 83 | pub name: Ident, 84 | pub pars: Vec, 85 | pub blks: Vec, 86 | } 87 | 88 | impl Function { 89 | pub fn new(name: Ident, pars: Vec) -> Function { 90 | Function { 91 | name, 92 | pars, 93 | blks: Vec::new(), 94 | } 95 | } 96 | 97 | pub fn push(&mut self, blk: BasicBlock) { 98 | self.blks.push(blk); 99 | } 100 | } 101 | 102 | #[derive(Clone, Debug)] 103 | pub struct Module { 104 | pub name: Ident, 105 | pub funcs: HashMap, 106 | } 107 | 108 | impl Module { 109 | pub fn new(name: Ident) -> Module { 110 | Module { 111 | name, 112 | funcs: HashMap::new(), 113 | } 114 | } 115 | 116 | pub fn push(&mut self, func: Function) { 117 | self.funcs.insert(func.name, func); 118 | } 119 | } 120 | 121 | impl fmt::Display for BasicBlock { 122 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 123 | let BasicBlock { name, codes, last } = self; 124 | writeln!(f, "{name}:")?; 125 | for code in codes { 126 | writeln!(f, " {code:?}")?; 127 | } 128 | if let Some(last) = last { 129 | writeln!(f, " {last:?}")?; 130 | } 131 | Ok(()) 132 | } 133 | } 134 | impl fmt::Display for Function { 135 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 136 | let Function { name, pars, blks } = self; 137 | let pars = pars.iter().format(", "); 138 | writeln!(f, "function {name}({pars}) begin")?; 139 | for blk in blks { 140 | writeln!(f, "{blk}")?; 141 | } 142 | writeln!(f, "end")?; 143 | Ok(()) 144 | } 145 | } 146 | 147 | impl fmt::Display for Module { 148 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 149 | let Module { name, funcs } = self; 150 | writeln!(f, "module {name} where")?; 151 | for (_, func) in funcs.iter() { 152 | writeln!(f, "{func}")?; 153 | } 154 | Ok(()) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/core/printer.rs: -------------------------------------------------------------------------------- 1 | use super::cps::*; 2 | use crate::utils::padding::{DEDT, INDT, NWLN}; 3 | use itertools::Itertools; 4 | use std::fmt; 5 | 6 | impl fmt::Display for Atom { 7 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 8 | match self { 9 | Atom::Var(x) => x.fmt(f), 10 | Atom::Int(x) => x.fmt(f), 11 | Atom::Float(x) => x.fmt(f), 12 | Atom::Bool(x) => x.fmt(f), 13 | Atom::Char(x) => x.fmt(f), 14 | Atom::Unit => "()".fmt(f), 15 | } 16 | } 17 | } 18 | 19 | impl fmt::Display for IfCond { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | match self { 22 | IfCond::BTrue => "btrue".fmt(f), 23 | IfCond::BFalse => "bfalse".fmt(f), 24 | IfCond::ICmpGr => "icmpgr".fmt(f), 25 | IfCond::ICmpEq => "icmpeq".fmt(f), 26 | IfCond::ICmpLs => "icmpls".fmt(f), 27 | } 28 | } 29 | } 30 | 31 | impl fmt::Display for FuncDecl { 32 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 33 | let FuncDecl { 34 | func, 35 | cont, 36 | pars, 37 | body, 38 | } = self; 39 | let pars = [cont].into_iter().chain(pars.iter()).format(&", "); 40 | write!(f, "func {func}({pars}):")?; 41 | write!(f, "{INDT}{NWLN}{body}{DEDT}")?; 42 | Ok(()) 43 | } 44 | } 45 | 46 | impl fmt::Display for ContDecl { 47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 | let ContDecl { cont, pars, body } = self; 49 | let pars = pars.iter().format(&", "); 50 | write!(f, "cont {cont}({pars}):")?; 51 | write!(f, "{INDT}{NWLN}{body}{DEDT}")?; 52 | Ok(()) 53 | } 54 | } 55 | 56 | impl fmt::Display for Expr { 57 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 58 | match self { 59 | Expr::Decls { funcs, conts, body } => { 60 | write!(f, "decls{INDT}")?; 61 | for func in funcs { 62 | write!(f, "{NWLN}{func}")?; 63 | } 64 | for cont in conts { 65 | write!(f, "{NWLN}{cont}")?; 66 | } 67 | write!(f, "{DEDT}{NWLN}in{INDT}{NWLN}{body}{DEDT}{NWLN}end")?; 68 | Ok(()) 69 | } 70 | Expr::Prim { 71 | bind, 72 | prim, 73 | args, 74 | rest, 75 | } => { 76 | let args = args.iter().format(&", "); 77 | write!(f, "let {bind} = {prim}({args});{NWLN}{rest}") 78 | } 79 | Expr::Record { bind, args, rest } => { 80 | let args = args 81 | .iter() 82 | .map(|(is_mut, arg)| { 83 | if *is_mut { 84 | format!("mut {}", arg) 85 | } else { 86 | format!("{}", arg) 87 | } 88 | }) 89 | .format(", "); 90 | write!(f, "record {bind} = {{ {args} }};{NWLN}{rest}") 91 | } 92 | Expr::Select { 93 | bind, 94 | rec, 95 | idx, 96 | rest, 97 | } => { 98 | write!(f, "select {bind} = {rec}[{idx}];{NWLN}{rest}") 99 | } 100 | Expr::Update { 101 | rec, 102 | idx, 103 | arg, 104 | rest, 105 | } => { 106 | write!(f, "update {rec}[{idx}] = {arg};{NWLN}{rest}") 107 | } 108 | Expr::Call { func, cont, args } => { 109 | let cont = Atom::Var(*cont); 110 | let args = [&cont].into_iter().chain(args.iter()).format(&", "); 111 | write!(f, "call {func}({args});") 112 | } 113 | Expr::Jump { cont, args } => { 114 | let args = args.iter().format(&", "); 115 | write!(f, "jump {cont}({args});") 116 | } 117 | Expr::Ifte { 118 | cond, 119 | args, 120 | trbr, 121 | flbr, 122 | } => { 123 | let args = args.iter().format(&", "); 124 | write!(f, "if {cond}({args})")?; 125 | write!(f, "{NWLN}then{INDT}{NWLN}{trbr}{DEDT}")?; 126 | write!(f, "{NWLN}else{INDT}{NWLN}{flbr}{DEDT}")?; 127 | Ok(()) 128 | } 129 | Expr::Switch { arg, brchs, dflt } => { 130 | write!(f, "switch {arg} of")?; 131 | for (i, brch) in brchs { 132 | write!(f, "{NWLN}case {i}:{INDT}{NWLN}{brch}{DEDT}")?; 133 | } 134 | if let Some(dflt) = dflt { 135 | write!(f, "{NWLN}default:{INDT}{NWLN}{dflt}{DEDT}")?; 136 | } 137 | write!(f, "{NWLN}end")?; 138 | Ok(()) 139 | } 140 | Expr::Retn { res } => { 141 | write!(f, "return {res};") 142 | } 143 | } 144 | } 145 | } 146 | 147 | impl fmt::Display for Module { 148 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 149 | let Module { name, decls } = self; 150 | write!(f, "module {} where", name)?; 151 | for decl in decls { 152 | write!(f, "{NWLN}{}{NWLN}", decl)?; 153 | } 154 | Ok(()) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/syntax/lexer.rs: -------------------------------------------------------------------------------- 1 | use logos::Logos; 2 | 3 | pub type Span = logos::Span; 4 | 5 | #[derive(Clone, Copy, Debug, Eq, Logos, PartialEq)] 6 | #[logos(skip r"[ \t\f]+")] 7 | pub enum Token { 8 | #[token("(")] 9 | LParen, 10 | #[token(")")] 11 | RParen, 12 | #[token("[")] 13 | LBracket, 14 | #[token("]")] 15 | RBracket, 16 | #[token("{")] 17 | LBrace, 18 | #[token("}")] 19 | RBrace, 20 | #[token(":")] 21 | Colon, 22 | #[token(";")] 23 | Semi, 24 | #[token(",")] 25 | Comma, 26 | #[token(".")] 27 | Dot, 28 | #[token("|")] 29 | Bar, 30 | #[token("=")] 31 | Equal, 32 | #[token("+")] 33 | Plus, 34 | #[token("-")] 35 | Minus, 36 | #[token("*")] 37 | Star, 38 | #[token("/")] 39 | Slash, 40 | #[token("%")] 41 | Percent, 42 | #[token("<")] 43 | Less, 44 | #[token("<=")] 45 | LessEqual, 46 | #[token("==")] 47 | EqualEqual, 48 | #[token(">=")] 49 | GreaterEqual, 50 | #[token(">")] 51 | Greater, 52 | #[token("!=")] 53 | BangEqual, 54 | #[token("^")] 55 | Caret, 56 | #[token("&&")] 57 | DoubleAmpersand, 58 | #[token("||")] 59 | DoubleBar, 60 | #[token("!")] 61 | Bang, 62 | #[token("->")] 63 | Arrow, 64 | #[token("=>")] 65 | FatArrow, 66 | #[token("<-")] 67 | LeftArrow, 68 | #[token(":=")] 69 | ColonEqual, 70 | #[token("fn")] 71 | Fn, 72 | #[token("let")] 73 | Let, 74 | #[token("if")] 75 | If, 76 | #[token("then")] 77 | Then, 78 | #[token("else")] 79 | Else, 80 | #[token("match")] 81 | Match, 82 | #[token("with")] 83 | With, 84 | #[token("case")] 85 | Case, 86 | #[token("of")] 87 | Of, 88 | #[token("as")] 89 | As, 90 | #[token("begin")] 91 | Begin, 92 | #[token("end")] 93 | End, 94 | #[token("while")] 95 | While, 96 | #[token("do")] 97 | Do, 98 | #[token("ref")] 99 | Ref, 100 | #[token("mut")] 101 | Mut, 102 | #[token("function")] 103 | Function, 104 | #[token("datatype")] 105 | Datatype, 106 | #[token("module")] 107 | Module, 108 | #[token("where")] 109 | Where, 110 | #[token("_")] 111 | Wild, 112 | #[regex(r"[0-9]([0-9])*")] 113 | Int, 114 | #[regex(r"[0-9]([0-9])*\.[0-9]([0-9])*")] 115 | Float, 116 | #[token("true")] 117 | #[token("false")] 118 | Bool, 119 | #[regex(r"'(.|\\.)'")] 120 | Char, 121 | #[token("Int")] 122 | TyInt, 123 | #[token("Float")] 124 | TyFloat, 125 | #[token("Bool")] 126 | TyBool, 127 | #[token("Char")] 128 | TyChar, 129 | #[token("Unit")] 130 | TyUnit, 131 | #[regex(r"[a-z]([a-zA-Z0-9]|_)*")] 132 | LowerIdent, 133 | #[regex(r"[A-Z]([a-zA-Z0-9]|_)*")] 134 | UpperIdent, 135 | #[regex(r"@[a-zA-Z]([a-zA-Z0-9]|_)*")] 136 | PrimOpr, 137 | #[token("//", line_comment)] 138 | LineComment, 139 | #[token("/*", block_comment)] 140 | BlockComment, 141 | #[token("\n")] 142 | NewLine, 143 | /// lexer failed, skip till next whitespace 144 | TokError, 145 | EndOfFile, 146 | } 147 | 148 | fn line_comment(lex: &mut logos::Lexer) -> bool { 149 | let mut rest = lex.remainder().chars(); 150 | loop { 151 | if let Some(ch) = rest.next() { 152 | lex.bump(ch.len_utf8()); 153 | if ch == '\n' { 154 | return true; 155 | } 156 | } else { 157 | return false; 158 | } 159 | } 160 | } 161 | 162 | fn block_comment(lex: &mut logos::Lexer) -> bool { 163 | let mut rest = lex.remainder().chars(); 164 | let mut last_char = ' '; 165 | let mut nested_level: usize = 1; 166 | loop { 167 | if let Some(ch) = rest.next() { 168 | lex.bump(ch.len_utf8()); 169 | match ch { 170 | '/' if last_char == '*' => { 171 | nested_level -= 1; 172 | } 173 | '*' if last_char == '/' => { 174 | nested_level += 1; 175 | } 176 | _ => {} 177 | } 178 | if nested_level == 0 { 179 | return true; 180 | } 181 | last_char = ch; 182 | } else { 183 | return false; 184 | } 185 | } 186 | } 187 | 188 | pub struct TokenSpan { 189 | pub token: Token, 190 | pub span: Span, 191 | } 192 | 193 | pub fn tokenize(source: &str) -> Vec { 194 | let mut lex = Token::lexer(source); 195 | let mut vec = Vec::new(); 196 | while let Some(tok) = lex.next() { 197 | let span = lex.span(); 198 | match tok { 199 | // we don't leak these three tokens to parser 200 | // but they will be useful in the future, if we want to write a formatter 201 | Ok(Token::NewLine) | Ok(Token::LineComment) | Ok(Token::BlockComment) => {} 202 | Ok(token) => { 203 | vec.push(TokenSpan { token, span }); 204 | } 205 | Err(()) => { 206 | let token = Token::TokError; 207 | vec.push(TokenSpan { token, span }); 208 | } 209 | } 210 | } 211 | let token = Token::EndOfFile; 212 | let span = lex.span(); 213 | vec.push(TokenSpan { token, span }); 214 | vec 215 | } 216 | 217 | #[test] 218 | #[ignore = "just to see result"] 219 | fn lexer_test() { 220 | let s = r#" 221 | // test line comment 222 | /* 223 | /* 224 | test block comment 225 | */ 226 | */ 227 | (fn(x) => (@iadd(x,1)))(42) 228 | "#; 229 | 230 | let mut lex = Token::lexer(s); 231 | 232 | loop { 233 | if let Some(tok) = lex.next() { 234 | println!("{:?} {:?} {}", tok, lex.span(), lex.slice()); 235 | } else { 236 | break; 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/utils/env_map.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Borrow; 2 | use std::collections::{hash_map, HashMap}; 3 | use std::fmt::Debug; 4 | use std::hash::Hash; 5 | 6 | /// `EnvOpr` records all the operation have done. 7 | /// When you do [`EnvMap::insert`] or [`EnvMap::remove`], an `EnvOpr` is created 8 | 9 | #[derive(Clone, Debug, PartialEq)] 10 | enum EnvOpr { 11 | Update(K, V), 12 | Insert(K), 13 | Delete(K, V), 14 | Nothing, 15 | } 16 | 17 | /// EnvMap is a wrapper of HashMap, but with the ability to backtrack and recover from modification 18 | #[derive(Clone, Debug)] 19 | pub struct EnvMap { 20 | /// The wrapped HashMap allow us to do all the work. 21 | base_map: HashMap, 22 | /// History records all the operations that have done. 23 | history: Vec>, 24 | /// Scopes records the history pivot for each scope 25 | scopes: Vec, 26 | } 27 | 28 | /// Many implementations are just the same as HashMap 29 | impl EnvMap 30 | where 31 | K: Eq + Hash + Clone, 32 | { 33 | /// Creating an empty EnvMap 34 | pub fn new() -> EnvMap { 35 | EnvMap { 36 | base_map: HashMap::new(), 37 | history: Vec::new(), 38 | scopes: Vec::new(), 39 | } 40 | } 41 | 42 | /// Creating an empty EnvMap with capacity 43 | pub fn with_capacity(capacity: usize) -> EnvMap { 44 | EnvMap { 45 | base_map: HashMap::with_capacity(capacity), 46 | history: Vec::new(), 47 | scopes: Vec::new(), 48 | } 49 | } 50 | 51 | /// Returns the number of elements the map can hold without reallocating. 52 | pub fn capacity(&self) -> usize { 53 | self.base_map.capacity() 54 | } 55 | 56 | /// An iterator visiting all keys in arbitrary order. 57 | pub fn keys(&self) -> hash_map::Keys<'_, K, V> { 58 | self.base_map.keys() 59 | } 60 | 61 | /// An iterator visiting all values in arbitrary order. 62 | pub fn values(&self) -> hash_map::Values<'_, K, V> { 63 | self.base_map.values() 64 | } 65 | 66 | /// An iterator visiting all key-value pairs in arbitrary order. 67 | pub fn iter(&self) -> hash_map::Iter<'_, K, V> { 68 | self.base_map.iter() 69 | } 70 | 71 | /// Returns `true` if the map contains no elements. 72 | pub fn is_empty(&self) -> bool { 73 | self.base_map.is_empty() 74 | } 75 | 76 | /// Returns a reference to the value corresponding to the key. 77 | pub fn get(&self, k: &Q) -> Option<&V> 78 | where 79 | K: Borrow, 80 | Q: Hash + Eq, 81 | { 82 | self.base_map.get(k) 83 | } 84 | 85 | /// Returns the key-value pair corresponding to the supplied key. 86 | pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> 87 | where 88 | K: Borrow, 89 | Q: Hash + Eq, 90 | { 91 | self.base_map.get_key_value(k) 92 | } 93 | 94 | /// Returns `true` if the map contains a value for the specified key. 95 | pub fn contains_key(&self, k: &Q) -> bool 96 | where 97 | K: Borrow, 98 | Q: Hash + Eq, 99 | { 100 | self.base_map.contains_key(k) 101 | } 102 | 103 | /// Inserts a key-value pair into the map. 104 | pub fn insert(&mut self, k: K, v: V) -> bool { 105 | if let Some(old) = self.base_map.insert(k.clone(), v) { 106 | self.history.push(EnvOpr::Update(k, old)); 107 | true 108 | } else { 109 | self.history.push(EnvOpr::Insert(k)); 110 | false 111 | } 112 | } 113 | 114 | /// Removes a key from the map 115 | pub fn remove(&mut self, k: &K) -> bool { 116 | if let Some(old) = self.base_map.remove(k) { 117 | self.history.push(EnvOpr::Delete(k.clone(), old)); 118 | true 119 | } else { 120 | self.history.push(EnvOpr::Nothing); 121 | false 122 | } 123 | } 124 | 125 | /// Enter a new scope, record the current pivot of history 126 | pub fn enter_scope(&mut self) { 127 | self.scopes.push(self.history.len()) 128 | } 129 | 130 | /// Leave from a scope, unwind the history and recover. 131 | pub fn leave_scope(&mut self) { 132 | let n = self.scopes.pop().unwrap(); 133 | for _ in n..self.history.len() { 134 | match self.history.pop().unwrap() { 135 | EnvOpr::Update(k, v) => { 136 | // recover the old value that was covered by insert 137 | let r = self.base_map.insert(k, v); 138 | assert!(r.is_some()); 139 | } 140 | EnvOpr::Insert(k) => { 141 | // remove the inserted key and value 142 | let r = self.base_map.remove(&k); 143 | assert!(r.is_some()); 144 | } 145 | EnvOpr::Delete(k, v) => { 146 | // recover the deleted key and value 147 | let r = self.base_map.insert(k, v); 148 | assert!(r.is_none()); 149 | } 150 | EnvOpr::Nothing => { 151 | // Well, do nothing... 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | impl std::ops::Index<&K> for EnvMap 159 | where 160 | K: Hash + Eq, 161 | { 162 | type Output = V; 163 | 164 | fn index(&self, index: &K) -> &Self::Output { 165 | &self.base_map[index] 166 | } 167 | } 168 | 169 | #[test] 170 | fn env_map_test() { 171 | let mut env = EnvMap::new(); 172 | env.insert(&1, 'a'); 173 | env.enter_scope(); 174 | env.insert(&1, 'd'); 175 | env.insert(&2, 'b'); 176 | env.insert(&3, 'c'); 177 | assert_eq!(env.get(&1), Some(&'d')); 178 | assert_eq!(env.get(&2), Some(&'b')); 179 | assert_eq!(env.get(&3), Some(&'c')); 180 | env.leave_scope(); 181 | assert_eq!(env.get(&1), Some(&'a')); 182 | assert_eq!(env.get(&2), None); 183 | assert_eq!(env.get(&3), None); 184 | } 185 | -------------------------------------------------------------------------------- /src/syntax/ast.rs: -------------------------------------------------------------------------------- 1 | use super::lexer::Span; 2 | use super::prim::Prim; 3 | use crate::utils::ident::Ident; 4 | use crate::utils::intern::InternStr; 5 | 6 | #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] 7 | pub enum LitVal { 8 | Int(i64), 9 | Float(f64), 10 | Bool(bool), 11 | Char(char), 12 | Unit, 13 | } 14 | 15 | #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, PartialOrd)] 16 | pub enum LitType { 17 | TyInt, 18 | TyFloat, 19 | TyBool, 20 | TyChar, 21 | TyUnit, 22 | } 23 | 24 | impl LitVal { 25 | pub fn get_lit_type(&self) -> LitType { 26 | match self { 27 | LitVal::Int(_) => LitType::TyInt, 28 | LitVal::Float(_) => LitType::TyFloat, 29 | LitVal::Bool(_) => LitType::TyBool, 30 | LitVal::Char(_) => LitType::TyChar, 31 | LitVal::Unit => LitType::TyUnit, 32 | } 33 | } 34 | } 35 | 36 | #[derive(Clone, Debug, PartialEq)] 37 | pub enum Type { 38 | Lit { 39 | lit: LitType, 40 | span: Span, 41 | }, 42 | Var { 43 | ident: Ident, 44 | span: Span, 45 | }, 46 | Cons { 47 | cons: Ident, 48 | args: Vec, 49 | span: Span, 50 | }, 51 | Func { 52 | pars: Vec, 53 | res: Box, 54 | span: Span, 55 | }, 56 | } 57 | 58 | #[derive(Clone, Debug, PartialEq)] 59 | pub enum Expr { 60 | Lit { 61 | lit: LitVal, 62 | span: Span, 63 | }, 64 | Var { 65 | ident: Ident, 66 | span: Span, 67 | }, 68 | Prim { 69 | prim: Prim, 70 | args: Vec, 71 | span: Span, 72 | }, 73 | Cons { 74 | cons: Ident, 75 | flds: Vec>, 76 | span: Span, 77 | }, 78 | Func { 79 | pars: Vec, 80 | body: Box, 81 | span: Span, 82 | }, 83 | App { 84 | func: Box, 85 | args: Vec, 86 | span: Span, 87 | }, 88 | Ifte { 89 | cond: Box, 90 | trbr: Box, 91 | flbr: Box, 92 | span: Span, 93 | }, 94 | Case { 95 | expr: Box, 96 | rules: Vec, 97 | span: Span, 98 | }, 99 | Field { 100 | expr: Box, 101 | field: InternStr, 102 | cons_info: Option, 103 | span: Span, 104 | }, 105 | NewRef { 106 | expr: Box, 107 | span: Span, 108 | }, 109 | RefGet { 110 | expr: Box, 111 | span: Span, 112 | }, 113 | Stmt { 114 | stmt: Box, 115 | cont: Box, 116 | span: Span, 117 | }, 118 | } 119 | 120 | #[derive(Clone, Debug, PartialEq)] 121 | pub enum Stmt { 122 | Let { 123 | ident: Ident, 124 | typ: Option, 125 | expr: Expr, 126 | span: Span, 127 | }, 128 | RefSet { 129 | lhs: Expr, 130 | rhs: Expr, 131 | span: Span, 132 | }, 133 | Assign { 134 | lhs: Expr, 135 | rhs: Expr, 136 | span: Span, 137 | }, 138 | While { 139 | cond: Expr, 140 | body: Expr, 141 | span: Span, 142 | }, 143 | Do { 144 | expr: Expr, 145 | span: Span, 146 | }, 147 | } 148 | 149 | #[derive(Clone, Debug, PartialEq)] 150 | pub struct Labeled { 151 | pub label: InternStr, 152 | pub data: T, 153 | pub span: Span, 154 | } 155 | 156 | #[derive(Clone, Debug, PartialEq)] 157 | pub struct Rule { 158 | pub patn: Pattern, 159 | pub body: Expr, 160 | pub span: Span, 161 | } 162 | 163 | #[derive(Clone, Debug, PartialEq)] 164 | pub enum Pattern { 165 | Var { 166 | ident: Ident, 167 | span: Span, 168 | }, 169 | Lit { 170 | lit: LitVal, 171 | span: Span, 172 | }, 173 | Cons { 174 | cons: Ident, 175 | patns: Vec>, 176 | as_ident: Option, 177 | span: Span, 178 | }, 179 | Wild { 180 | span: Span, 181 | }, 182 | } 183 | 184 | #[derive(Clone, Debug, PartialEq)] 185 | pub struct Varient { 186 | pub cons: Ident, 187 | pub flds: Vec>, 188 | pub span: Span, 189 | } 190 | 191 | #[derive(Clone, Debug, PartialEq)] 192 | pub struct FuncSign { 193 | pub func: Ident, 194 | pub polys: Vec, 195 | pub pars: Vec<(Ident, Type)>, 196 | pub res: Type, 197 | pub span: Span, 198 | } 199 | 200 | #[derive(Clone, Debug, PartialEq)] 201 | pub enum Decl { 202 | Func { 203 | sign: FuncSign, 204 | body: Expr, 205 | span: Span, 206 | }, 207 | Data { 208 | ident: Ident, 209 | polys: Vec, 210 | vars: Vec, 211 | span: Span, 212 | }, 213 | } 214 | 215 | impl Expr { 216 | pub fn get_span(&self) -> &Span { 217 | match self { 218 | Expr::Lit { span, .. } => span, 219 | Expr::Var { span, .. } => span, 220 | Expr::Prim { span, .. } => span, 221 | Expr::Cons { span, .. } => span, 222 | Expr::Func { span, .. } => span, 223 | Expr::App { span, .. } => span, 224 | Expr::Ifte { span, .. } => span, 225 | Expr::Case { span, .. } => span, 226 | Expr::Field { span, .. } => span, 227 | Expr::NewRef { span, .. } => span, 228 | Expr::RefGet { span, .. } => span, 229 | Expr::Stmt { span, .. } => span, 230 | } 231 | } 232 | } 233 | 234 | impl Stmt { 235 | pub fn get_span(&self) -> &Span { 236 | match self { 237 | Stmt::Let { span, .. } => span, 238 | Stmt::RefSet { span, .. } => span, 239 | Stmt::Assign { span, .. } => span, 240 | Stmt::While { span, .. } => span, 241 | Stmt::Do { span, .. } => span, 242 | } 243 | } 244 | } 245 | 246 | impl Decl { 247 | pub fn get_span(&self) -> &Span { 248 | match self { 249 | Decl::Func { span, .. } => span, 250 | Decl::Data { span, .. } => span, 251 | } 252 | } 253 | } 254 | 255 | #[derive(Clone, Debug, PartialEq)] 256 | pub struct Module { 257 | pub name: Ident, 258 | pub decls: Vec, 259 | } 260 | -------------------------------------------------------------------------------- /src/analyze/unify.rs: -------------------------------------------------------------------------------- 1 | use crate::syntax::ast::{LitType, Type}; 2 | use crate::utils::ident::Ident; 3 | use std::collections::HashMap; 4 | use std::ops::Deref; 5 | 6 | #[derive(Clone, Debug, PartialEq, Eq)] 7 | pub enum UnifyType { 8 | Lit(LitType), 9 | Var(Ident), 10 | Cons(Ident, Vec), 11 | Func(Vec, Box), 12 | Cell(usize), 13 | } 14 | 15 | impl From<&Type> for UnifyType { 16 | fn from(value: &Type) -> Self { 17 | match value { 18 | Type::Lit { lit, span: _ } => UnifyType::Lit(*lit), 19 | Type::Var { ident, span: _ } => UnifyType::Var(*ident), 20 | Type::Cons { 21 | cons, 22 | args, 23 | span: _, 24 | } => { 25 | let args = args.iter().map(|arg| arg.into()).collect(); 26 | UnifyType::Cons(*cons, args) 27 | } 28 | Type::Func { pars, res, span: _ } => { 29 | let pars = pars.iter().map(|par| par.into()).collect(); 30 | let res = Box::new(res.deref().into()); 31 | UnifyType::Func(pars, res) 32 | } 33 | } 34 | } 35 | } 36 | 37 | pub enum UnifyError { 38 | VecDiffLen(Vec, Vec), 39 | CannotUnify(UnifyType, UnifyType), 40 | OccurCheckFailed(usize, UnifyType), 41 | } 42 | 43 | type UnifyResult = Result<(), UnifyError>; 44 | 45 | pub struct UnifySolver { 46 | arena: Vec>, 47 | } 48 | 49 | impl UnifySolver { 50 | pub fn new() -> UnifySolver { 51 | UnifySolver { arena: Vec::new() } 52 | } 53 | 54 | pub fn new_cell(&mut self) -> usize { 55 | self.arena.push(None); 56 | self.arena.len() - 1 57 | } 58 | 59 | pub fn unify_many(&mut self, typs1: &Vec, typs2: &Vec) -> UnifyResult { 60 | if typs1.len() != typs2.len() { 61 | Err(UnifyError::VecDiffLen(typs1.clone(), typs2.clone())) 62 | } else { 63 | for (typ1, typ2) in typs1.iter().zip(typs2.iter()) { 64 | self.unify(typ1, typ2)?; 65 | } 66 | Ok(()) 67 | } 68 | } 69 | 70 | pub fn unify(&mut self, typ1: &UnifyType, typ2: &UnifyType) -> UnifyResult { 71 | match (typ1, typ2) { 72 | (UnifyType::Lit(lit1), UnifyType::Lit(lit2)) if lit1 == lit2 => Ok(()), 73 | (UnifyType::Var(ident1), UnifyType::Var(ident2)) if ident1 == ident2 => Ok(()), 74 | (UnifyType::Cons(cons1, args1), UnifyType::Cons(cons2, args2)) if cons1 == cons2 => { 75 | self.unify_many(args1, args2)?; 76 | Ok(()) 77 | } 78 | 79 | (UnifyType::Func(pars1, res1), UnifyType::Func(pars2, res2)) => { 80 | self.unify_many(pars1, pars2)?; 81 | self.unify(res1, res2)?; 82 | Ok(()) 83 | } 84 | (UnifyType::Cell(cell), typ) | (typ, UnifyType::Cell(cell)) => self.assign(*cell, typ), 85 | (typ1, typ2) => Err(UnifyError::CannotUnify(typ1.clone(), typ2.clone())), 86 | } 87 | } 88 | 89 | pub fn assign(&mut self, cell: usize, typ: &UnifyType) -> UnifyResult { 90 | if let Some(typ2) = &self.arena[cell] { 91 | // avoid clone somehow? 92 | self.unify(typ, &typ2.clone()) 93 | } else { 94 | if self.occur_check(cell, typ) { 95 | Err(UnifyError::OccurCheckFailed(cell, typ.clone())) 96 | } else { 97 | self.arena[cell] = Some(typ.clone()); 98 | Ok(()) 99 | } 100 | } 101 | } 102 | 103 | pub fn occur_check(&self, cell: usize, typ: &UnifyType) -> bool { 104 | match typ { 105 | UnifyType::Lit(_) => false, 106 | UnifyType::Var(_) => false, 107 | UnifyType::Cons(_, args) => args.iter().any(|arg| self.occur_check(cell, arg)), 108 | UnifyType::Func(pars, res) => pars 109 | .iter() 110 | .chain(std::iter::once(res.deref())) 111 | .any(|x| self.occur_check(cell, x)), 112 | UnifyType::Cell(cell2) if cell == *cell2 => true, 113 | UnifyType::Cell(cell2) => { 114 | if let Some(typ2) = &self.arena[*cell2] { 115 | self.occur_check(cell, typ2) 116 | } else { 117 | false 118 | } 119 | } 120 | } 121 | } 122 | 123 | pub fn merge(&self, typ: &UnifyType) -> UnifyType { 124 | match typ { 125 | UnifyType::Cons(cons, args) => { 126 | let args = args.iter().map(|arg| self.merge(arg)).collect(); 127 | UnifyType::Cons(*cons, args) 128 | } 129 | UnifyType::Func(pars, res) => { 130 | let pars = pars.iter().map(|par| self.merge(par)).collect(); 131 | let res = Box::new(self.merge(res)); 132 | UnifyType::Func(pars, res) 133 | } 134 | UnifyType::Cell(cell) => { 135 | if self.arena[*cell].is_some() { 136 | self.merge(self.arena[*cell].as_ref().unwrap()) 137 | } else { 138 | UnifyType::Cell(*cell) 139 | } 140 | } 141 | other => other.clone(), 142 | } 143 | } 144 | } 145 | 146 | pub fn substitute(map: &HashMap, typ: &UnifyType) -> UnifyType { 147 | match typ { 148 | UnifyType::Lit(lit) => UnifyType::Lit(*lit), 149 | UnifyType::Var(ident) => { 150 | if let Some(cell) = map.get(ident) { 151 | UnifyType::Cell(*cell) 152 | } else { 153 | UnifyType::Var(*ident) 154 | } 155 | } 156 | UnifyType::Cons(cons, args) => { 157 | let args = args.iter().map(|arg| substitute(map, arg)).collect(); 158 | UnifyType::Cons(*cons, args) 159 | } 160 | UnifyType::Func(pars, res) => { 161 | let pars = pars.iter().map(|par| substitute(map, par)).collect(); 162 | let res = Box::new(substitute(map, res)); 163 | UnifyType::Func(pars, res) 164 | } 165 | UnifyType::Cell(cell) => UnifyType::Cell(*cell), 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/core/rename.rs: -------------------------------------------------------------------------------- 1 | use super::cps::*; 2 | use crate::utils::env_map::EnvMap; 3 | use crate::utils::ident::Ident; 4 | 5 | pub struct Renamer { 6 | context: EnvMap, 7 | } 8 | 9 | impl Renamer { 10 | pub fn run(modl: &mut Module) { 11 | let mut pass = Renamer { 12 | context: EnvMap::new(), 13 | }; 14 | pass.visit_module(modl); 15 | } 16 | 17 | fn visit_bind(&mut self, bind: &mut Ident) { 18 | let new = bind.uniquify(); 19 | self.context.insert(*bind, new); 20 | *bind = new; 21 | } 22 | 23 | fn visit_atom(&mut self, atom: &mut Atom) { 24 | if let Atom::Var(x) = atom { 25 | if let Some(y) = self.context.get(&x) { 26 | *atom = Atom::Var(*y); 27 | } 28 | } 29 | } 30 | 31 | fn visit_module(&mut self, modl: &mut Module) { 32 | let Module { name: _, decls } = modl; 33 | self.context.enter_scope(); 34 | for decl in decls.iter_mut() { 35 | self.visit_bind(&mut decl.func); 36 | } 37 | for decl in decls { 38 | self.visit_func_decl(decl); 39 | } 40 | self.context.leave_scope() 41 | } 42 | 43 | fn visit_func_decl(&mut self, decl: &mut FuncDecl) { 44 | let FuncDecl { 45 | func: _, 46 | cont, 47 | pars, 48 | body, 49 | } = decl; 50 | self.context.enter_scope(); 51 | self.visit_bind(cont); 52 | for par in pars.iter_mut() { 53 | self.visit_bind(par); 54 | } 55 | self.visit_expr(body); 56 | self.context.leave_scope(); 57 | } 58 | 59 | fn visit_cont_decl(&mut self, decl: &mut ContDecl) { 60 | let ContDecl { 61 | cont: _, 62 | pars, 63 | body, 64 | } = decl; 65 | self.context.enter_scope(); 66 | for par in pars.iter_mut() { 67 | self.visit_bind(par); 68 | } 69 | self.visit_expr(body); 70 | self.context.leave_scope(); 71 | } 72 | 73 | fn visit_expr(&mut self, expr: &mut Expr) { 74 | match expr { 75 | Expr::Decls { funcs, conts, body } => { 76 | self.context.enter_scope(); 77 | for decl in funcs.iter_mut() { 78 | self.visit_bind(&mut decl.func); 79 | } 80 | for decl in conts.iter_mut() { 81 | self.visit_bind(&mut decl.cont); 82 | } 83 | for decl in funcs { 84 | self.visit_func_decl(decl); 85 | } 86 | for decl in conts { 87 | self.visit_cont_decl(decl); 88 | } 89 | self.visit_expr(body); 90 | self.context.leave_scope() 91 | } 92 | Expr::Prim { 93 | bind, 94 | prim: _, 95 | args, 96 | rest, 97 | } => { 98 | args.iter_mut().for_each(|arg| self.visit_atom(arg)); 99 | self.context.enter_scope(); 100 | self.visit_bind(bind); 101 | self.visit_expr(rest); 102 | self.context.leave_scope() 103 | } 104 | Expr::Record { bind, args, rest } => { 105 | args.iter_mut().for_each(|arg| self.visit_atom(&mut arg.1)); 106 | self.context.enter_scope(); 107 | self.visit_bind(bind); 108 | self.visit_expr(rest); 109 | self.context.leave_scope() 110 | } 111 | Expr::Select { 112 | bind, 113 | rec, 114 | idx: _, 115 | rest, 116 | } => { 117 | self.visit_atom(rec); 118 | self.context.enter_scope(); 119 | self.visit_bind(bind); 120 | self.visit_expr(rest); 121 | self.context.leave_scope() 122 | } 123 | Expr::Update { 124 | rec, 125 | idx: _, 126 | arg, 127 | rest, 128 | } => { 129 | self.visit_atom(rec); 130 | self.visit_atom(arg); 131 | self.context.enter_scope(); 132 | self.visit_expr(rest); 133 | self.context.leave_scope() 134 | } 135 | Expr::Call { func, cont, args } => { 136 | let new = *self.context.get(func).unwrap(); 137 | *func = new; 138 | let new = *self.context.get(cont).unwrap(); 139 | *cont = new; 140 | args.iter_mut().for_each(|arg| self.visit_atom(arg)); 141 | } 142 | Expr::Jump { cont, args } => { 143 | let new = *self.context.get(cont).unwrap(); 144 | *cont = new; 145 | args.iter_mut().for_each(|arg| self.visit_atom(arg)); 146 | } 147 | Expr::Ifte { 148 | cond: _, 149 | args, 150 | trbr, 151 | flbr, 152 | } => { 153 | args.iter_mut().for_each(|arg| self.visit_atom(arg)); 154 | self.visit_expr(trbr); 155 | self.visit_expr(flbr); 156 | } 157 | Expr::Switch { arg, brchs, dflt } => { 158 | self.visit_atom(arg); 159 | for (_, brch) in brchs.iter_mut() { 160 | self.visit_expr(brch); 161 | } 162 | if let Some(dflt) = dflt { 163 | self.visit_expr(dflt) 164 | } 165 | } 166 | Expr::Retn { res } => { 167 | self.visit_atom(res); 168 | } 169 | } 170 | } 171 | } 172 | 173 | #[test] 174 | #[ignore = "just to see result"] 175 | fn rename_test() { 176 | let s = r#" 177 | module Test where 178 | func top1(x, y): 179 | return x; 180 | func top2(x): 181 | decls 182 | func f(k, x, y, z): 183 | jump k(x); 184 | cont k(a): 185 | return a; 186 | in 187 | let x = @iadd(1, 2); 188 | call f(k, 1, 2, 3); 189 | end 190 | "#; 191 | let mut modl = super::parser::parse_module(s).unwrap(); 192 | println!("{}\n", modl); 193 | Renamer::run(&mut modl); 194 | println!("{}\n", modl); 195 | } 196 | -------------------------------------------------------------------------------- /src/syntax/prim.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::str::FromStr; 3 | 4 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 5 | pub enum Compare { 6 | Lt, 7 | Le, 8 | Eq, 9 | Ge, 10 | Gt, 11 | Ne, 12 | } 13 | 14 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 15 | pub enum Prim { 16 | // arithmethics 17 | IAdd, 18 | ISub, 19 | IMul, 20 | IDiv, 21 | IRem, 22 | INeg, 23 | FAdd, 24 | FSub, 25 | FMul, 26 | FDiv, 27 | FNeg, 28 | // boolean 29 | BAnd, 30 | BOr, 31 | BNot, 32 | // comparision 33 | ICmp(Compare), 34 | FCmp(Compare), 35 | // move 36 | Move, 37 | // memory operation 38 | Alloc, 39 | Load, 40 | Store, 41 | // print and scan 42 | IPrint, 43 | IScan, 44 | FPrint, 45 | FScan, 46 | CPrint, 47 | CScan, 48 | Assert, 49 | } 50 | 51 | impl Prim { 52 | pub fn get_arity(&self) -> usize { 53 | match self { 54 | Prim::IAdd => 2, 55 | Prim::ISub => 2, 56 | Prim::IMul => 2, 57 | Prim::IDiv => 2, 58 | Prim::IRem => 2, 59 | Prim::INeg => 1, 60 | Prim::FAdd => 2, 61 | Prim::FSub => 2, 62 | Prim::FMul => 2, 63 | Prim::FDiv => 2, 64 | Prim::FNeg => 1, 65 | Prim::BAnd => 2, 66 | Prim::BOr => 2, 67 | Prim::BNot => 1, 68 | Prim::ICmp(_) => 2, 69 | Prim::FCmp(_) => 2, 70 | Prim::Move => 1, 71 | Prim::Alloc => 1, 72 | Prim::Load => 2, 73 | Prim::Store => 3, 74 | Prim::IPrint => 1, 75 | Prim::IScan => 0, 76 | Prim::FPrint => 1, 77 | Prim::FScan => 0, 78 | Prim::CPrint => 1, 79 | Prim::CScan => 0, 80 | Prim::Assert => 1, 81 | } 82 | } 83 | 84 | pub fn is_pure(&self) -> bool { 85 | match self { 86 | Prim::IAdd => true, 87 | Prim::ISub => true, 88 | Prim::IMul => true, 89 | Prim::IDiv => true, 90 | Prim::IRem => true, 91 | Prim::INeg => true, 92 | Prim::FAdd => true, 93 | Prim::FSub => true, 94 | Prim::FMul => true, 95 | Prim::FDiv => true, 96 | Prim::FNeg => true, 97 | Prim::BAnd => true, 98 | Prim::BOr => true, 99 | Prim::BNot => true, 100 | Prim::ICmp(_) => true, 101 | Prim::FCmp(_) => true, 102 | Prim::Move => true, 103 | Prim::Alloc => false, 104 | Prim::Load => false, 105 | Prim::Store => false, 106 | Prim::IPrint => false, 107 | Prim::IScan => false, 108 | Prim::FPrint => false, 109 | Prim::FScan => false, 110 | Prim::CPrint => false, 111 | Prim::CScan => false, 112 | Prim::Assert => false, 113 | } 114 | } 115 | } 116 | 117 | impl fmt::Display for Compare { 118 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 119 | match self { 120 | Compare::Lt => "lt".fmt(f), 121 | Compare::Le => "le".fmt(f), 122 | Compare::Eq => "eq".fmt(f), 123 | Compare::Ge => "ge".fmt(f), 124 | Compare::Gt => "gt".fmt(f), 125 | Compare::Ne => "ne".fmt(f), 126 | } 127 | } 128 | } 129 | 130 | impl fmt::Display for Prim { 131 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 132 | match self { 133 | Prim::IAdd => "@iadd".fmt(f), 134 | Prim::ISub => "@isub".fmt(f), 135 | Prim::IMul => "@imul".fmt(f), 136 | Prim::IDiv => "@idiv".fmt(f), 137 | Prim::IRem => "@irem".fmt(f), 138 | Prim::INeg => "@ineg".fmt(f), 139 | Prim::FAdd => "@fadd".fmt(f), 140 | Prim::FSub => "@fsub".fmt(f), 141 | Prim::FMul => "@fmul".fmt(f), 142 | Prim::FDiv => "@fdiv".fmt(f), 143 | Prim::FNeg => "@fneg".fmt(f), 144 | Prim::BAnd => "@band".fmt(f), 145 | Prim::BOr => "@bor".fmt(f), 146 | Prim::BNot => "@bnot".fmt(f), 147 | Prim::ICmp(Compare::Lt) => "@icmplt".fmt(f), 148 | Prim::ICmp(Compare::Le) => "@icmple".fmt(f), 149 | Prim::ICmp(Compare::Eq) => "@icmpeq".fmt(f), 150 | Prim::ICmp(Compare::Ge) => "@icmpge".fmt(f), 151 | Prim::ICmp(Compare::Gt) => "@icmpgr".fmt(f), 152 | Prim::ICmp(Compare::Ne) => "@icmpne".fmt(f), 153 | Prim::FCmp(Compare::Lt) => "@fcmplt".fmt(f), 154 | Prim::FCmp(Compare::Le) => "@fcmple".fmt(f), 155 | Prim::FCmp(Compare::Eq) => "@fcmpeq".fmt(f), 156 | Prim::FCmp(Compare::Ge) => "@fcmpge".fmt(f), 157 | Prim::FCmp(Compare::Gt) => "@fcmpgr".fmt(f), 158 | Prim::FCmp(Compare::Ne) => "@fcmpne".fmt(f), 159 | Prim::Move => "@move".fmt(f), 160 | Prim::Alloc => "@alloc".fmt(f), 161 | Prim::Load => "@load".fmt(f), 162 | Prim::Store => "@store".fmt(f), 163 | Prim::IPrint => "@iprint".fmt(f), 164 | Prim::IScan => "@iscan".fmt(f), 165 | Prim::FPrint => "@fprint".fmt(f), 166 | Prim::FScan => "@fscan".fmt(f), 167 | Prim::CPrint => "@cprint".fmt(f), 168 | Prim::CScan => "@cscan".fmt(f), 169 | Prim::Assert => "@assert".fmt(f), 170 | } 171 | } 172 | } 173 | 174 | impl FromStr for Prim { 175 | type Err = (); 176 | fn from_str(s: &str) -> Result { 177 | match s { 178 | "@iadd" => Ok(Prim::IAdd), 179 | "@isub" => Ok(Prim::ISub), 180 | "@imul" => Ok(Prim::IMul), 181 | "@idiv" => Ok(Prim::IDiv), 182 | "@irem" => Ok(Prim::IRem), 183 | "@ineg" => Ok(Prim::INeg), 184 | "@fadd" => Ok(Prim::FAdd), 185 | "@fsub" => Ok(Prim::FSub), 186 | "@fmul" => Ok(Prim::FMul), 187 | "@fdiv" => Ok(Prim::FDiv), 188 | "@fneg" => Ok(Prim::FNeg), 189 | "@band" => Ok(Prim::BAnd), 190 | "@bor" => Ok(Prim::BOr), 191 | "@bnot" => Ok(Prim::BNot), 192 | "@icmplt" => Ok(Prim::ICmp(Compare::Lt)), 193 | "@icmple" => Ok(Prim::ICmp(Compare::Le)), 194 | "@icmpeq" => Ok(Prim::ICmp(Compare::Eq)), 195 | "@icmpge" => Ok(Prim::ICmp(Compare::Ge)), 196 | "@icmpgt" => Ok(Prim::ICmp(Compare::Gt)), 197 | "@icmpne" => Ok(Prim::ICmp(Compare::Ne)), 198 | "@fcmplt" => Ok(Prim::FCmp(Compare::Lt)), 199 | "@fcmple" => Ok(Prim::FCmp(Compare::Le)), 200 | "@fcmpeq" => Ok(Prim::FCmp(Compare::Eq)), 201 | "@fcmpge" => Ok(Prim::FCmp(Compare::Ge)), 202 | "@fcmpgt" => Ok(Prim::FCmp(Compare::Gt)), 203 | "@fcmpne" => Ok(Prim::FCmp(Compare::Ne)), 204 | "@move" => Ok(Prim::Move), 205 | "@alloc" => Ok(Prim::Alloc), 206 | "@load" => Ok(Prim::Load), 207 | "@store" => Ok(Prim::Store), 208 | "@iprint" => Ok(Prim::IPrint), 209 | "@iscan" => Ok(Prim::IScan), 210 | "@fprint" => Ok(Prim::FPrint), 211 | "@fscan" => Ok(Prim::FScan), 212 | "@cprint" => Ok(Prim::CPrint), 213 | "@cscan" => Ok(Prim::CScan), 214 | "@assert" => Ok(Prim::Assert), 215 | _ => Err(()), 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /examples/Game2048.nr: -------------------------------------------------------------------------------- 1 | module Game2048 where 2 | 3 | datatype List[T] where 4 | | Nil 5 | | Cons(T, List[T]) 6 | end 7 | 8 | function is_empty[T](xs: List[T]) -> Bool 9 | begin 10 | match xs with 11 | | Nil => true 12 | | Cons(x, xs) => false 13 | end 14 | end 15 | 16 | function reverse_concat[T](xs: List[T], ys: List[T]) -> List[T] 17 | begin 18 | match xs with 19 | | Nil => ys 20 | | Cons(x, rest) => reverse_concat(rest, Cons(x, ys)) 21 | end 22 | end 23 | 24 | function reverse[T](xs: List[T]) -> List[T] 25 | begin 26 | reverse_concat(xs, Nil) 27 | end 28 | 29 | function concat[T](xs: List[T], ys: List[T]) -> List[T] 30 | begin 31 | reverse_concat(reverse(xs), ys) 32 | end 33 | 34 | function length[T](xs: List[T]) -> Int 35 | begin 36 | match xs with 37 | | Nil => 0 38 | | Cons(x, xs) => length(xs) + 1 39 | end 40 | end 41 | 42 | function list_map[T, U](f: fn(T) -> U, xs: List[T]) -> List[U] 43 | begin 44 | match xs with 45 | | Nil => Nil 46 | | Cons(x, rest) => Cons(f(x), list_map(f, rest)) 47 | end 48 | end 49 | 50 | function list_flat_map[T, U](f: fn(T) -> Option[U], xs: List[T]) -> List[U] 51 | begin 52 | match xs with 53 | | Nil => Nil 54 | | Cons(x, rest) => 55 | match f(x) with 56 | | Some(res) => Cons(res, list_flat_map(f, rest)) 57 | | None => list_flat_map(f, rest) 58 | end 59 | end 60 | end 61 | 62 | function list_iter[T](f: fn(T) -> (), xs: List[T]) -> () 63 | begin 64 | match xs with 65 | | Nil => () 66 | | Cons(x, rest) => 67 | begin 68 | f(x); 69 | list_iter(f, rest); 70 | end 71 | end 72 | end 73 | 74 | function list_count[T](f: fn(T) -> Bool, xs: List[T]) -> Int 75 | begin 76 | match xs with 77 | | Nil => 0 78 | | Cons(x, rest) => if f(x) then list_count(f, rest) + 1 else list_count(f, rest) 79 | end 80 | end 81 | 82 | function list_all[T](f: fn(T) -> Bool, xs: List[T]) -> Bool 83 | begin 84 | match xs with 85 | | Nil => true 86 | | Cons(x, rest) => if f(x) then list_all(f, rest) else false 87 | end 88 | end 89 | 90 | function repeat[T](x: T, n: Int) -> List[T] 91 | begin 92 | if n < 1 then Nil 93 | else Cons(x, repeat(x, n - 1)) 94 | end 95 | 96 | function repeat_init[T](f: fn() -> T, n: Int) -> List[T] 97 | begin 98 | if n < 1 then Nil 99 | else Cons(f(), repeat_init(f, n - 1)) 100 | end 101 | 102 | function transpose[T](mat: List[List[T]]) -> List[List[T]] 103 | begin 104 | Nil 105 | end 106 | 107 | datatype Option[T] where 108 | | None 109 | | Some(T) 110 | end 111 | 112 | function next_random(n: Int) -> Int 113 | begin 114 | // Borland C random number generator implementation 115 | (22695477 * n + 1) % 2147483648 116 | end 117 | 118 | datatype GameBoard where 119 | | GameBoard { 120 | random: mut Int, 121 | matrix: mut List[List[Int]], 122 | } 123 | end 124 | 125 | function count_zeros(matrix: List[List[Int]]) -> Int 126 | begin 127 | let count = ref 0; 128 | list_iter(fn(row) => 129 | list_iter(fn(elem) => 130 | if elem == 0 then 131 | begin 132 | count <- ^count + 1; 133 | end 134 | else (), 135 | row, 136 | ), 137 | matrix, 138 | ); 139 | ^count 140 | end 141 | 142 | function print_matrix(matrix: List[List[Int]]) 143 | begin 144 | @cprint('\n'); 145 | list_iter(fn(row) => 146 | begin 147 | list_iter(fn(elem) => 148 | begin 149 | @iprint(elem); 150 | @cprint(' '); 151 | end, 152 | row, 153 | ); 154 | @cprint('\n'); 155 | end, 156 | matrix, 157 | ); 158 | end 159 | 160 | function squash_line(xs: List[Int]) -> List[Int] 161 | begin 162 | match xs with 163 | | Nil => xs 164 | | Cons(x, Nil) => 165 | if x == 0 then Nil else xs 166 | | Cons(x, rest1) => 167 | if x == 0 then 168 | squash_line(rest1) 169 | else 170 | match squash_line(rest1) with 171 | | Nil => Cons(x, Nil) 172 | | Cons(y, rest2) => 173 | if x == y then 174 | Cons(x + y, rest2) 175 | else 176 | Cons(x, Cons(y, rest2)) 177 | end 178 | end 179 | end 180 | 181 | function game_step(board: GameBoard) 182 | begin 183 | let rows = board.matrix; 184 | let rows = list_map( 185 | fn(row) => begin 186 | let head = squash_line(row); 187 | let tail = repeat(0, 4 - length(head)); 188 | concat(head, tail) 189 | end, 190 | rows, 191 | ); 192 | board.matrix := rows; 193 | end 194 | 195 | function create_new(board: GameBoard) 196 | begin 197 | let rows = board.matrix; 198 | let zeros = count_zeros(board.matrix); 199 | if zeros == 0 then () 200 | else 201 | begin 202 | let seed = ref (board.random % zeros); 203 | let rows = list_map( 204 | fn(row) => begin 205 | list_map( 206 | fn(elem) => begin 207 | if elem == 0 then 208 | begin 209 | let old = ^seed; 210 | seed <- ^seed - 1; 211 | if old == 0 then 1 else 0 212 | end 213 | else elem 214 | end, 215 | row, 216 | ) 217 | end, 218 | rows, 219 | ); 220 | board.matrix := rows; 221 | end 222 | end 223 | 224 | function transpose_matrix(matrix: List[List[Int]]) -> List[List[Int]] 225 | begin 226 | if is_empty(matrix) then 227 | Nil 228 | else 229 | begin 230 | let first_col = ref Nil; 231 | let rest_matrix = ref Nil; 232 | list_iter( 233 | fn(row) => 234 | match row with 235 | | Cons(x, xs) => 236 | begin 237 | // why can't I uncomment this line? 238 | let m : List[Int] = ^first_col; 239 | 240 | first_col <- Cons(x, ^first_col); 241 | if is_empty(xs) then 242 | () 243 | else 244 | begin 245 | rest_matrix <- Cons(xs, ^rest_matrix); 246 | end 247 | ; 248 | end 249 | | Nil => () 250 | end 251 | , 252 | matrix, 253 | ); 254 | Cons( 255 | reverse(^first_col), 256 | transpose_matrix(reverse(^rest_matrix)), 257 | ) 258 | end 259 | end 260 | 261 | function reverse_matrix(matrix: List[List[Int]]) -> List[List[Int]] 262 | begin 263 | list_map( 264 | fn(row) => reverse(row), 265 | matrix, 266 | ) 267 | end 268 | 269 | 270 | function main() -> Int 271 | begin 272 | let seed = @iscan(); 273 | let matrix = repeat(repeat(0, 4), 4); 274 | let game = GameBoard { random: seed, matrix }; 275 | 276 | while count_zeros(game.matrix) != 0 do 277 | // print matrix 278 | print_matrix(game.matrix); 279 | // get input 280 | let input = @iscan(); 281 | 282 | if input == 4 then 283 | begin 284 | game_step(game); 285 | end 286 | else if input == 8 then 287 | begin 288 | game.matrix := transpose_matrix(game.matrix); 289 | game_step(game); 290 | game.matrix := transpose_matrix(game.matrix); 291 | end 292 | else if input == 2 then 293 | begin 294 | game.matrix := transpose_matrix(game.matrix); 295 | game.matrix := reverse_matrix(game.matrix); 296 | game_step(game); 297 | game.matrix := reverse_matrix(game.matrix); 298 | game.matrix := transpose_matrix(game.matrix); 299 | end 300 | else if input == 6 then 301 | begin 302 | game.matrix := reverse_matrix(game.matrix); 303 | game_step(game); 304 | game.matrix := reverse_matrix(game.matrix); 305 | end 306 | else 307 | (); 308 | 309 | // generate new number 310 | create_new(game); 311 | 312 | // update random number 313 | game.random := next_random(game.random); 314 | end; 315 | 316 | print_matrix(game.matrix); 317 | 0 318 | end 319 | -------------------------------------------------------------------------------- /src/analyze/diagnostic.rs: -------------------------------------------------------------------------------- 1 | use crate::syntax::lexer::Span; 2 | use std::fmt; 3 | 4 | #[derive(Debug, Clone, PartialEq, Eq)] 5 | pub struct LineCol { 6 | line: usize, 7 | col: usize, 8 | } 9 | 10 | impl fmt::Display for LineCol { 11 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 12 | let LineCol { line, col } = self; 13 | // index starts from 0 internally, but prints from 1 14 | write!(f, "line {}, col {}", line + 1, col + 1) 15 | } 16 | } 17 | 18 | fn get_line_col_vec(source: &str) -> Vec { 19 | let mut vec = Vec::with_capacity(source.len()); 20 | let mut line = 0; 21 | let mut col = 0; 22 | for ch in source.chars() { 23 | vec.push(LineCol { line, col }); 24 | if ch == '\n' { 25 | line += 1; 26 | col = 0; 27 | } else { 28 | col += 1; 29 | } 30 | } 31 | vec 32 | } 33 | 34 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 35 | pub enum DiagLevel { 36 | Error, 37 | Warn, 38 | Info, 39 | } 40 | 41 | impl fmt::Display for DiagLevel { 42 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 | match self { 44 | DiagLevel::Error => write!(f, "Error"), 45 | DiagLevel::Warn => write!(f, "Warn"), 46 | DiagLevel::Info => write!(f, "Info"), 47 | } 48 | } 49 | } 50 | 51 | #[derive(Debug, Clone, PartialEq, Eq)] 52 | pub struct Description { 53 | verbosity: u8, 54 | message: String, 55 | span: Option, 56 | } 57 | 58 | impl Description { 59 | pub fn message>(msg: S) -> Description { 60 | Description { 61 | verbosity: 10, 62 | message: msg.into(), 63 | span: None, 64 | } 65 | } 66 | 67 | pub fn with_span(mut self, span: Span) -> Description { 68 | self.span = Some(span); 69 | self 70 | } 71 | 72 | pub fn with_verbosity(mut self, verbosity: u8) -> Description { 73 | self.verbosity = verbosity; 74 | self 75 | } 76 | } 77 | 78 | #[derive(Clone, Debug, PartialEq)] 79 | pub struct Diagnostic { 80 | level: DiagLevel, 81 | title: String, 82 | descriptions: Vec, 83 | } 84 | 85 | impl Diagnostic { 86 | pub fn error>(title: S) -> Diagnostic { 87 | Diagnostic { 88 | level: DiagLevel::Error, 89 | title: title.into(), 90 | descriptions: Vec::new(), 91 | } 92 | } 93 | 94 | pub fn warn>(title: S) -> Diagnostic { 95 | Diagnostic { 96 | level: DiagLevel::Warn, 97 | title: title.into(), 98 | descriptions: Vec::new(), 99 | } 100 | } 101 | 102 | pub fn info>(title: S) -> Diagnostic { 103 | Diagnostic { 104 | level: DiagLevel::Info, 105 | title: title.into(), 106 | descriptions: Vec::new(), 107 | } 108 | } 109 | 110 | pub fn line>(mut self, msg: S) -> Diagnostic { 111 | self.descriptions.push(Description::message(msg)); 112 | self 113 | } 114 | 115 | pub fn line_span>(mut self, span: Span, msg: S) -> Diagnostic { 116 | self.descriptions 117 | .push(Description::message(msg).with_span(span)); 118 | self 119 | } 120 | 121 | pub fn line_verb>(mut self, verbosity: u8, msg: S) -> Diagnostic { 122 | self.descriptions 123 | .push(Description::message(msg).with_verbosity(verbosity)); 124 | self 125 | } 126 | 127 | pub fn line_span_verb>( 128 | mut self, 129 | span: Span, 130 | verbosity: u8, 131 | msg: S, 132 | ) -> Diagnostic { 133 | self.descriptions.push( 134 | Description::message(msg) 135 | .with_span(span) 136 | .with_verbosity(verbosity), 137 | ); 138 | self 139 | } 140 | 141 | /// minimal_report shows only spans, instead of source code. 142 | pub fn minimal_report(&self, source: &str, verbosity: u8) -> String { 143 | let mut output = format!("[{}]: {}\n", self.level, &self.title); 144 | let linecol = get_line_col_vec(source); 145 | for descr in &self.descriptions { 146 | if descr.verbosity > verbosity { 147 | // ignore those description with higher verbosity 148 | continue; 149 | } 150 | match &descr.span { 151 | Some(span) => { 152 | output.push_str(&format!( 153 | "{} - {}:\n{}\n", 154 | linecol[span.start], linecol[span.end], descr.message, 155 | )); 156 | } 157 | None => { 158 | output.push_str(&descr.message); 159 | output.push('\n'); 160 | } 161 | } 162 | } 163 | output 164 | } 165 | 166 | pub fn report(&self, source: &str, verbosity: u8) -> String { 167 | let mut output = format!("[{}]: {}\n", self.level, &self.title); 168 | let linecol = get_line_col_vec(source); 169 | for descr in &self.descriptions { 170 | if descr.verbosity > verbosity { 171 | // ignore those description with higher verbosity 172 | continue; 173 | } 174 | match &descr.span { 175 | Some(span) => { 176 | let start_line = linecol[span.start].line; 177 | let start_col = linecol[span.start].col; 178 | let end_line = linecol[span.end].line; 179 | let end_col = linecol[span.end].col; 180 | let text = source.lines().collect::>(); 181 | let mut vec: Vec<(usize, usize)> = Vec::new(); 182 | if start_line == end_line { 183 | vec.push((start_col, end_col)) 184 | } else { 185 | for line in start_line..=end_line { 186 | if line == start_line { 187 | vec.push((start_col, text[line].chars().count())) 188 | } else if line == end_line { 189 | vec.push((0, end_col)) 190 | } else { 191 | vec.push((0, text[line].chars().count())) 192 | } 193 | } 194 | } 195 | 196 | let head_width = (1 + end_line).to_string().len(); 197 | for (line, (s, e)) in (start_line..=end_line).zip(vec.into_iter()) { 198 | // print header "xxx | ", where xxx is the line number 199 | output.push_str(&format!("{:head_width$} | {}\n", line + 1, text[line])); 200 | output.push_str(&format!("{:head_width$} | ", ' ')); 201 | for _ in 0..s { 202 | output.push(' '); 203 | } 204 | if line == start_line { 205 | output.push('^'); 206 | for _ in s + 1..e { 207 | output.push('~'); 208 | } 209 | } else if line == end_line { 210 | for _ in s..e { 211 | output.push('~'); 212 | } 213 | output.push('^'); 214 | } else { 215 | for _ in s..e { 216 | output.push('~'); 217 | } 218 | } 219 | output.push('\n'); 220 | } 221 | output.push_str(&descr.message); 222 | output.push('\n'); 223 | } 224 | None => { 225 | output.push_str(&descr.message); 226 | output.push('\n'); 227 | } 228 | } 229 | } 230 | output 231 | } 232 | } 233 | 234 | #[test] 235 | fn diagnostic_test() { 236 | let source = r#"1234567890 237 | 1234567890 238 | 1234567890 239 | "#; 240 | 241 | let span = Span { start: 6, end: 25 }; 242 | let diag = Diagnostic::error("Error Name") 243 | .line("some error discreption") 244 | .line_span(span, "some spanned error discreption") 245 | .line_verb(100, "this should not appear!"); 246 | 247 | assert_eq!( 248 | diag.minimal_report(source, 30), 249 | r#"[Error]: Error Name 250 | some error discreption 251 | line 1, col 7 - line 3, col 4: 252 | some spanned error discreption 253 | "# 254 | ); 255 | assert_eq!( 256 | diag.report(source, 30), 257 | r#"[Error]: Error Name 258 | some error discreption 259 | 1 | 1234567890 260 | | ^~~~ 261 | 2 | 1234567890 262 | | ~~~~~~~~~~ 263 | 3 | 1234567890 264 | | ~~~^ 265 | some spanned error discreption 266 | "# 267 | ); 268 | } 269 | -------------------------------------------------------------------------------- /src/core/pattern.rs: -------------------------------------------------------------------------------- 1 | use crate::syntax::ast::{LitVal, Pattern}; 2 | use crate::utils::ident::Ident; 3 | use crate::utils::intern::InternStr; 4 | 5 | pub fn get_bind_vars(patn: &Pattern) -> Vec { 6 | fn aux(vec: &mut Vec, patn: &Pattern) { 7 | match patn { 8 | Pattern::Var { ident, span: _ } => { 9 | vec.push(*ident); 10 | } 11 | Pattern::Lit { .. } => {} 12 | Pattern::Cons { 13 | cons: _, 14 | patns, 15 | as_ident, 16 | span: _, 17 | } => { 18 | if let Some(as_ident) = as_ident { 19 | vec.push(*as_ident); 20 | } 21 | for patn in patns { 22 | aux(vec, &patn.data) 23 | } 24 | } 25 | Pattern::Wild { .. } => {} 26 | } 27 | } 28 | let mut vec = Vec::new(); 29 | aux(&mut vec, patn); 30 | vec 31 | } 32 | 33 | fn remove_nth(vec: &Vec, j: usize) -> Vec { 34 | vec[..j] 35 | .iter() 36 | .chain(vec[j + 1..].iter()) 37 | .cloned() 38 | .collect() 39 | } 40 | 41 | fn insert_nth(vec: &Vec, j: usize, vec2: &Vec) -> Vec { 42 | vec[..j] 43 | .iter() 44 | .chain(vec2.into_iter()) 45 | .chain(vec[j + 1..].iter()) 46 | .cloned() 47 | .collect() 48 | } 49 | 50 | #[derive(Debug, Clone)] 51 | pub struct PatnMatrix { 52 | pub objs: Vec, 53 | pub matrix: Vec>, 54 | pub acts: Vec, 55 | } 56 | 57 | pub enum ColType { 58 | Lit, 59 | Cons, 60 | Unknown, 61 | } 62 | 63 | impl PatnMatrix { 64 | pub fn is_empty(&self) -> bool { 65 | self.matrix.is_empty() 66 | } 67 | pub fn first_row_aways_match(&self) -> bool { 68 | assert!(!self.matrix.is_empty()); 69 | self.matrix[0].iter().all(|patn| match patn { 70 | Pattern::Var { .. } => true, 71 | Pattern::Lit { .. } => false, 72 | Pattern::Cons { .. } => false, 73 | Pattern::Wild { .. } => false, 74 | }) 75 | } 76 | pub fn get_row_num(&self) -> usize { 77 | assert_eq!(self.acts.len(), self.matrix.len()); 78 | self.acts.len() 79 | } 80 | pub fn get_col_num(&self) -> usize { 81 | assert!(self.matrix.iter().all(|row| row.len() == self.objs.len())); 82 | self.objs.len() 83 | } 84 | pub fn get_lit_set(&self, j: usize) -> Vec { 85 | let mut vec = Vec::new(); 86 | for row in self.matrix.iter() { 87 | match &row[j] { 88 | Pattern::Lit { lit, .. } => { 89 | vec.push(*lit); 90 | } 91 | Pattern::Var { .. } => {} 92 | Pattern::Cons { .. } => { 93 | unreachable!() 94 | } 95 | Pattern::Wild { .. } => {} 96 | } 97 | } 98 | vec 99 | } 100 | pub fn get_cons_set(&self, j: usize) -> Vec { 101 | let mut vec = Vec::new(); 102 | for row in self.matrix.iter() { 103 | match &row[j] { 104 | Pattern::Lit { .. } => { 105 | unreachable!() 106 | } 107 | Pattern::Var { .. } => {} 108 | Pattern::Cons { cons, .. } => { 109 | vec.push(*cons); 110 | } 111 | Pattern::Wild { .. } => {} 112 | } 113 | } 114 | vec 115 | } 116 | 117 | pub fn get_col_type(&self, j: usize) -> ColType { 118 | for row in self.matrix.iter() { 119 | match row[j] { 120 | Pattern::Var { .. } => {} 121 | Pattern::Lit { .. } => return ColType::Lit, 122 | Pattern::Cons { .. } => return ColType::Cons, 123 | Pattern::Wild { .. } => {} 124 | } 125 | } 126 | ColType::Unknown 127 | } 128 | 129 | // first row always success 130 | // return (bindings, act) 131 | pub fn success(&self) -> (Vec<(Ident, Ident)>, Ident) { 132 | let bindings = self.matrix[0] 133 | .iter() 134 | .zip(self.objs.iter()) 135 | .flat_map(|(patn, obj)| match patn { 136 | Pattern::Var { ident, .. } => Some((*ident, *obj)), 137 | Pattern::Lit { .. } => unreachable!(), 138 | Pattern::Cons { .. } => unreachable!(), 139 | Pattern::Wild { .. } => None, 140 | }) 141 | .collect(); 142 | let act = self.acts[0].clone(); 143 | (bindings, act) 144 | } 145 | 146 | // return (new_mat, hits) 147 | pub fn default(&self, j: usize) -> (PatnMatrix, Vec) { 148 | let objs = remove_nth(&self.objs, j); 149 | let mut hits: Vec = Vec::new(); 150 | let (matrix, acts): (Vec>, Vec<_>) = self 151 | .matrix 152 | .iter() 153 | .zip(self.acts.iter()) 154 | .flat_map(|(row, act)| match &row[j] { 155 | Pattern::Lit { .. } => unreachable!(), 156 | Pattern::Var { ident, .. } => { 157 | hits.push(*ident); 158 | let new_row = remove_nth(row, j); 159 | Some((new_row, *act)) 160 | } 161 | Pattern::Cons { .. } => unreachable!(), 162 | Pattern::Wild { .. } => { 163 | let new_row = remove_nth(row, j); 164 | Some((new_row, *act)) 165 | } 166 | }) 167 | .unzip(); 168 | let new_mat = PatnMatrix { objs, matrix, acts }; 169 | (new_mat, hits) 170 | } 171 | 172 | // return (new_mat, hits) 173 | pub fn specialize_lit(&self, j: usize, lit: LitVal) -> (PatnMatrix, Vec) { 174 | let objs = remove_nth(&self.objs, j); 175 | let mut hits: Vec = Vec::new(); 176 | let (matrix, acts): (Vec>, Vec<_>) = self 177 | .matrix 178 | .iter() 179 | .zip(self.acts.iter()) 180 | .flat_map(|(row, act)| match &row[j] { 181 | Pattern::Lit { lit: lit2, .. } => { 182 | if *lit2 == lit { 183 | let new_row = remove_nth(row, j); 184 | Some((new_row, act.clone())) 185 | } else { 186 | None 187 | } 188 | } 189 | Pattern::Var { ident, .. } => { 190 | hits.push(*ident); 191 | let new_row = remove_nth(row, j); 192 | Some((new_row, *act)) 193 | } 194 | Pattern::Cons { .. } => { 195 | unreachable!() 196 | } 197 | Pattern::Wild { .. } => { 198 | let new_row = remove_nth(row, j); 199 | Some((new_row, *act)) 200 | } 201 | }) 202 | .unzip(); 203 | let new_mat = PatnMatrix { objs, matrix, acts }; 204 | (new_mat, hits) 205 | } 206 | // return (new_mat, hits) 207 | pub fn specialize_cons( 208 | &self, 209 | j: usize, 210 | cons: &Ident, 211 | binds: &Vec<(InternStr, Ident)>, 212 | ) -> (PatnMatrix, Vec) { 213 | let (labels, new_objs): (Vec, Vec) = binds.iter().copied().unzip(); 214 | let objs = insert_nth(&self.objs, j, &new_objs); 215 | let mut hits: Vec = Vec::new(); 216 | let (matrix, acts): (Vec>, Vec<_>) = self 217 | .matrix 218 | .iter() 219 | .zip(self.acts.iter()) 220 | .flat_map(|(row, act)| match &row[j] { 221 | Pattern::Lit { .. } => { 222 | unreachable!() 223 | } 224 | Pattern::Var { ident, span } => { 225 | hits.push(*ident); 226 | let vec = std::iter::repeat(Pattern::Wild { span: span.clone() }) 227 | .take(binds.len()) 228 | .collect(); 229 | let new_row = insert_nth(row, j, &vec); 230 | Some((new_row, act.clone())) 231 | } 232 | Pattern::Cons { 233 | cons: cons2, 234 | patns, 235 | as_ident, 236 | span, 237 | } if *cons2 == *cons => { 238 | let patns = labels 239 | .iter() 240 | .map(|label| { 241 | if let Some(patn) = patns.iter().find(|patn| patn.label == *label) { 242 | patn.data.clone() 243 | } else { 244 | Pattern::Wild { span: span.clone() } 245 | } 246 | }) 247 | .collect(); 248 | if let Some(as_ident) = as_ident { 249 | hits.push(*as_ident) 250 | } 251 | let new_row = insert_nth(row, j, &patns); 252 | Some((new_row, *act)) 253 | } 254 | Pattern::Cons { .. } => None, 255 | Pattern::Wild { span } => { 256 | let vec = std::iter::repeat(Pattern::Wild { span: span.clone() }) 257 | .take(binds.len()) 258 | .collect(); 259 | let new_row = insert_nth(row, j, &vec); 260 | Some((new_row, *act)) 261 | } 262 | }) 263 | .unzip(); 264 | let new_mat = PatnMatrix { objs, matrix, acts }; 265 | (new_mat, hits) 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/core/closure.rs: -------------------------------------------------------------------------------- 1 | use super::cps::*; 2 | use crate::utils::ident::Ident; 3 | use std::{collections::HashSet, mem}; 4 | 5 | pub struct ClosConv { 6 | toplevel: Vec, 7 | freevar: HashSet, 8 | } 9 | 10 | impl ClosConv { 11 | pub fn run(modl: Module) -> Module { 12 | let mut pass = ClosConv { 13 | toplevel: Vec::new(), 14 | freevar: HashSet::new(), 15 | }; 16 | let modl_name = modl.name; 17 | pass.visit_module(modl); 18 | assert!(pass.freevar.is_empty()); 19 | let mut res = Module { 20 | name: modl_name, 21 | decls: pass.toplevel, 22 | }; 23 | super::rename::Renamer::run(&mut res); 24 | res 25 | } 26 | 27 | fn visit_atom(&mut self, atom: Atom) -> Atom { 28 | if let Atom::Var(x) = atom { 29 | self.freevar.insert(x); 30 | } 31 | atom 32 | } 33 | 34 | fn visit_module(&mut self, modl: Module) { 35 | let Module { name: _, decls } = modl; 36 | let expr = Expr::Decls { 37 | funcs: decls, 38 | conts: Vec::new(), 39 | body: Box::new(Expr::Retn { res: Atom::Unit }), 40 | }; 41 | self.visit_expr(expr); 42 | } 43 | 44 | fn visit_func_decl(&mut self, decl: FuncDecl) -> FuncDecl { 45 | let FuncDecl { 46 | func, 47 | cont, 48 | pars, 49 | body, 50 | } = decl; 51 | let body = self.visit_expr(body); 52 | for par in pars.iter() { 53 | self.freevar.remove(par); 54 | } 55 | FuncDecl { 56 | func, 57 | cont, 58 | pars, 59 | body, 60 | } 61 | } 62 | 63 | fn visit_cont_decl(&mut self, decl: ContDecl) -> ContDecl { 64 | let ContDecl { cont, pars, body } = decl; 65 | let body = self.visit_expr(body); 66 | for par in pars.iter() { 67 | self.freevar.remove(par); 68 | } 69 | ContDecl { cont, pars, body } 70 | } 71 | 72 | fn visit_expr(&mut self, expr: Expr) -> Expr { 73 | match expr { 74 | Expr::Decls { funcs, conts, body } => { 75 | // firstly, scan free variables 76 | let mut old_free: HashSet = HashSet::new(); 77 | mem::swap(&mut self.freevar, &mut old_free); 78 | 79 | let funcs: Vec = funcs 80 | .into_iter() 81 | .map(|decl| self.visit_func_decl(decl)) 82 | .collect(); 83 | let conts: Vec = conts 84 | .into_iter() 85 | .map(|decl| self.visit_cont_decl(decl)) 86 | .collect(); 87 | 88 | let mut frees = self.freevar.clone(); 89 | for decl in funcs.iter() { 90 | frees.remove(&decl.func); 91 | } 92 | for decl in conts.iter() { 93 | frees.remove(&decl.cont); 94 | } 95 | let free_funcs: Vec = funcs.iter().map(|decl| decl.func).collect(); 96 | 97 | // secondly, add closure parameter and unpack 98 | let funcs: Vec = funcs 99 | .into_iter() 100 | .map(|decl| { 101 | let FuncDecl { 102 | func, 103 | cont, 104 | pars, 105 | body, 106 | } = decl; 107 | let c = Ident::fresh(&"c"); 108 | let pars: Vec = [c].iter().chain(pars.iter()).copied().collect(); 109 | let body = 110 | frees 111 | .iter() 112 | .enumerate() 113 | .fold(body, |acc, (i, x)| Expr::Select { 114 | bind: *x, 115 | rec: Atom::Var(c), 116 | idx: i, 117 | rest: Box::new(acc), 118 | }); 119 | let body = free_funcs.iter().fold(body, |acc, func| Expr::Record { 120 | bind: *func, 121 | args: vec![(false, Atom::Var(*func)), (false, Atom::Var(c))], 122 | rest: Box::new(acc), 123 | }); 124 | 125 | FuncDecl { 126 | func, 127 | cont, 128 | pars, 129 | body, 130 | } 131 | }) 132 | .collect(); 133 | 134 | let c = Ident::fresh(&"c"); 135 | 136 | let body = self.visit_expr(*body); 137 | 138 | let body = 139 | funcs 140 | .iter() 141 | .map(|decl| decl.func) 142 | .fold(body, |acc, func| Expr::Record { 143 | bind: func, 144 | args: vec![(false, Atom::Var(func)), (false, Atom::Var(c))], 145 | rest: Box::new(acc), 146 | }); 147 | 148 | let body = Expr::Record { 149 | bind: c, 150 | args: frees.iter().map(|x| (false, Atom::Var(*x))).collect(), 151 | rest: Box::new(body), 152 | }; 153 | 154 | for decl in funcs { 155 | self.freevar.remove(&decl.func); 156 | self.toplevel.push(decl); 157 | } 158 | 159 | // recover saved free variables 160 | for old in old_free.iter() { 161 | self.freevar.insert(*old); 162 | } 163 | 164 | Expr::Decls { 165 | funcs: Vec::new(), 166 | conts, 167 | body: Box::new(body), 168 | } 169 | } 170 | Expr::Prim { 171 | bind, 172 | prim, 173 | args, 174 | rest, 175 | } => { 176 | let rest = Box::new(self.visit_expr(*rest)); 177 | self.freevar.remove(&bind); 178 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 179 | Expr::Prim { 180 | bind, 181 | prim, 182 | args, 183 | rest, 184 | } 185 | } 186 | Expr::Record { bind, args, rest } => { 187 | let rest = Box::new(self.visit_expr(*rest)); 188 | self.freevar.remove(&bind); 189 | let args: Vec<(bool, Atom)> = args 190 | .into_iter() 191 | .map(|arg| (arg.0, self.visit_atom(arg.1))) 192 | .collect(); 193 | Expr::Record { bind, args, rest } 194 | } 195 | Expr::Select { 196 | bind, 197 | rec, 198 | idx, 199 | rest, 200 | } => { 201 | let rest = Box::new(self.visit_expr(*rest)); 202 | self.freevar.remove(&bind); 203 | let rec = self.visit_atom(rec); 204 | Expr::Select { 205 | bind, 206 | rec, 207 | idx, 208 | rest, 209 | } 210 | } 211 | Expr::Update { 212 | rec, 213 | idx, 214 | arg, 215 | rest, 216 | } => { 217 | let rest = Box::new(self.visit_expr(*rest)); 218 | let rec = self.visit_atom(rec); 219 | let arg = self.visit_atom(arg); 220 | Expr::Update { 221 | rec, 222 | idx, 223 | arg, 224 | rest, 225 | } 226 | } 227 | Expr::Call { func, cont, args } => { 228 | self.visit_atom(Atom::Var(func)); 229 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 230 | let f = Ident::fresh(&"f"); 231 | let c = Ident::fresh(&"c"); 232 | Expr::Select { 233 | bind: f, 234 | rec: Atom::Var(func), 235 | idx: 0, 236 | rest: Box::new(Expr::Select { 237 | bind: c, 238 | rec: Atom::Var(func), 239 | idx: 1, 240 | rest: Box::new(Expr::Call { 241 | func: f, 242 | cont, 243 | args: [Atom::Var(c)].into_iter().chain(args.into_iter()).collect(), 244 | }), 245 | }), 246 | } 247 | } 248 | Expr::Jump { cont, args } => { 249 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 250 | Expr::Jump { cont, args } 251 | } 252 | Expr::Ifte { 253 | cond, 254 | args, 255 | trbr, 256 | flbr, 257 | } => { 258 | let trbr = Box::new(self.visit_expr(*trbr)); 259 | let flbr = Box::new(self.visit_expr(*flbr)); 260 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 261 | Expr::Ifte { 262 | cond, 263 | args, 264 | trbr, 265 | flbr, 266 | } 267 | } 268 | Expr::Switch { arg, brchs, dflt } => { 269 | let brchs = brchs 270 | .into_iter() 271 | .map(|(i, brch)| (i, self.visit_expr(brch))) 272 | .collect(); 273 | let arg = self.visit_atom(arg); 274 | let dflt = dflt.map(|dflt| Box::new(self.visit_expr(*dflt))); 275 | Expr::Switch { arg, brchs, dflt } 276 | } 277 | Expr::Retn { res } => { 278 | let res = self.visit_atom(res); 279 | Expr::Retn { res } 280 | } 281 | } 282 | } 283 | } 284 | 285 | #[test] 286 | #[ignore = "just to see result"] 287 | fn clos_conv_test_1() { 288 | let s = r#" 289 | module Test where 290 | func f(k1, x1): 291 | decls 292 | func g(k2, x2): 293 | let r = @iadd(x1, x2); 294 | jump k2(r); 295 | in 296 | jump k1(g); 297 | end 298 | 299 | func top(k): 300 | decls 301 | cont next(h): 302 | call h(k, 2); 303 | in 304 | call f(next, 1); 305 | end 306 | "#; 307 | let modl = super::parser::parse_module(s).unwrap(); 308 | println!("{}\n", modl); 309 | let modl = super::optimize::Optimizer::run(modl); 310 | println!("{}\n", modl); 311 | let modl = ClosConv::run(modl); 312 | println!("{}\n", modl); 313 | let modl = super::optimize::Optimizer::run(modl); 314 | println!("{}\n", modl); 315 | } 316 | 317 | #[test] 318 | #[ignore = "just to see result"] 319 | fn clos_conv_test_2() { 320 | let s = r#" 321 | module Test where 322 | fn f(x) begin 323 | let y = @iadd(x, 1); 324 | return y; 325 | end 326 | fn g(z) begin 327 | let a = f(z); 328 | return a; 329 | end 330 | fn top() begin 331 | let r = g(42); 332 | return r; 333 | end 334 | "#; 335 | let modl = super::parser::parse_module(s).unwrap(); 336 | println!("{}\n", modl); 337 | let modl = super::optimize::Optimizer::run(modl); 338 | println!("{}\n", modl); 339 | let modl = ClosConv::run(modl); 340 | println!("{}\n", modl); 341 | let modl = super::optimize::Optimizer::run(modl); 342 | println!("{}\n", modl); 343 | } 344 | 345 | #[test] 346 | #[ignore = "just to see result"] 347 | fn clos_conv_test_3() { 348 | let s = r#" 349 | module Test where 350 | fn f(x) begin 351 | let one = @move(1); 352 | decl 353 | fn g(z) begin 354 | let a = @iadd(z, one); 355 | return a; 356 | end 357 | in 358 | let y = g(x); 359 | return y; 360 | end 361 | end 362 | fn top() begin 363 | let r = f(42); 364 | return r; 365 | end 366 | "#; 367 | let modl = super::parser::parse_module(s).unwrap(); 368 | println!("{}\n", modl); 369 | let modl = super::optimize::Optimizer::run(modl); 370 | println!("{}\n", modl); 371 | let modl = ClosConv::run(modl); 372 | println!("{}\n", modl); 373 | let modl = super::optimize::Optimizer::run(modl); 374 | println!("{}\n", modl); 375 | } 376 | -------------------------------------------------------------------------------- /src/core/parser.rs: -------------------------------------------------------------------------------- 1 | use super::cps::*; 2 | use crate::syntax::prim::Prim; 3 | use crate::utils::ident::Ident; 4 | use nom::branch::alt; 5 | use nom::bytes::complete::{tag, take_while}; 6 | use nom::character::complete::{alpha1, digit1}; 7 | use nom::combinator::{map, opt, value}; 8 | use nom::multi::{many0, separated_list0}; 9 | use nom::IResult; 10 | 11 | fn is_space_or_newline(ch: char) -> bool { 12 | match ch { 13 | ' ' | '\t' | '\n' | '\r' => true, 14 | _ => false, 15 | } 16 | } 17 | 18 | fn skip_space(input: &str) -> IResult<&str, &str> { 19 | take_while(is_space_or_newline)(input) 20 | } 21 | 22 | fn skip_space_tag<'a>(tok: &str, input: &'a str) -> IResult<&'a str, &'a str> { 23 | let (input, _) = skip_space(input)?; 24 | tag(tok)(input) 25 | } 26 | 27 | fn atom(input: &str) -> IResult<&str, Atom> { 28 | alt(( 29 | map(ident, |x| Atom::Var(x)), 30 | map(int, |x| Atom::Int(x)), 31 | map(float, |x| Atom::Float(x)), 32 | map(bool, |x| Atom::Bool(x)), 33 | map(char, |x| Atom::Char(x)), 34 | map(tag("()"), |_| Atom::Unit), 35 | ))(input) 36 | } 37 | 38 | fn ident(input: &str) -> IResult<&str, Ident> { 39 | let (input, _) = skip_space(input)?; 40 | let (input, s1) = alpha1(input)?; 41 | let (input, s2) = take_while(char::is_alphanumeric)(input)?; 42 | let mut s: String = String::new(); 43 | s.push_str(s1); 44 | s.push_str(s2); 45 | Ok((input, Ident::dummy(&s))) 46 | } 47 | 48 | fn int(input: &str) -> IResult<&str, i64> { 49 | let (input, _) = skip_space(input)?; 50 | let (input, s) = digit1(input)?; 51 | Ok((input, s.parse::().unwrap())) 52 | } 53 | 54 | fn float(input: &str) -> IResult<&str, f64> { 55 | let (input, _) = skip_space(input)?; 56 | let (input, s1) = digit1(input)?; 57 | let (input, _) = tag(".")(input)?; 58 | let (input, s2) = digit1(input)?; 59 | let mut s: String = String::new(); 60 | s.push_str(s1); 61 | s.push('.'); 62 | s.push_str(s2); 63 | Ok((input, s.parse::().unwrap())) 64 | } 65 | 66 | fn bool(input: &str) -> IResult<&str, bool> { 67 | let (input, _) = skip_space(input)?; 68 | alt((map(tag("true"), |_| true), map(tag("false"), |_| false)))(input) 69 | } 70 | 71 | fn char(input: &str) -> IResult<&str, char> { 72 | let (input, _) = skip_space(input)?; 73 | let (input, _) = tag("'")(input)?; 74 | let (input, s1) = alpha1(input)?; 75 | let (input, _) = tag("'")(input)?; 76 | let mut s: String = String::new(); 77 | s.push_str("'"); 78 | s.push_str(s1); 79 | s.push_str("'"); 80 | Ok((input, s.parse::().unwrap())) 81 | } 82 | 83 | fn prim_opr(input: &str) -> IResult<&str, Prim> { 84 | let (input, _) = skip_space(input)?; 85 | let (input, head) = tag("@")(input)?; 86 | let (input, body) = alpha1(input)?; 87 | let mut s = String::new(); 88 | s.push_str(head); 89 | s.push_str(body); 90 | if let Ok(res) = s.parse() { 91 | Ok((input, res)) 92 | } else { 93 | nom::combinator::fail("unknown primitive!") 94 | } 95 | } 96 | 97 | fn if_cond(input: &str) -> IResult<&str, IfCond> { 98 | let (input, _) = skip_space(input)?; 99 | alt(( 100 | value(IfCond::BTrue, tag("btrue")), 101 | value(IfCond::BFalse, tag("bfalse")), 102 | value(IfCond::ICmpGr, tag("icmpgr")), 103 | value(IfCond::ICmpEq, tag("icmpeq")), 104 | value(IfCond::ICmpLs, tag("icmpls")), 105 | ))(input) 106 | } 107 | 108 | fn expr_decls(input: &str) -> IResult<&str, Expr> { 109 | let (input, _) = skip_space_tag("decls", input)?; 110 | let (input, funcs) = many0(func_decl)(input)?; 111 | let (input, conts) = many0(cont_decl)(input)?; 112 | let (input, _) = skip_space_tag("in", input)?; 113 | let (input, body) = expr(input)?; 114 | let (input, _) = skip_space_tag("end", input)?; 115 | let body = Box::new(body); 116 | Ok((input, Expr::Decls { funcs, conts, body })) 117 | } 118 | 119 | fn expr_prim(input: &str) -> IResult<&str, Expr> { 120 | let (input, _) = skip_space_tag("let", input)?; 121 | let (input, bind) = ident(input)?; 122 | let (input, _) = skip_space_tag("=", input)?; 123 | let (input, prim) = prim_opr(input)?; 124 | let (input, _) = skip_space_tag("(", input)?; 125 | let (input, args) = separated_list0(|input| skip_space_tag(",", input), atom)(input)?; 126 | let (input, _) = skip_space_tag(")", input)?; 127 | let (input, _) = skip_space_tag(";", input)?; 128 | let (input, rest) = expr(input)?; 129 | Ok(( 130 | input, 131 | Expr::Prim { 132 | bind, 133 | prim, 134 | args, 135 | rest: Box::new(rest), 136 | }, 137 | )) 138 | } 139 | 140 | fn expr_call(input: &str) -> IResult<&str, Expr> { 141 | let (input, _) = skip_space_tag("call", input)?; 142 | let (input, func) = ident(input)?; 143 | let (input, _) = skip_space_tag("(", input)?; 144 | let (input, args) = separated_list0(|input| skip_space_tag(",", input), atom)(input)?; 145 | let (input, _) = skip_space_tag(")", input)?; 146 | let (input, _) = skip_space_tag(";", input)?; 147 | if !args.is_empty() { 148 | let cont = args[0]; 149 | let args = args[1..].iter().copied().collect(); 150 | if let Atom::Var(cont) = cont { 151 | Ok((input, Expr::Call { func, cont, args })) 152 | } else { 153 | nom::combinator::fail("function call with a non-cont first argument!") 154 | } 155 | } else { 156 | nom::combinator::fail("function call without cont argument!") 157 | } 158 | } 159 | 160 | fn expr_record(input: &str) -> IResult<&str, Expr> { 161 | let (input, _) = skip_space_tag("record", input)?; 162 | let (input, bind) = ident(input)?; 163 | let (input, _) = skip_space_tag("=", input)?; 164 | let (input, _) = skip_space_tag("{", input)?; 165 | let (input, args) = separated_list0( 166 | |input| skip_space_tag(",", input), 167 | |input| { 168 | let (input, res) = opt(|input| skip_space_tag("{", input))(input)?; 169 | let (input, arg) = atom(input)?; 170 | Ok((input, (res.is_some(), arg))) 171 | }, 172 | )(input)?; 173 | let (input, _) = skip_space_tag("}", input)?; 174 | let (input, _) = skip_space_tag(";", input)?; 175 | let (input, rest) = expr(input)?; 176 | Ok(( 177 | input, 178 | Expr::Record { 179 | bind, 180 | args, 181 | rest: Box::new(rest), 182 | }, 183 | )) 184 | } 185 | 186 | fn expr_select(input: &str) -> IResult<&str, Expr> { 187 | let (input, _) = skip_space_tag("select", input)?; 188 | let (input, bind) = ident(input)?; 189 | let (input, _) = skip_space_tag("=", input)?; 190 | let (input, rec) = atom(input)?; 191 | let (input, _) = skip_space_tag("[", input)?; 192 | let (input, idx) = digit1(input)?; 193 | let (input, _) = skip_space_tag("]", input)?; 194 | let (input, _) = skip_space_tag(";", input)?; 195 | let (input, rest) = expr(input)?; 196 | Ok(( 197 | input, 198 | Expr::Select { 199 | bind, 200 | rec, 201 | idx: idx.parse().unwrap(), 202 | rest: Box::new(rest), 203 | }, 204 | )) 205 | } 206 | 207 | fn expr_update(input: &str) -> IResult<&str, Expr> { 208 | let (input, _) = skip_space_tag("update", input)?; 209 | let (input, rec) = atom(input)?; 210 | let (input, _) = skip_space_tag("[", input)?; 211 | let (input, idx) = digit1(input)?; 212 | let (input, _) = skip_space_tag("]", input)?; 213 | let (input, _) = skip_space_tag("=", input)?; 214 | let (input, arg) = atom(input)?; 215 | let (input, _) = skip_space_tag(";", input)?; 216 | let (input, rest) = expr(input)?; 217 | Ok(( 218 | input, 219 | Expr::Update { 220 | rec, 221 | idx: idx.parse().unwrap(), 222 | arg, 223 | rest: Box::new(rest), 224 | }, 225 | )) 226 | } 227 | 228 | fn expr_jump(input: &str) -> IResult<&str, Expr> { 229 | let (input, _) = skip_space_tag("jump", input)?; 230 | let (input, cont) = ident(input)?; 231 | let (input, _) = skip_space_tag("(", input)?; 232 | let (input, args) = separated_list0(|input| skip_space_tag(",", input), atom)(input)?; 233 | let (input, _) = skip_space_tag(")", input)?; 234 | let (input, _) = skip_space_tag(";", input)?; 235 | Ok((input, Expr::Jump { cont, args })) 236 | } 237 | 238 | fn expr_ifte(input: &str) -> IResult<&str, Expr> { 239 | let (input, _) = skip_space_tag("if", input)?; 240 | let (input, cond) = if_cond(input)?; 241 | let (input, _) = skip_space_tag("(", input)?; 242 | let (input, args) = separated_list0(|input| skip_space_tag(",", input), atom)(input)?; 243 | let (input, _) = skip_space_tag(")", input)?; 244 | let (input, _) = skip_space_tag("then", input)?; 245 | let (input, trbr) = expr(input)?; 246 | let (input, _) = skip_space_tag("else", input)?; 247 | let (input, flbr) = expr(input)?; 248 | Ok(( 249 | input, 250 | Expr::Ifte { 251 | cond, 252 | args, 253 | trbr: Box::new(trbr), 254 | flbr: Box::new(flbr), 255 | }, 256 | )) 257 | } 258 | 259 | fn expr_switch(input: &str) -> IResult<&str, Expr> { 260 | let (input, _) = skip_space_tag("switch", input)?; 261 | let (input, arg) = atom(input)?; 262 | let (input, _) = skip_space_tag("of", input)?; 263 | let (input, brchs) = many0(|input| { 264 | let (input, _) = skip_space_tag("case", input)?; 265 | let (input, i) = int(input)?; 266 | let (input, _) = skip_space_tag(":", input)?; 267 | let (input, brch) = expr(input)?; 268 | Ok((input, (i as usize, brch))) 269 | })(input)?; 270 | 271 | let (input, dflt) = opt(|input| { 272 | let (input, _) = skip_space_tag("default", input)?; 273 | let (input, _) = skip_space_tag(":", input)?; 274 | let (input, brch) = expr(input)?; 275 | Ok((input, Box::new(brch))) 276 | })(input)?; 277 | let (input, _) = skip_space_tag("end", input)?; 278 | Ok((input, Expr::Switch { arg, brchs, dflt })) 279 | } 280 | 281 | fn expr_retn(input: &str) -> IResult<&str, Expr> { 282 | let (input, _) = skip_space_tag("return", input)?; 283 | let (input, res) = atom(input)?; 284 | let (input, _) = skip_space_tag(";", input)?; 285 | Ok((input, Expr::Retn { res })) 286 | } 287 | 288 | fn expr(input: &str) -> IResult<&str, Expr> { 289 | alt(( 290 | expr_decls, 291 | expr_prim, 292 | expr_record, 293 | expr_select, 294 | expr_update, 295 | expr_call, 296 | expr_jump, 297 | expr_ifte, 298 | expr_switch, 299 | expr_retn, 300 | ))(input) 301 | } 302 | 303 | fn func_decl(input: &str) -> IResult<&str, FuncDecl> { 304 | let (input, _) = skip_space_tag("func", input)?; 305 | let (input, func) = ident(input)?; 306 | let (input, _) = skip_space_tag("(", input)?; 307 | let (input, pars) = separated_list0(|input| skip_space_tag(",", input), ident)(input)?; 308 | let (input, _) = skip_space_tag(")", input)?; 309 | let (input, _) = skip_space_tag(":", input)?; 310 | let (input, body) = expr(input)?; 311 | if !pars.is_empty() { 312 | let cont = pars[0]; 313 | let pars = pars[1..].iter().copied().collect(); 314 | Ok(( 315 | input, 316 | FuncDecl { 317 | func, 318 | cont, 319 | pars, 320 | body, 321 | }, 322 | )) 323 | } else { 324 | nom::combinator::fail("function definition without cont parameter!") 325 | } 326 | } 327 | 328 | fn cont_decl(input: &str) -> IResult<&str, ContDecl> { 329 | let (input, _) = skip_space_tag("cont", input)?; 330 | let (input, cont) = ident(input)?; 331 | let (input, _) = skip_space_tag("(", input)?; 332 | let (input, pars) = separated_list0(|input| skip_space_tag(",", input), ident)(input)?; 333 | let (input, _) = skip_space_tag(")", input)?; 334 | let (input, _) = skip_space_tag(":", input)?; 335 | let (input, body) = expr(input)?; 336 | Ok((input, ContDecl { cont, pars, body })) 337 | } 338 | 339 | fn module(input: &str) -> IResult<&str, Module> { 340 | let (input, _) = skip_space_tag("module", input)?; 341 | let (input, name) = ident(input)?; 342 | let (input, _) = skip_space_tag("where", input)?; 343 | let (input, decls) = many0(func_decl)(input)?; 344 | Ok((input, Module { name, decls })) 345 | } 346 | 347 | pub fn parse_module(input: &str) -> Option { 348 | match module(input) { 349 | Ok((input, mut modl)) => { 350 | let (input, _) = skip_space(input).unwrap(); 351 | if input == "" { 352 | super::rename::Renamer::run(&mut modl); 353 | Some(modl) 354 | } else { 355 | None 356 | } 357 | } 358 | Err(_) => None, 359 | } 360 | } 361 | 362 | #[test] 363 | #[ignore = "just to see result"] 364 | fn parser_test() { 365 | let s = r#" 366 | module Test where 367 | func top1(x, y): 368 | return x; 369 | func top2(x): 370 | decls 371 | func f(k, x, y, z): 372 | jump k(x); 373 | cont k(a): 374 | return a; 375 | in 376 | let x = @iadd(1, 2); 377 | call f(k, 1, 2, 3); 378 | end 379 | "#; 380 | let res = parse_module(s).unwrap(); 381 | println!("{}", res); 382 | } 383 | -------------------------------------------------------------------------------- /src/core/inline.rs: -------------------------------------------------------------------------------- 1 | use super::cps::*; 2 | use crate::syntax::prim::Prim; 3 | use crate::utils::ident::Ident; 4 | use std::collections::{HashMap, HashSet}; 5 | 6 | pub struct InlineScan { 7 | // (n, m), where n is occur times, and m is call-site occur times 8 | // n >= m always 9 | occur_map: HashMap, 10 | inline_mark: HashSet, 11 | } 12 | 13 | impl InlineScan { 14 | pub fn run(modl: &Module) -> HashSet { 15 | let mut pass = InlineScan { 16 | occur_map: HashMap::new(), 17 | inline_mark: HashSet::new(), 18 | }; 19 | pass.visit_module(modl); 20 | pass.inline_mark 21 | } 22 | 23 | fn visit_atom(&mut self, atom: &Atom) { 24 | if let Atom::Var(x) = atom { 25 | let res = self.occur_map.get_mut(x); 26 | if let Some((n, _m)) = res { 27 | *n += 1; 28 | } else { 29 | self.occur_map.insert(*x, (1, 0)); 30 | } 31 | } 32 | } 33 | 34 | fn visit_module(&mut self, modl: &Module) { 35 | let Module { name: _, decls } = modl; 36 | for decl in decls { 37 | self.visit_func_decl(decl); 38 | } 39 | } 40 | 41 | fn visit_func_decl(&mut self, decl: &FuncDecl) { 42 | let FuncDecl { 43 | func: _, 44 | cont, 45 | pars, 46 | body, 47 | } = decl; 48 | self.visit_expr(body); 49 | pars.iter().for_each(|par| { 50 | self.occur_map.remove(par); 51 | }); 52 | self.occur_map.remove(&cont); 53 | } 54 | 55 | fn visit_cont_decl(&mut self, decl: &ContDecl) { 56 | let ContDecl { 57 | cont: _, 58 | pars, 59 | body, 60 | } = decl; 61 | self.visit_expr(body); 62 | pars.iter().for_each(|par| { 63 | self.occur_map.remove(par); 64 | }); 65 | } 66 | 67 | fn visit_expr(&mut self, expr: &Expr) { 68 | match expr { 69 | Expr::Decls { funcs, conts, body } => { 70 | self.visit_expr(body); 71 | for decl in funcs { 72 | self.visit_func_decl(decl) 73 | } 74 | for decl in conts { 75 | self.visit_cont_decl(decl) 76 | } 77 | for decl in funcs { 78 | let name = decl.func; 79 | let res = self.occur_map.remove(&name); 80 | if res == Some((1, 1)) { 81 | self.inline_mark.insert(name); 82 | } 83 | } 84 | for decl in conts { 85 | let name = decl.cont; 86 | let res = self.occur_map.remove(&name); 87 | if res == Some((1, 1)) { 88 | self.inline_mark.insert(name); 89 | } 90 | } 91 | } 92 | Expr::Prim { 93 | bind: _, 94 | prim: _, 95 | args, 96 | rest, 97 | } => { 98 | self.visit_expr(rest); 99 | args.iter().for_each(|arg| self.visit_atom(arg)); 100 | } 101 | Expr::Record { 102 | bind: _, 103 | args, 104 | rest, 105 | } => { 106 | self.visit_expr(rest); 107 | args.iter().for_each(|arg| self.visit_atom(&arg.1)); 108 | } 109 | Expr::Select { 110 | bind: _, 111 | rec, 112 | idx: _, 113 | rest, 114 | } => { 115 | self.visit_expr(rest); 116 | self.visit_atom(rec); 117 | } 118 | Expr::Update { 119 | rec, 120 | idx: _, 121 | arg, 122 | rest, 123 | } => { 124 | self.visit_expr(rest); 125 | self.visit_atom(rec); 126 | self.visit_atom(arg); 127 | } 128 | Expr::Call { func, cont, args } => { 129 | self.visit_atom(&Atom::Var(*func)); 130 | self.visit_atom(&Atom::Var(*cont)); 131 | args.iter().for_each(|arg| self.visit_atom(arg)); 132 | let res = self.occur_map.get_mut(&func).unwrap(); 133 | res.1 += 1; 134 | } 135 | Expr::Jump { cont, args } => { 136 | self.visit_atom(&Atom::Var(*cont)); 137 | args.iter().for_each(|arg| self.visit_atom(arg)); 138 | let res = self.occur_map.get_mut(&cont).unwrap(); 139 | res.1 += 1; 140 | } 141 | Expr::Ifte { 142 | cond: _, 143 | args, 144 | trbr, 145 | flbr, 146 | } => { 147 | self.visit_expr(trbr); 148 | self.visit_expr(flbr); 149 | args.iter().for_each(|arg| self.visit_atom(arg)); 150 | } 151 | Expr::Switch { arg, brchs, dflt } => { 152 | brchs.iter().for_each(|(_, brch)| self.visit_expr(brch)); 153 | dflt.as_ref().map(|dflt| self.visit_expr(dflt)); 154 | self.visit_atom(arg); 155 | } 156 | Expr::Retn { res } => { 157 | self.visit_atom(res); 158 | } 159 | } 160 | } 161 | } 162 | 163 | pub struct InlinePerform { 164 | inline_mark: HashSet, 165 | func_map: HashMap, 166 | cont_map: HashMap, 167 | } 168 | 169 | impl InlinePerform { 170 | pub fn run(modl: Module, mark: HashSet) -> Module { 171 | let mut pass = InlinePerform { 172 | inline_mark: mark, 173 | func_map: HashMap::new(), 174 | cont_map: HashMap::new(), 175 | }; 176 | pass.visit_module(modl) 177 | } 178 | 179 | fn visit_module(&mut self, modl: Module) -> Module { 180 | let Module { name, decls } = modl; 181 | 182 | decls.iter().for_each(|decl| { 183 | if self.inline_mark.contains(&decl.func) { 184 | self.func_map.insert(decl.func, decl.clone()); 185 | } 186 | }); 187 | 188 | let decls: Vec = decls 189 | .into_iter() 190 | .map(|decl| self.visit_func_decl(decl)) 191 | .collect(); 192 | 193 | Module { name, decls } 194 | } 195 | 196 | fn visit_func_decl(&mut self, decl: FuncDecl) -> FuncDecl { 197 | let FuncDecl { 198 | func, 199 | cont, 200 | pars, 201 | body, 202 | } = decl; 203 | let body = self.visit_expr(body); 204 | FuncDecl { 205 | func, 206 | cont, 207 | pars, 208 | body, 209 | } 210 | } 211 | 212 | fn visit_cont_decl(&mut self, decl: ContDecl) -> ContDecl { 213 | let ContDecl { cont, pars, body } = decl; 214 | let body = self.visit_expr(body); 215 | ContDecl { cont, pars, body } 216 | } 217 | 218 | fn visit_expr(&mut self, expr: Expr) -> Expr { 219 | match expr { 220 | Expr::Decls { funcs, conts, body } => { 221 | for decl in funcs.iter() { 222 | if self.inline_mark.contains(&decl.func) { 223 | self.func_map.insert(decl.func, decl.clone()); 224 | } 225 | } 226 | for decl in conts.iter() { 227 | if self.inline_mark.contains(&decl.cont) { 228 | self.cont_map.insert(decl.cont, decl.clone()); 229 | } 230 | } 231 | let funcs: Vec = funcs 232 | .into_iter() 233 | .map(|decl| self.visit_func_decl(decl)) 234 | .collect(); 235 | let conts: Vec = conts 236 | .into_iter() 237 | .map(|decl| self.visit_cont_decl(decl)) 238 | .collect(); 239 | 240 | let body = Box::new(self.visit_expr(*body)); 241 | 242 | if funcs.is_empty() && conts.is_empty() { 243 | *body 244 | } else { 245 | Expr::Decls { funcs, conts, body } 246 | } 247 | } 248 | Expr::Prim { 249 | bind, 250 | prim, 251 | args, 252 | rest, 253 | } => { 254 | let rest = Box::new(self.visit_expr(*rest)); 255 | Expr::Prim { 256 | bind, 257 | prim, 258 | args, 259 | rest, 260 | } 261 | } 262 | Expr::Record { bind, args, rest } => { 263 | let rest = Box::new(self.visit_expr(*rest)); 264 | Expr::Record { bind, args, rest } 265 | } 266 | Expr::Select { 267 | bind, 268 | rec, 269 | idx, 270 | rest, 271 | } => { 272 | let rest = Box::new(self.visit_expr(*rest)); 273 | Expr::Select { 274 | bind, 275 | rec, 276 | idx, 277 | rest, 278 | } 279 | } 280 | Expr::Update { 281 | rec, 282 | idx, 283 | arg, 284 | rest, 285 | } => { 286 | let rest = Box::new(self.visit_expr(*rest)); 287 | Expr::Update { 288 | rec, 289 | idx, 290 | arg, 291 | rest, 292 | } 293 | } 294 | Expr::Call { func, cont, args } => { 295 | if let Some(decl) = self.func_map.remove(&func) { 296 | let FuncDecl { 297 | func: func2, 298 | cont: cont2, 299 | pars, 300 | body, 301 | } = decl; 302 | assert_eq!(func, func2); 303 | assert_eq!(args.len(), pars.len()); 304 | pars.into_iter().zip(args.into_iter()).fold( 305 | // this have to be const-folded! 306 | Expr::Prim { 307 | bind: cont2, 308 | prim: Prim::Move, 309 | args: vec![Atom::Var(cont)], 310 | rest: Box::new(body), 311 | }, 312 | |rest, (par, arg)| Expr::Prim { 313 | bind: par, 314 | prim: Prim::Move, 315 | args: vec![arg], 316 | rest: Box::new(rest), 317 | }, 318 | ) 319 | } else { 320 | Expr::Call { func, cont, args } 321 | } 322 | } 323 | Expr::Jump { cont, args } => { 324 | if let Some(decl) = self.cont_map.remove(&cont) { 325 | let ContDecl { 326 | cont: cont2, 327 | pars, 328 | body, 329 | } = decl; 330 | assert_eq!(cont, cont2); 331 | assert_eq!(args.len(), pars.len()); 332 | pars.into_iter() 333 | .zip(args.into_iter()) 334 | .fold(body, |rest, (par, arg)| Expr::Prim { 335 | bind: par, 336 | prim: Prim::Move, 337 | args: vec![arg], 338 | rest: Box::new(rest), 339 | }) 340 | } else { 341 | Expr::Jump { cont, args } 342 | } 343 | } 344 | Expr::Ifte { 345 | cond, 346 | args, 347 | trbr, 348 | flbr, 349 | } => { 350 | let trbr = Box::new(self.visit_expr(*trbr)); 351 | let flbr = Box::new(self.visit_expr(*flbr)); 352 | Expr::Ifte { 353 | cond, 354 | args, 355 | trbr, 356 | flbr, 357 | } 358 | } 359 | Expr::Switch { arg, brchs, dflt } => { 360 | let dflt = dflt.map(|dflt| Box::new(self.visit_expr(*dflt))); 361 | let brchs = brchs 362 | .into_iter() 363 | .map(|(i, brch)| (i, self.visit_expr(brch))) 364 | .collect(); 365 | Expr::Switch { arg, brchs, dflt } 366 | } 367 | Expr::Retn { res } => Expr::Retn { res }, 368 | } 369 | } 370 | } 371 | 372 | #[test] 373 | #[ignore = "just to see result"] 374 | fn inline_test() { 375 | let s = r#" 376 | module Test where 377 | func test(k): 378 | decls 379 | func f(k1, x1): 380 | call g(k1, x1); 381 | func g(k2, x2): 382 | let r = @iadd(x2, x2); 383 | jump k2(r); 384 | in 385 | call f(k, 42); 386 | end 387 | "#; 388 | let expr = super::parser::parse_module(s).unwrap(); 389 | println!("{}", expr); 390 | let mark = InlineScan::run(&expr); 391 | let expr = InlinePerform::run(expr, mark); 392 | println!("{}", expr); 393 | } 394 | -------------------------------------------------------------------------------- /src/backend/interp.rs: -------------------------------------------------------------------------------- 1 | use crate::syntax::prim::Compare; 2 | use crate::utils::ident::Ident; 3 | use std::collections::HashMap; 4 | 5 | use super::tac::*; 6 | 7 | #[derive(Copy, Clone, Debug, PartialEq)] 8 | pub enum Value { 9 | Int(i64), 10 | Float(f64), 11 | Bool(bool), 12 | Char(char), 13 | Addr(Ident), 14 | Unit, 15 | Ptr(*mut Value), 16 | } 17 | 18 | impl Value { 19 | fn unwrap_int(&self) -> i64 { 20 | if let Value::Int(x) = self { 21 | *x 22 | } else { 23 | panic!("failed to unwrap Value::Int!"); 24 | } 25 | } 26 | fn unwrap_float(&self) -> f64 { 27 | if let Value::Float(x) = self { 28 | *x 29 | } else { 30 | panic!("failed to unwrap Value::Float!"); 31 | } 32 | } 33 | fn unwrap_bool(&self) -> bool { 34 | if let Value::Bool(x) = self { 35 | *x 36 | } else { 37 | panic!("failed to unwrap Value::Bool!"); 38 | } 39 | } 40 | fn unwrap_char(&self) -> char { 41 | if let Value::Char(x) = self { 42 | *x 43 | } else { 44 | panic!("failed to unwrap Value::Char!"); 45 | } 46 | } 47 | fn unwrap_addr(&self) -> Ident { 48 | if let Value::Addr(x) = self { 49 | *x 50 | } else { 51 | panic!("failed to unwrap Value::Addr!"); 52 | } 53 | } 54 | fn unwrap_ptr(&self) -> *mut Value { 55 | if let Value::Ptr(x) = self { 56 | *x 57 | } else { 58 | panic!("failed to unwrap Value::Ptr!"); 59 | } 60 | } 61 | } 62 | 63 | fn alloc_memory(size: usize) -> Value { 64 | let mut vec = Vec::with_capacity(size as usize); 65 | for _ in 0..size { 66 | vec.push(Value::Unit); 67 | } 68 | let boxed = Box::new(vec); 69 | let ptr = boxed.leak(); 70 | Value::Ptr(ptr.as_mut_ptr()) 71 | } 72 | 73 | struct CallSave { 74 | bind: Ident, 75 | cont: Ident, 76 | local: HashMap, 77 | } 78 | 79 | pub struct Interpreter<'a> { 80 | // map block names (or function name) to block references 81 | code_map: HashMap, 82 | // map function names to function parameters 83 | pars_map: HashMap>, 84 | stack: Vec, 85 | local: HashMap, 86 | } 87 | 88 | impl<'a> Interpreter<'a> { 89 | pub fn new(modl: &'a Module) -> Interpreter { 90 | let mut code_map = HashMap::new(); 91 | let mut pars_map = HashMap::new(); 92 | for func in modl.funcs.values() { 93 | for blk in func.blks.iter() { 94 | code_map.insert(blk.name, blk); 95 | } 96 | code_map.insert(func.name, &func.blks[0]); 97 | pars_map.insert(func.name, &func.pars); 98 | } 99 | Interpreter { 100 | code_map, 101 | pars_map, 102 | stack: Vec::new(), 103 | local: HashMap::new(), 104 | } 105 | } 106 | pub unsafe fn run(&mut self, func: Ident, args: Vec) -> Value { 107 | let mut run_blk: &BasicBlock = self.code_map[&func]; 108 | for (par, arg) in self.pars_map[&func].iter().zip(args.iter()) { 109 | self.local.insert(*par, *arg); 110 | } 111 | loop { 112 | for code in run_blk.codes.iter() { 113 | match code { 114 | Instr::LitI(r, v) => { 115 | self.local.insert(*r, Value::Int(*v)); 116 | } 117 | Instr::LitF(r, v) => { 118 | self.local.insert(*r, Value::Float(*v)); 119 | } 120 | Instr::LitB(r, v) => { 121 | self.local.insert(*r, Value::Bool(*v)); 122 | } 123 | Instr::LitC(r, v) => { 124 | self.local.insert(*r, Value::Char(*v)); 125 | } 126 | Instr::LitA(r, v) => { 127 | self.local.insert(*r, Value::Addr(*v)); 128 | } 129 | Instr::IAdd(r1, r2, r3) => { 130 | let value = self.local[r2].unwrap_int() + self.local[r3].unwrap_int(); 131 | self.local.insert(*r1, Value::Int(value)); 132 | } 133 | Instr::ISub(r1, r2, r3) => { 134 | let value = self.local[r2].unwrap_int() - self.local[r3].unwrap_int(); 135 | self.local.insert(*r1, Value::Int(value)); 136 | } 137 | Instr::IMul(r1, r2, r3) => { 138 | let value = self.local[r2].unwrap_int() * self.local[r3].unwrap_int(); 139 | self.local.insert(*r1, Value::Int(value)); 140 | } 141 | Instr::IDiv(r1, r2, r3) => { 142 | let value = self.local[r2].unwrap_int() / self.local[r3].unwrap_int(); 143 | self.local.insert(*r1, Value::Int(value)); 144 | } 145 | Instr::IRem(r1, r2, r3) => { 146 | let value = self.local[r2].unwrap_int() % self.local[r3].unwrap_int(); 147 | self.local.insert(*r1, Value::Int(value)); 148 | } 149 | Instr::INeg(r1, r2) => { 150 | let value = -self.local[r2].unwrap_int(); 151 | self.local.insert(*r1, Value::Int(value)); 152 | } 153 | Instr::FAdd(r1, r2, r3) => { 154 | let value = self.local[r2].unwrap_float() + self.local[r3].unwrap_float(); 155 | self.local.insert(*r1, Value::Float(value)); 156 | } 157 | Instr::FSub(r1, r2, r3) => { 158 | let value = self.local[r2].unwrap_float() - self.local[r3].unwrap_float(); 159 | self.local.insert(*r1, Value::Float(value)); 160 | } 161 | Instr::FMul(r1, r2, r3) => { 162 | let value = self.local[r2].unwrap_float() * self.local[r3].unwrap_float(); 163 | self.local.insert(*r1, Value::Float(value)); 164 | } 165 | Instr::FDiv(r1, r2, r3) => { 166 | let value = self.local[r2].unwrap_float() / self.local[r3].unwrap_float(); 167 | self.local.insert(*r1, Value::Float(value)); 168 | } 169 | Instr::FNeg(r1, r2) => { 170 | let value = -self.local[r2].unwrap_float(); 171 | self.local.insert(*r1, Value::Float(value)); 172 | } 173 | Instr::BAnd(r1, r2, r3) => { 174 | let value = self.local[r2].unwrap_bool() && self.local[r3].unwrap_bool(); 175 | self.local.insert(*r1, Value::Bool(value)); 176 | } 177 | Instr::BOr(r1, r2, r3) => { 178 | let value = self.local[r2].unwrap_bool() || self.local[r3].unwrap_bool(); 179 | self.local.insert(*r1, Value::Bool(value)); 180 | } 181 | Instr::BNot(r1, r2) => { 182 | let value = !self.local[r2].unwrap_bool(); 183 | self.local.insert(*r1, Value::Bool(value)); 184 | } 185 | Instr::ICmp(cmp, r1, r2, r3) => { 186 | let lhs = self.local[r2].unwrap_int(); 187 | let rhs = self.local[r3].unwrap_int(); 188 | let value = match cmp { 189 | Compare::Lt => lhs < rhs, 190 | Compare::Le => lhs <= rhs, 191 | Compare::Eq => lhs == rhs, 192 | Compare::Ge => lhs >= rhs, 193 | Compare::Gt => lhs > rhs, 194 | Compare::Ne => lhs != rhs, 195 | }; 196 | self.local.insert(*r1, Value::Bool(value)); 197 | } 198 | Instr::FCmp(cmp, r1, r2, r3) => { 199 | let lhs = self.local[r2].unwrap_float(); 200 | let rhs = self.local[r3].unwrap_float(); 201 | let value = match cmp { 202 | Compare::Lt => lhs < rhs, 203 | Compare::Le => lhs <= rhs, 204 | Compare::Eq => lhs == rhs, 205 | Compare::Ge => lhs >= rhs, 206 | Compare::Gt => lhs > rhs, 207 | Compare::Ne => lhs != rhs, 208 | }; 209 | self.local.insert(*r1, Value::Bool(value)); 210 | } 211 | Instr::Move(r1, r2) => { 212 | let v = self.local[r2]; 213 | self.local.insert(*r1, v); 214 | } 215 | Instr::Alloc(reg1, arg2) => { 216 | let len = self.local[arg2].unwrap_int(); 217 | let ptr = alloc_memory(len as usize); 218 | self.local.insert(*reg1, ptr); 219 | } 220 | Instr::Load(reg, mem, idx) => { 221 | let ptr = self.local[mem].unwrap_ptr(); 222 | let ptr = ptr.add(self.local[idx].unwrap_int() as usize); 223 | self.local.insert(*reg, *ptr); 224 | } 225 | Instr::Store(mem, idx, reg) => { 226 | let ptr = self.local[mem].unwrap_ptr(); 227 | let ptr = ptr.add(self.local[idx].unwrap_int() as usize); 228 | *ptr = *self.local.get(reg).unwrap(); 229 | } 230 | Instr::IPrint(r) => { 231 | let value = self.local[r].unwrap_int(); 232 | print!("{}", value); 233 | } 234 | Instr::IScan(r) => { 235 | let mut s = String::new(); 236 | std::io::stdin().read_line(&mut s).unwrap(); 237 | self.local 238 | .insert(*r, Value::Int(s.trim().parse().unwrap_or(0))); 239 | } 240 | Instr::FPrint(r) => { 241 | let value = self.local[r].unwrap_float(); 242 | print!("{}", value); 243 | } 244 | Instr::FScan(r) => { 245 | let mut s = String::new(); 246 | std::io::stdin().read_line(&mut s).unwrap(); 247 | self.local 248 | .insert(*r, Value::Float(s.trim().parse().unwrap_or(0.0))); 249 | } 250 | Instr::CPrint(r) => { 251 | let value = self.local[r].unwrap_char(); 252 | print!("{}", value); 253 | } 254 | Instr::CScan(r) => { 255 | let mut s = String::new(); 256 | std::io::stdin().read_line(&mut s).unwrap(); 257 | self.local 258 | .insert(*r, Value::Char(s.trim().parse().unwrap_or('0'))); 259 | } 260 | Instr::Assert(r) => { 261 | let value = self.local[r].unwrap_bool(); 262 | if !value { 263 | panic!("assert failed!"); 264 | } 265 | } 266 | } 267 | } 268 | match run_blk.last.as_ref().unwrap() { 269 | LastInstr::TailCall(func, args) => { 270 | let func = self.local[&func].unwrap_addr(); 271 | let pars = self.pars_map[&func]; 272 | let args: Vec<_> = args.iter().map(|arg| self.local[arg]).collect(); 273 | assert_eq!(pars.len(), args.len()); 274 | let mut temp = HashMap::new(); 275 | for (par, arg) in pars.iter().zip(args.iter()) { 276 | temp.insert(*par, *arg); 277 | } 278 | // jump to new function with new local variables 279 | self.local = temp; 280 | run_blk = self.code_map[&func]; 281 | } 282 | LastInstr::Call(bind, func, cont, args) => { 283 | let func = self.local[&func].unwrap_addr(); 284 | // introduce function parameters 285 | let pars = self.pars_map[&func]; 286 | let args: Vec<_> = args.iter().map(|arg| self.local[arg]).collect(); 287 | assert_eq!(pars.len(), args.len()); 288 | let mut temp = HashMap::new(); 289 | for (par, arg) in pars.iter().zip(args.iter()) { 290 | temp.insert(*par, *arg); 291 | } 292 | // push current local variables and call function 293 | std::mem::swap(&mut self.local, &mut temp); 294 | self.stack.push(CallSave { 295 | bind: *bind, 296 | cont: *cont, 297 | local: temp, 298 | }); 299 | run_blk = self.code_map[&func]; 300 | } 301 | LastInstr::Return(ret) => { 302 | if let Some(save) = self.stack.pop() { 303 | let CallSave { bind, cont, local } = save; 304 | let ret = self.local[ret]; 305 | self.local = local; 306 | self.local.insert(bind, ret); 307 | run_blk = self.code_map[&cont]; 308 | } else { 309 | return self.local[ret]; 310 | } 311 | } 312 | LastInstr::Jump(cont) => { 313 | run_blk = self.code_map[&cont]; 314 | } 315 | LastInstr::BrIf(cond, trbr, flbr) => { 316 | if let Value::Bool(cond) = self.local[cond] { 317 | if cond { 318 | run_blk = self.code_map[trbr]; 319 | } else { 320 | run_blk = self.code_map[flbr]; 321 | } 322 | } else { 323 | panic!("non-boolean value for if-then-else!"); 324 | } 325 | } 326 | } 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /src/backend/lowering.rs: -------------------------------------------------------------------------------- 1 | use crate::core::cps::{self, Atom, Expr, FuncDecl}; 2 | use crate::syntax::prim::{Compare, Prim}; 3 | use crate::utils::ident::Ident; 4 | use std::collections::{HashMap, HashSet}; 5 | 6 | use super::tac::*; 7 | 8 | pub struct Lowering { 9 | cur_blk: Option, 10 | cur_func: Option, 11 | cur_modl: Module, 12 | addr_set: HashSet, 13 | cont_pars: HashMap>, 14 | } 15 | impl Lowering { 16 | pub fn new(name: Ident) -> Lowering { 17 | Lowering { 18 | cur_blk: None, 19 | cur_func: None, 20 | cur_modl: Module::new(name), 21 | addr_set: HashSet::new(), 22 | cont_pars: HashMap::new(), 23 | } 24 | } 25 | 26 | pub fn run(modl: &cps::Module) -> Module { 27 | let mut pass = Lowering::new(modl.name); 28 | for decl in modl.decls.iter() { 29 | pass.addr_set.insert(decl.func); 30 | } 31 | for decl in modl.decls.iter() { 32 | pass.visit_func_decl(decl); 33 | } 34 | pass.cur_modl 35 | } 36 | 37 | fn push(&mut self, code: Instr) { 38 | self.cur_blk.as_mut().unwrap().push(code); 39 | } 40 | 41 | fn seal(&mut self, last: LastInstr) { 42 | self.cur_blk.as_mut().unwrap().seal(last); 43 | } 44 | 45 | fn new_block(&mut self, name: Ident) { 46 | assert!(self.cur_blk.is_none()); 47 | let blk = BasicBlock::new(name); 48 | self.cur_blk = Some(blk); 49 | } 50 | 51 | fn emit_block(&mut self) { 52 | assert!(self.cur_blk.is_some()); 53 | assert!(self.cur_blk.as_mut().unwrap().is_sealed()); 54 | let blk = self.cur_blk.take().unwrap(); 55 | self.cur_func.as_mut().unwrap().push(blk); 56 | } 57 | 58 | fn new_func(&mut self, name: Ident, pars: Vec) { 59 | assert!(self.cur_func.is_none()); 60 | let func = Function::new(name, pars); 61 | self.cur_func = Some(func); 62 | } 63 | 64 | fn emit_func(&mut self) { 65 | assert!(self.cur_func.is_some()); 66 | let func = self.cur_func.take().unwrap(); 67 | self.cur_modl.push(func); 68 | } 69 | 70 | fn visit_atom(&mut self, atom: &cps::Atom) -> Ident { 71 | match atom { 72 | Atom::Var(x) => { 73 | if self.addr_set.contains(x) { 74 | let x2 = Ident::fresh(&"x"); 75 | self.push(Instr::LitA(x2, *x)); 76 | x2 77 | } else { 78 | *x 79 | } 80 | } 81 | Atom::Int(v) => { 82 | let x = Ident::fresh(&"x"); 83 | self.push(Instr::LitI(x, *v)); 84 | x 85 | } 86 | Atom::Float(v) => { 87 | let x = Ident::fresh(&"x"); 88 | self.push(Instr::LitF(x, *v)); 89 | x 90 | } 91 | Atom::Bool(v) => { 92 | let x = Ident::fresh(&"x"); 93 | self.push(Instr::LitB(x, *v)); 94 | x 95 | } 96 | Atom::Char(v) => { 97 | let x = Ident::fresh(&"x"); 98 | self.push(Instr::LitC(x, *v)); 99 | x 100 | } 101 | Atom::Unit => { 102 | let x = Ident::fresh(&"x"); 103 | self.push(Instr::LitI(x, 0)); 104 | x 105 | } 106 | } 107 | } 108 | 109 | fn visit_func_decl(&mut self, decl: &FuncDecl) { 110 | let FuncDecl { 111 | func, 112 | cont, 113 | pars, 114 | body, 115 | } = decl; 116 | self.new_func(*func, pars.clone()); 117 | let entry = Ident::fresh(&"entry"); 118 | self.new_block(entry); 119 | self.visit_expr(body, *cont); 120 | self.emit_func(); 121 | } 122 | 123 | fn visit_expr(&mut self, expr: &Expr, cont: Ident) { 124 | match expr { 125 | Expr::Decls { funcs, conts, body } => { 126 | assert!(funcs.is_empty()); 127 | for decl in conts { 128 | self.cont_pars.insert(decl.cont, decl.pars.clone()); 129 | } 130 | self.visit_expr(body, cont); 131 | for decl in conts { 132 | self.new_block(decl.cont); 133 | self.visit_expr(&decl.body, cont); 134 | } 135 | for decl in conts { 136 | self.cont_pars.remove(&decl.cont); 137 | } 138 | } 139 | Expr::Prim { 140 | bind, 141 | prim, 142 | args, 143 | rest, 144 | } => { 145 | assert_eq!(prim.get_arity(), args.len()); 146 | let args: Vec<_> = args.iter().map(|arg| self.visit_atom(arg)).collect(); 147 | match (prim, &args[..]) { 148 | (Prim::IAdd, [arg1, arg2]) => { 149 | self.push(Instr::IAdd(*bind, *arg1, *arg2)); 150 | } 151 | (Prim::ISub, [arg1, arg2]) => { 152 | self.push(Instr::ISub(*bind, *arg1, *arg2)); 153 | } 154 | (Prim::IMul, [arg1, arg2]) => { 155 | self.push(Instr::IMul(*bind, *arg1, *arg2)); 156 | } 157 | (Prim::IDiv, [arg1, arg2]) => { 158 | self.push(Instr::IDiv(*bind, *arg1, *arg2)); 159 | } 160 | (Prim::IRem, [arg1, arg2]) => { 161 | self.push(Instr::IRem(*bind, *arg1, *arg2)); 162 | } 163 | (Prim::INeg, [arg1]) => { 164 | self.push(Instr::INeg(*bind, *arg1)); 165 | } 166 | (Prim::FAdd, [arg1, arg2]) => { 167 | self.push(Instr::FAdd(*bind, *arg1, *arg2)); 168 | } 169 | (Prim::FSub, [arg1, arg2]) => { 170 | self.push(Instr::FSub(*bind, *arg1, *arg2)); 171 | } 172 | (Prim::FMul, [arg1, arg2]) => { 173 | self.push(Instr::FMul(*bind, *arg1, *arg2)); 174 | } 175 | (Prim::FDiv, [arg1, arg2]) => { 176 | self.push(Instr::FDiv(*bind, *arg1, *arg2)); 177 | } 178 | (Prim::FNeg, [arg1]) => { 179 | self.push(Instr::FNeg(*bind, *arg1)); 180 | } 181 | (Prim::ICmp(cmp), [arg1, arg2]) => { 182 | self.push(Instr::ICmp(*cmp, *bind, *arg1, *arg2)); 183 | } 184 | (Prim::FCmp(cmp), [arg1, arg2]) => { 185 | self.push(Instr::FCmp(*cmp, *bind, *arg1, *arg2)); 186 | } 187 | (Prim::Move, [arg]) => { 188 | self.push(Instr::Move(*bind, *arg)); 189 | } 190 | (Prim::Alloc, [arg]) => { 191 | self.push(Instr::Alloc(*bind, *arg)); 192 | } 193 | (Prim::Load, [arg1, arg2]) => { 194 | self.push(Instr::Load(*bind, *arg1, *arg2)); 195 | } 196 | (Prim::Store, [arg1, arg2, arg3]) => { 197 | self.push(Instr::Store(*arg1, *arg2, *arg3)); 198 | } 199 | (Prim::IPrint, [arg]) => { 200 | self.push(Instr::IPrint(*arg)); 201 | } 202 | (Prim::IScan, []) => { 203 | self.push(Instr::IScan(*bind)); 204 | } 205 | (Prim::FPrint, [arg]) => { 206 | self.push(Instr::FPrint(*arg)); 207 | } 208 | (Prim::FScan, []) => { 209 | self.push(Instr::FScan(*bind)); 210 | } 211 | (Prim::CPrint, [arg]) => { 212 | self.push(Instr::CPrint(*arg)); 213 | } 214 | (Prim::CScan, []) => { 215 | self.push(Instr::CScan(*bind)); 216 | } 217 | (Prim::Assert, [arg]) => { 218 | self.push(Instr::Assert(*arg)); 219 | } 220 | (prim, _) => { 221 | println!("{prim}"); 222 | unreachable!() 223 | } 224 | } 225 | self.visit_expr(rest, cont); 226 | } 227 | Expr::Record { bind, args, rest } => { 228 | let r = Ident::fresh(&"r"); 229 | self.push(Instr::LitI(r, args.len() as i64)); 230 | self.push(Instr::Alloc(*bind, r)); 231 | for (i, (_, arg)) in args.iter().enumerate() { 232 | let idx = self.visit_atom(&Atom::Int(i as i64)); 233 | let arg = self.visit_atom(arg); 234 | self.push(Instr::Store(*bind, idx, arg)); 235 | } 236 | self.visit_expr(rest, cont); 237 | } 238 | Expr::Select { 239 | bind, 240 | rec, 241 | idx, 242 | rest, 243 | } => { 244 | let rec = self.visit_atom(rec); 245 | let idx = self.visit_atom(&Atom::Int(*idx as i64)); 246 | self.push(Instr::Load(*bind, rec, idx)); 247 | self.visit_expr(rest, cont); 248 | } 249 | Expr::Update { 250 | rec, 251 | idx, 252 | arg, 253 | rest, 254 | } => { 255 | let rec = self.visit_atom(rec); 256 | let idx = self.visit_atom(&Atom::Int(*idx as i64)); 257 | let arg = self.visit_atom(arg); 258 | self.push(Instr::Store(rec, idx, arg)); 259 | self.visit_expr(rest, cont); 260 | } 261 | Expr::Call { 262 | func, 263 | cont: cont2, 264 | args, 265 | } if *cont2 == cont => { 266 | let func = self.visit_atom(&Atom::Var(*func)); 267 | let args: Vec<_> = args.iter().map(|arg| self.visit_atom(arg)).collect(); 268 | self.seal(LastInstr::TailCall(func, args)); 269 | self.emit_block(); 270 | } 271 | Expr::Call { func, cont, args } => { 272 | let func = self.visit_atom(&Atom::Var(*func)); 273 | let args: Vec<_> = args.iter().map(|arg| self.visit_atom(arg)).collect(); 274 | assert_eq!(self.cont_pars[cont].len(), 1); 275 | let bind = self.cont_pars[cont][0]; 276 | self.seal(LastInstr::Call(bind, func, *cont, args)); 277 | self.emit_block(); 278 | } 279 | Expr::Jump { cont: cont2, args } if *cont2 == cont => { 280 | assert_eq!(args.len(), 1); 281 | let var = self.visit_atom(&args[0]); 282 | self.seal(LastInstr::Return(var)); 283 | self.emit_block(); 284 | } 285 | Expr::Jump { cont, args } => { 286 | let args: Vec<_> = args.iter().map(|arg| self.visit_atom(arg)).collect(); 287 | println!("{}", cont); 288 | let par_arg: Vec<(Ident, Ident)> = self.cont_pars[cont] 289 | .iter() 290 | .zip(args.iter()) 291 | .map(|(par, arg)| (*par, *arg)) 292 | .collect(); 293 | for (par, arg) in par_arg { 294 | self.push(Instr::Move(par, arg)); 295 | } 296 | self.seal(LastInstr::Jump(*cont)); 297 | self.emit_block(); 298 | } 299 | Expr::Ifte { 300 | cond, 301 | args, 302 | trbr, 303 | flbr, 304 | } => { 305 | let trbr_label = Ident::fresh(&"trbr"); 306 | let flbr_label = Ident::fresh(&"flbr"); 307 | let args: Vec<_> = args.iter().map(|arg| self.visit_atom(arg)).collect(); 308 | match (cond, &args[..]) { 309 | (cps::IfCond::BTrue, [arg]) => { 310 | self.seal(LastInstr::BrIf(*arg, trbr_label, flbr_label)); 311 | } 312 | (_, _) => { 313 | todo!() 314 | } 315 | } 316 | self.emit_block(); 317 | 318 | self.new_block(trbr_label); 319 | self.visit_expr(trbr, cont); 320 | 321 | self.new_block(flbr_label); 322 | self.visit_expr(flbr, cont); 323 | } 324 | Expr::Switch { arg, brchs, dflt } => { 325 | fn binary_search(slf: &mut Lowering, arg: Ident, brchs: &[(usize, Ident, &Expr)]) { 326 | assert!(!brchs.is_empty()); 327 | if brchs.len() == 1 { 328 | slf.seal(LastInstr::Jump(brchs[0].1)); 329 | slf.emit_block(); 330 | } else { 331 | let mid_len = brchs.len() / 2; 332 | let mid_id = brchs[mid_len].0; 333 | 334 | let temp = Ident::fresh(&"temp"); 335 | let trbr_label = Ident::fresh(&"trbr"); 336 | let flbr_label = Ident::fresh(&"flbr"); 337 | 338 | slf.push(Instr::LitI(temp, mid_id as i64)); 339 | slf.push(Instr::ICmp(Compare::Lt, temp, arg, temp)); 340 | slf.seal(LastInstr::BrIf(temp, trbr_label, flbr_label)); 341 | slf.emit_block(); 342 | 343 | slf.new_block(trbr_label); 344 | binary_search(slf, arg, &brchs[0..mid_len]); 345 | 346 | slf.new_block(flbr_label); 347 | binary_search(slf, arg, &brchs[mid_len..]); 348 | } 349 | } 350 | let brchs: Vec<(usize, Ident, &Expr)> = brchs 351 | .into_iter() 352 | .map(|(i, brch)| (*i, Ident::fresh(&"case"), brch)) 353 | .collect(); 354 | let dflt = dflt.as_ref().map(|dflt| (Ident::fresh(&"default"), dflt)); 355 | let arg = self.visit_atom(arg); 356 | 357 | binary_search(self, arg, &brchs[..]); 358 | for (_i, label, brch) in brchs { 359 | self.new_block(label); 360 | self.visit_expr(&brch, cont); 361 | } 362 | if let Some((label, dflt)) = dflt { 363 | self.new_block(label); 364 | self.visit_expr(&dflt, cont); 365 | } 366 | } 367 | Expr::Retn { res: _ } => { 368 | panic!("no return instruction!"); 369 | } 370 | } 371 | } 372 | } 373 | 374 | #[test] 375 | #[ignore = "just to see result"] 376 | fn lowering_test() { 377 | let s = r#" 378 | module test where 379 | func f(k, x): 380 | let a = @iadd(x, 1); 381 | let b = @iadd(a, 1); 382 | let c = @iadd(b, 1); 383 | let y = @iadd(c, 1); 384 | jump k(x); 385 | 386 | func main(k): 387 | call f(k, 42); 388 | "#; 389 | let modl = crate::core::parser::parse_module(s).unwrap(); 390 | println!("{}\n", modl); 391 | let modl = Lowering::run(&modl); 392 | println!("{:#?}\n", modl); 393 | } 394 | -------------------------------------------------------------------------------- /src/syntax/rename.rs: -------------------------------------------------------------------------------- 1 | use super::ast::*; 2 | use super::lexer::Span; 3 | use crate::analyze::diagnostic::Diagnostic; 4 | use crate::utils::env_map::EnvMap; 5 | use crate::utils::ident::Ident; 6 | use std::ops::DerefMut; 7 | 8 | struct Renamer<'diag> { 9 | val_ctx: EnvMap, 10 | typ_ctx: EnvMap, 11 | cons_ctx: EnvMap, 12 | data_ctx: EnvMap, 13 | diags: &'diag mut Vec, 14 | } 15 | 16 | type RenameResult = Result<(), ()>; 17 | 18 | impl<'diag> Renamer<'diag> { 19 | pub fn new(diags: &'diag mut Vec) -> Renamer<'diag> { 20 | Renamer { 21 | val_ctx: EnvMap::new(), 22 | typ_ctx: EnvMap::new(), 23 | cons_ctx: EnvMap::new(), 24 | data_ctx: EnvMap::new(), 25 | diags, 26 | } 27 | } 28 | 29 | fn enter_scope(&mut self) { 30 | self.val_ctx.enter_scope(); 31 | self.typ_ctx.enter_scope(); 32 | self.cons_ctx.enter_scope(); 33 | self.data_ctx.enter_scope(); 34 | } 35 | 36 | fn leave_scope(&mut self) { 37 | self.val_ctx.leave_scope(); 38 | self.typ_ctx.leave_scope(); 39 | self.cons_ctx.leave_scope(); 40 | self.data_ctx.leave_scope(); 41 | } 42 | 43 | fn intro_val_ident(&mut self, ident: &mut Ident) { 44 | assert!(ident.is_dummy()); 45 | let new = ident.uniquify(); 46 | self.val_ctx.insert(*ident, new); 47 | *ident = new; 48 | } 49 | 50 | fn intro_typ_ident(&mut self, ident: &mut Ident) { 51 | assert!(ident.is_dummy()); 52 | let new = ident.uniquify(); 53 | self.typ_ctx.insert(*ident, new); 54 | *ident = new; 55 | } 56 | 57 | fn intro_cons_ident(&mut self, ident: &mut Ident) { 58 | assert!(ident.is_dummy()); 59 | let new = ident.uniquify(); 60 | self.cons_ctx.insert(*ident, new); 61 | *ident = new; 62 | } 63 | 64 | fn intro_data_ident(&mut self, ident: &mut Ident) { 65 | assert!(ident.is_dummy()); 66 | let new = ident.uniquify(); 67 | self.data_ctx.insert(*ident, new); 68 | *ident = new; 69 | } 70 | 71 | fn rename_val_ident(&mut self, ident: &mut Ident, span: Span) -> RenameResult { 72 | assert!(ident.is_dummy()); 73 | if let Some(res) = self.val_ctx.get(&ident) { 74 | *ident = *res; 75 | } else { 76 | self.diags.push( 77 | Diagnostic::error("value variable not found!") 78 | .line_span(span, format!("here is the value variable {ident}")), 79 | ); 80 | } 81 | Ok(()) 82 | } 83 | 84 | fn rename_typ_ident(&mut self, ident: &mut Ident, span: Span) -> RenameResult { 85 | assert!(ident.is_dummy()); 86 | if let Some(res) = self.typ_ctx.get(&ident) { 87 | *ident = *res; 88 | } else { 89 | self.diags.push( 90 | Diagnostic::error("type variable not found!") 91 | .line_span(span, format!("here is the type variable {ident}")), 92 | ); 93 | } 94 | Ok(()) 95 | } 96 | 97 | fn rename_cons_ident(&mut self, ident: &mut Ident, span: Span) -> RenameResult { 98 | assert!(ident.is_dummy()); 99 | if let Some(res) = self.cons_ctx.get(&ident) { 100 | *ident = *res; 101 | } else { 102 | self.diags.push( 103 | Diagnostic::error("data constructor not found!") 104 | .line_span(span, format!("here is the data constructor {ident}")), 105 | ); 106 | } 107 | Ok(()) 108 | } 109 | 110 | fn rename_data_ident(&mut self, ident: &mut Ident, span: Span) -> RenameResult { 111 | assert!(ident.is_dummy()); 112 | if let Some(res) = self.data_ctx.get(&ident) { 113 | *ident = *res; 114 | } else { 115 | self.diags.push( 116 | Diagnostic::error("data type not found!") 117 | .line_span(span, format!("here is the data type {ident}")), 118 | ); 119 | } 120 | Ok(()) 121 | } 122 | 123 | fn rename_expr(&mut self, expr: &mut Expr) -> RenameResult { 124 | match expr { 125 | Expr::Lit { lit: _, span: _ } => Ok(()), 126 | Expr::Var { ident, span } => { 127 | self.rename_val_ident(ident, span.clone())?; 128 | Ok(()) 129 | } 130 | Expr::Prim { 131 | prim: _, 132 | args, 133 | span: _, 134 | } => { 135 | for arg in args.iter_mut() { 136 | self.rename_expr(arg)? 137 | } 138 | Ok(()) 139 | } 140 | Expr::Cons { cons, flds, span } => { 141 | self.rename_cons_ident(cons, span.clone())?; 142 | for fld in flds.iter_mut() { 143 | self.rename_expr(&mut fld.data)?; 144 | } 145 | Ok(()) 146 | } 147 | Expr::Func { 148 | pars, 149 | body, 150 | span: _, 151 | } => { 152 | self.enter_scope(); 153 | for par in pars.iter_mut() { 154 | self.intro_val_ident(par); 155 | } 156 | self.rename_expr(body)?; 157 | self.leave_scope(); 158 | Ok(()) 159 | } 160 | Expr::App { 161 | func, 162 | args, 163 | span: _, 164 | } => { 165 | self.rename_expr(func)?; 166 | for arg in args.iter_mut() { 167 | self.rename_expr(arg)?; 168 | } 169 | Ok(()) 170 | } 171 | Expr::Ifte { 172 | cond, 173 | trbr, 174 | flbr, 175 | span: _, 176 | } => { 177 | self.rename_expr(cond)?; 178 | self.rename_expr(trbr)?; 179 | self.rename_expr(flbr)?; 180 | Ok(()) 181 | } 182 | Expr::Case { 183 | expr, 184 | rules, 185 | span: _, 186 | } => { 187 | self.rename_expr(expr)?; 188 | for rule in rules.iter_mut() { 189 | self.rename_rule(rule)?; 190 | } 191 | Ok(()) 192 | } 193 | Expr::Field { 194 | expr, 195 | field: _, 196 | cons_info: _, 197 | span: _, 198 | } => { 199 | self.rename_expr(expr)?; 200 | Ok(()) 201 | } 202 | Expr::NewRef { expr, span: _ } => { 203 | self.rename_expr(expr)?; 204 | Ok(()) 205 | } 206 | Expr::RefGet { expr, span: _ } => { 207 | self.rename_expr(expr)?; 208 | Ok(()) 209 | } 210 | Expr::Stmt { 211 | stmt, 212 | cont, 213 | span: _, 214 | } => { 215 | match stmt.deref_mut() { 216 | Stmt::Let { 217 | ident, 218 | typ, 219 | expr, 220 | span: _, 221 | } => { 222 | self.rename_expr(expr)?; 223 | self.val_ctx.enter_scope(); 224 | self.intro_val_ident(ident); 225 | if let Some(typ) = typ { 226 | self.rename_type(typ)?; 227 | } 228 | self.rename_expr(cont)?; 229 | self.val_ctx.leave_scope(); 230 | return Ok(()); 231 | } 232 | Stmt::RefSet { lhs, rhs, span: _ } => { 233 | self.rename_expr(lhs)?; 234 | self.rename_expr(rhs)?; 235 | } 236 | Stmt::Assign { lhs, rhs, span: _ } => { 237 | self.rename_expr(lhs)?; 238 | self.rename_expr(rhs)?; 239 | } 240 | Stmt::While { 241 | cond, 242 | body, 243 | span: _, 244 | } => { 245 | self.rename_expr(cond)?; 246 | self.rename_expr(body)?; 247 | } 248 | Stmt::Do { expr, span: _ } => { 249 | self.rename_expr(expr)?; 250 | } 251 | } 252 | self.rename_expr(cont)?; 253 | Ok(()) 254 | } 255 | } 256 | } 257 | 258 | fn rename_type(&mut self, typ: &mut Type) -> RenameResult { 259 | match typ { 260 | Type::Lit { lit: _, span: _ } => Ok(()), 261 | Type::Var { ident, span } => { 262 | if self.data_ctx.contains_key(&ident) { 263 | // it's impossible to decide whether a Type::Var is really a type variable in parser 264 | // it could also be a datatype construction with zero argument 265 | // so we can only lookup the context and elaborate it in renaming pass 266 | *typ = Type::Cons { 267 | cons: *ident, 268 | args: Vec::new(), 269 | span: span.clone(), 270 | }; 271 | self.rename_type(typ) 272 | } else { 273 | self.rename_typ_ident(ident, span.clone()) 274 | } 275 | } 276 | Type::Cons { cons, args, span } => { 277 | self.rename_data_ident(cons, span.clone())?; 278 | for arg in args.iter_mut() { 279 | self.rename_type(arg)?; 280 | } 281 | Ok(()) 282 | } 283 | Type::Func { pars, res, span: _ } => { 284 | for par in pars.iter_mut() { 285 | self.rename_type(par)?; 286 | } 287 | self.rename_type(res)?; 288 | Ok(()) 289 | } 290 | } 291 | } 292 | 293 | fn rename_rule(&mut self, rule: &mut Rule) -> RenameResult { 294 | let Rule { 295 | patn, 296 | body, 297 | span: _, 298 | } = rule; 299 | self.enter_scope(); 300 | self.rename_pattern(patn)?; 301 | self.rename_expr(body)?; 302 | self.leave_scope(); 303 | Ok(()) 304 | } 305 | 306 | fn rename_pattern(&mut self, patn: &mut Pattern) -> RenameResult { 307 | match patn { 308 | Pattern::Var { ident, span: _ } => { 309 | self.intro_val_ident(ident); 310 | } 311 | Pattern::Lit { lit: _, span: _ } => {} 312 | Pattern::Cons { 313 | cons, 314 | patns, 315 | as_ident, 316 | span, 317 | } => { 318 | self.rename_cons_ident(cons, span.clone())?; 319 | if let Some(as_ident) = as_ident { 320 | self.intro_val_ident(as_ident); 321 | } 322 | for patn in patns.iter_mut() { 323 | self.rename_pattern(&mut patn.data)?; 324 | } 325 | } 326 | Pattern::Wild { span: _ } => {} 327 | } 328 | Ok(()) 329 | } 330 | 331 | fn rename_decl(&mut self, decl: &mut Decl) -> RenameResult { 332 | match decl { 333 | Decl::Func { 334 | sign: 335 | FuncSign { 336 | func: _, 337 | polys, 338 | pars, 339 | res, 340 | span: _, 341 | }, 342 | body, 343 | span: _, 344 | } => { 345 | self.enter_scope(); 346 | for poly in polys { 347 | self.intro_typ_ident(poly); 348 | } 349 | for (par, typ) in pars.iter_mut() { 350 | self.intro_val_ident(par); 351 | self.rename_type(typ)?; 352 | } 353 | self.rename_type(res)?; 354 | self.rename_expr(body)?; 355 | self.leave_scope(); 356 | Ok(()) 357 | } 358 | Decl::Data { 359 | ident: _, 360 | polys, 361 | vars, 362 | span: _, 363 | } => { 364 | self.enter_scope(); 365 | for poly in polys { 366 | self.intro_typ_ident(poly); 367 | } 368 | for var in vars { 369 | for fld in var.flds.iter_mut() { 370 | self.rename_type(&mut fld.data.1)?; 371 | } 372 | } 373 | self.leave_scope(); 374 | Ok(()) 375 | } 376 | } 377 | } 378 | 379 | fn rename_module(&mut self, modl: &mut Module) -> RenameResult { 380 | let Module { name: _, decls } = modl; 381 | self.enter_scope(); 382 | for decl in decls.iter_mut() { 383 | match decl { 384 | Decl::Func { sign, .. } => { 385 | self.intro_val_ident(&mut sign.func); 386 | } 387 | Decl::Data { 388 | ident, 389 | polys: _, 390 | vars, 391 | span: _, 392 | } => { 393 | self.intro_data_ident(ident); 394 | for var in vars.iter_mut() { 395 | self.intro_cons_ident(&mut var.cons); 396 | } 397 | } 398 | } 399 | } 400 | for decl in decls.iter_mut() { 401 | self.rename_decl(decl)?; 402 | } 403 | self.leave_scope(); 404 | Ok(()) 405 | } 406 | } 407 | 408 | pub fn rename_expr<'diag>(expr: &mut Expr, diags: &'diag mut Vec) -> Result<(), ()> { 409 | let mut pass = Renamer::new(diags); 410 | pass.rename_expr(expr) 411 | } 412 | 413 | pub fn rename_module<'diag>( 414 | expr: &mut Module, 415 | diags: &'diag mut Vec, 416 | ) -> Result<(), ()> { 417 | let mut pass = Renamer::new(diags); 418 | pass.rename_module(expr) 419 | } 420 | 421 | #[test] 422 | #[ignore = "just to see result"] 423 | fn renamer_test() { 424 | use crate::syntax::parser::parse_module; 425 | let s = r#" 426 | module Test where 427 | datatype List[T] where 428 | | Nil 429 | | Cons(T, List[T]) 430 | end 431 | function map[T, U](f: fn(T) -> U, xs: List[T]) -> List[U] 432 | begin 433 | match xs with 434 | | Nil => Nil 435 | | Cons(x, xs) => Cons(f(x), map(f,xs)) 436 | end 437 | end 438 | datatype List2[T] where 439 | | Nil2 440 | | Cons2 { head: T, tail: List2[T] } 441 | end 442 | function map2[T, U](f: fn(T) -> U, xs: List2[T]) -> List2[U] 443 | begin 444 | match xs with 445 | | Nil2 => Nil2 446 | | Cons2 { head, tail } => 447 | Cons2 { head: f(head), tail: map2(f,tail) } 448 | end 449 | end 450 | function f(x: Int) -> Int 451 | begin 452 | let f = fn(x) => @iadd(x,1); 453 | let res = f(42); 454 | let test = if @icmpls(1, 2) then 3 else 4; 455 | res 456 | end 457 | function g(x: Int) -> Int 458 | begin 459 | let r2 = ref 42; 460 | r2 := 2; 461 | let r = @iadd(x, 1); 462 | r 463 | end 464 | function id[T](x: T) -> T 465 | begin 466 | x 467 | end 468 | "#; 469 | let mut diags = Vec::new(); 470 | let mut modl = parse_module(s, &mut diags).unwrap(); 471 | assert!(diags.is_empty()); 472 | rename_module(&mut modl, &mut diags).unwrap(); 473 | println!("{:#?}", modl); 474 | } 475 | -------------------------------------------------------------------------------- /src/core/optimize.rs: -------------------------------------------------------------------------------- 1 | use super::cps::{self, Atom, IfCond, Module}; 2 | use crate::{syntax::prim::Prim, utils::ident::Ident}; 3 | use std::collections::{HashMap, HashSet}; 4 | 5 | pub struct Optimizer { 6 | atom_map: HashMap, 7 | record_map: HashMap>, 8 | used_set: HashSet, 9 | } 10 | 11 | impl Optimizer { 12 | pub fn run(modl: Module) -> Module { 13 | let mut pass = Optimizer { 14 | atom_map: HashMap::new(), 15 | record_map: HashMap::new(), 16 | used_set: HashSet::new(), 17 | }; 18 | pass.visit_module(modl) 19 | } 20 | 21 | fn visit_atom(&mut self, arg: Atom) -> Atom { 22 | let mut res = arg; 23 | while res.is_var() { 24 | let var = res.unwrap_var(); 25 | if let Some(new_res) = self.atom_map.get(&var) { 26 | res = *new_res; 27 | } else { 28 | break; 29 | } 30 | } 31 | res 32 | } 33 | 34 | fn mark_val_used(&mut self, arg: &Atom) { 35 | if let Atom::Var(var) = arg { 36 | self.used_set.insert(*var); 37 | } 38 | } 39 | 40 | fn visit_module(&mut self, modl: cps::Module) -> cps::Module { 41 | let Module { name, decls } = modl; 42 | 43 | let func_names: Vec = decls.iter().map(|decl| decl.func).collect(); 44 | 45 | let decls: Vec = decls 46 | .into_iter() 47 | .map(|decl| { 48 | let cps::FuncDecl { 49 | func, 50 | cont, 51 | pars, 52 | body, 53 | } = decl; 54 | let body = self.visit_expr(body); 55 | self.used_set.remove(&cont); 56 | for par in pars.iter() { 57 | self.used_set.remove(par); 58 | } 59 | for name in func_names.iter() { 60 | self.used_set.remove(name); 61 | } 62 | cps::FuncDecl { 63 | func, 64 | cont, 65 | pars, 66 | body, 67 | } 68 | }) 69 | .collect(); 70 | 71 | Module { name, decls } 72 | } 73 | 74 | fn visit_expr(&mut self, expr: cps::Expr) -> cps::Expr { 75 | match expr { 76 | cps::Expr::Decls { funcs, conts, body } => { 77 | let func_names: Vec = funcs.iter().map(|decl| decl.func).collect(); 78 | let cont_names: Vec = conts.iter().map(|decl| decl.cont).collect(); 79 | let decl_names: Vec = func_names 80 | .iter() 81 | .chain(cont_names.iter()) 82 | .copied() 83 | .collect(); 84 | 85 | let mut call_graph: HashMap> = decl_names 86 | .iter() 87 | .map(|name| (*name, HashSet::new())) 88 | .collect(); 89 | 90 | let funcs: Vec = funcs 91 | .into_iter() 92 | .map(|decl| { 93 | let cps::FuncDecl { 94 | func, 95 | cont, 96 | pars, 97 | body, 98 | } = decl; 99 | let body = self.visit_expr(body); 100 | self.used_set.remove(&cont); 101 | for par in pars.iter() { 102 | self.used_set.remove(par); 103 | } 104 | for name in decl_names.iter() { 105 | if self.used_set.remove(name) { 106 | call_graph.get_mut(&func).unwrap().insert(*name); 107 | } 108 | } 109 | cps::FuncDecl { 110 | func, 111 | cont, 112 | pars, 113 | body, 114 | } 115 | }) 116 | .collect(); 117 | 118 | let conts: Vec = conts 119 | .into_iter() 120 | .map(|decl| { 121 | let cps::ContDecl { cont, pars, body } = decl; 122 | let body = self.visit_expr(body); 123 | for par in pars.iter() { 124 | self.used_set.remove(par); 125 | } 126 | for name in decl_names.iter() { 127 | if self.used_set.remove(name) { 128 | call_graph.get_mut(&cont).unwrap().insert(*name); 129 | } 130 | } 131 | cps::ContDecl { cont, pars, body } 132 | }) 133 | .collect(); 134 | 135 | let body = Box::new(self.visit_expr(*body)); 136 | 137 | let start: HashSet = decl_names 138 | .iter() 139 | .filter(|name| self.used_set.remove(name)) 140 | .copied() 141 | .collect(); 142 | 143 | let reachable = calculate_reachable(&call_graph, &start); 144 | 145 | let funcs: Vec<_> = funcs 146 | .into_iter() 147 | .filter(|decl| reachable.contains(&decl.func)) 148 | .collect(); 149 | 150 | let conts: Vec<_> = conts 151 | .into_iter() 152 | .filter(|decl| reachable.contains(&decl.cont)) 153 | .collect(); 154 | 155 | if funcs.is_empty() && conts.is_empty() { 156 | *body 157 | } else { 158 | cps::Expr::Decls { funcs, conts, body } 159 | } 160 | } 161 | cps::Expr::Prim { 162 | bind, 163 | prim, 164 | args, 165 | rest, 166 | } => { 167 | assert!(prim.get_arity() == args.len()); 168 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 169 | match (prim, &args[..]) { 170 | (Prim::IAdd, [Atom::Int(a), Atom::Int(b)]) => { 171 | self.atom_map.insert(bind, Atom::Int(a + b)); 172 | self.visit_expr(*rest) 173 | } 174 | (Prim::ISub, [Atom::Int(a), Atom::Int(b)]) => { 175 | self.atom_map.insert(bind, Atom::Int(a - b)); 176 | self.visit_expr(*rest) 177 | } 178 | (Prim::IMul, [Atom::Int(a), Atom::Int(b)]) => { 179 | self.atom_map.insert(bind, Atom::Int(a * b)); 180 | self.visit_expr(*rest) 181 | } 182 | (Prim::Move, [atom]) => { 183 | self.atom_map.insert(bind, *atom); 184 | self.visit_expr(*rest) 185 | } 186 | _ => { 187 | let cont = self.visit_expr(*rest); 188 | // unused primitive elimination 189 | if !self.used_set.contains(&bind) && prim.is_pure() { 190 | cont 191 | } else { 192 | self.used_set.remove(&bind); 193 | args.iter().for_each(|arg| self.mark_val_used(arg)); 194 | cps::Expr::Prim { 195 | bind, 196 | prim, 197 | args, 198 | rest: Box::new(cont), 199 | } 200 | } 201 | } 202 | } 203 | } 204 | cps::Expr::Record { bind, args, rest } => { 205 | let args: Vec<(bool, Atom)> = args 206 | .into_iter() 207 | .map(|arg| (arg.0, self.visit_atom(arg.1))) 208 | .collect(); 209 | self.record_map.insert(bind, args.clone()); 210 | let rest = self.visit_expr(*rest); 211 | if self.used_set.contains(&bind) { 212 | self.used_set.remove(&bind); 213 | args.iter().for_each(|arg| self.mark_val_used(&arg.1)); 214 | cps::Expr::Record { 215 | bind, 216 | args, 217 | rest: Box::new(rest), 218 | } 219 | } else { 220 | rest 221 | } 222 | } 223 | cps::Expr::Select { 224 | bind, 225 | rec, 226 | idx, 227 | rest, 228 | } => { 229 | let rec = self.visit_atom(rec); 230 | if let Some(elems) = self.record_map.get(&rec.unwrap_var()) { 231 | if !elems[idx].0 { 232 | // if the field is not mutable, spread the value 233 | self.atom_map.insert(bind, elems[idx].1); 234 | return self.visit_expr(*rest); 235 | } 236 | } 237 | let rest = self.visit_expr(*rest); 238 | if self.used_set.contains(&bind) { 239 | self.used_set.remove(&bind); 240 | self.mark_val_used(&rec); 241 | cps::Expr::Select { 242 | bind, 243 | rec, 244 | idx, 245 | rest: Box::new(rest), 246 | } 247 | } else { 248 | rest 249 | } 250 | } 251 | cps::Expr::Update { 252 | rec, 253 | idx, 254 | arg, 255 | rest, 256 | } => { 257 | let rec = self.visit_atom(rec); 258 | let arg = self.visit_atom(arg); 259 | let rest = self.visit_expr(*rest); 260 | self.mark_val_used(&rec); 261 | self.mark_val_used(&arg); 262 | cps::Expr::Update { 263 | rec, 264 | idx, 265 | arg, 266 | rest: Box::new(rest), 267 | } 268 | } 269 | cps::Expr::Call { func, cont, args } => { 270 | let func = self.visit_atom(Atom::Var(func)).unwrap_var(); 271 | let cont = self.visit_atom(Atom::Var(cont)).unwrap_var(); 272 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 273 | self.used_set.insert(func); 274 | self.used_set.insert(cont); 275 | args.iter().for_each(|arg| self.mark_val_used(arg)); 276 | cps::Expr::Call { func, cont, args } 277 | } 278 | cps::Expr::Jump { cont, args } => { 279 | let cont = self.visit_atom(Atom::Var(cont)).unwrap_var(); 280 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 281 | self.used_set.insert(cont); 282 | args.iter().for_each(|arg| self.mark_val_used(arg)); 283 | cps::Expr::Jump { cont, args } 284 | } 285 | cps::Expr::Ifte { 286 | cond, 287 | args, 288 | trbr, 289 | flbr, 290 | } => { 291 | let args: Vec = args.into_iter().map(|arg| self.visit_atom(arg)).collect(); 292 | match (cond, &args[..]) { 293 | (IfCond::BTrue, [Atom::Bool(p)]) => { 294 | if *p { 295 | self.visit_expr(*trbr) 296 | } else { 297 | self.visit_expr(*flbr) 298 | } 299 | } 300 | (IfCond::BFalse, [Atom::Bool(p)]) => { 301 | if !*p { 302 | self.visit_expr(*trbr) 303 | } else { 304 | self.visit_expr(*flbr) 305 | } 306 | } 307 | (IfCond::ICmpGr, [Atom::Int(a), Atom::Int(b)]) => { 308 | if a > b { 309 | self.visit_expr(*trbr) 310 | } else { 311 | self.visit_expr(*flbr) 312 | } 313 | } 314 | (IfCond::ICmpEq, [Atom::Int(a), Atom::Int(b)]) => { 315 | if a == b { 316 | self.visit_expr(*trbr) 317 | } else { 318 | self.visit_expr(*flbr) 319 | } 320 | } 321 | (IfCond::ICmpLs, [Atom::Int(a), Atom::Int(b)]) => { 322 | if a < b { 323 | self.visit_expr(*trbr) 324 | } else { 325 | self.visit_expr(*flbr) 326 | } 327 | } 328 | _ => { 329 | let trbr = Box::new(self.visit_expr(*trbr)); 330 | let flbr = Box::new(self.visit_expr(*flbr)); 331 | args.iter().for_each(|arg| self.mark_val_used(arg)); 332 | cps::Expr::Ifte { 333 | cond, 334 | args, 335 | trbr, 336 | flbr, 337 | } 338 | } 339 | } 340 | } 341 | cps::Expr::Switch { arg, brchs, dflt } => { 342 | let arg = self.visit_atom(arg); 343 | 344 | if let Atom::Int(n) = arg { 345 | if let Some((_, brch)) = brchs.into_iter().find(|(i, _)| *i == n as usize) { 346 | self.visit_expr(brch) 347 | } else if let Some(dflt) = dflt { 348 | self.visit_expr(*dflt) 349 | } else { 350 | panic!("switch fallthrough without default branch!") 351 | } 352 | } else { 353 | let brchs = brchs 354 | .into_iter() 355 | .map(|(i, brch)| (i, self.visit_expr(brch))) 356 | .collect(); 357 | let dflt = dflt.map(|dflt| Box::new(self.visit_expr(*dflt))); 358 | self.mark_val_used(&arg); 359 | cps::Expr::Switch { arg, brchs, dflt } 360 | } 361 | } 362 | cps::Expr::Retn { res } => { 363 | let res = self.visit_atom(res); 364 | self.mark_val_used(&res); 365 | cps::Expr::Retn { res } 366 | } 367 | } 368 | } 369 | } 370 | 371 | fn calculate_reachable( 372 | call_graph: &HashMap>, 373 | start: &HashSet, 374 | ) -> HashSet { 375 | let mut reachable: HashSet = start.clone(); 376 | let mut new_reachable: Vec = Vec::new(); 377 | loop { 378 | for name in reachable.iter() { 379 | for new_name in &call_graph[name] { 380 | if !reachable.contains(new_name) { 381 | new_reachable.push(*new_name); 382 | } 383 | } 384 | } 385 | if new_reachable.is_empty() { 386 | return reachable; 387 | } else { 388 | while let Some(new_name) = new_reachable.pop() { 389 | reachable.insert(new_name); 390 | } 391 | } 392 | } 393 | } 394 | 395 | #[test] 396 | #[ignore = "just to see result"] 397 | fn optimize_test_const_fold() { 398 | let s = r#" 399 | module Test where 400 | func f(k): 401 | let x = @iadd(1, 2); 402 | record r = { x, x }; 403 | select x1 = r[0]; 404 | select x2 = r[1]; 405 | let y = @iadd(x1, x2); 406 | let z = @iadd(x1, y); 407 | return z; 408 | "#; 409 | let modl = super::parser::parse_module(s).unwrap(); 410 | println!("{}\n", modl); 411 | let expr = Optimizer::run(modl); 412 | let expr = Optimizer::run(expr); 413 | println!("{}\n", expr); 414 | } 415 | 416 | #[test] 417 | #[ignore = "just to see result"] 418 | fn optimize_test_dead_elim() { 419 | let s = r#" 420 | module Test where 421 | func f(k): 422 | let x = @iadd(a, b); 423 | let y = @iadd(x, c); 424 | let z = @iadd(x, y); 425 | return y; 426 | "#; 427 | let expr = super::parser::parse_module(s).unwrap(); 428 | println!("{}\n", expr); 429 | let expr = Optimizer::run(expr); 430 | println!("{}\n", expr); 431 | } 432 | 433 | #[test] 434 | #[ignore = "just to see result"] 435 | fn optimize_test_unused_func() { 436 | let s = r#" 437 | module Test where 438 | func test(k): 439 | decls 440 | func f(k1): 441 | call h(k1, 42); 442 | func g(k2, x2): 443 | call h(k2, 42); 444 | func h(k3, x3): 445 | jump k3(x3); 446 | in 447 | call f(k); 448 | end 449 | "#; 450 | let expr = super::parser::parse_module(s).unwrap(); 451 | println!("{}\n", expr); 452 | let expr = Optimizer::run(expr); 453 | println!("{}\n", expr); 454 | } 455 | --------------------------------------------------------------------------------