├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── src ├── bin │ └── f_ing.rs ├── lib.rs ├── rrd2014.rs └── rrd2014 │ ├── internal.rs │ ├── internal │ └── dynamic.rs │ └── parser.rs └── tests └── integration.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "modules" 3 | version = "0.1.0" 4 | authors = ["elpinal"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | colored = "1.7" 9 | failure = "0.1.3" 10 | structopt = "0.2" 11 | 12 | [dev-dependencies.cargo-husky] 13 | version = "1" 14 | default-features = false 15 | features = ["precommit-hook", "run-cargo-clippy", "run-cargo-fmt"] 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 El Pin Al 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modules 2 | 3 | This repository contains an interpreter of F-ing modules in Rust. 4 | 5 | ## Install 6 | 7 | Use nightly releases of Rust. 8 | 9 | ``` 10 | $ cargo install --git https://github.com/elpinal/modules-rs 11 | ``` 12 | 13 | ## Usage 14 | 15 | ``` 16 | $ f_ing 17 | f-ing 0.1.0 18 | F-ing modules. 19 | 20 | USAGE: 21 | f_ing 22 | 23 | FLAGS: 24 | -h, --help Prints help information 25 | -v, --version Prints version information 26 | 27 | SUBCOMMANDS: 28 | exec Executes a program. 29 | help Prints this message or the help of the given subcommand(s) 30 | parse Parses a program. 31 | typecheck Typechecks a program. 32 | typecheck-internal Translates a program into an internal program, and then typechecks it to ensure type 33 | soundness. 34 | ``` 35 | 36 | ## See also 37 | 38 | - [elpinal/modules](https://github.com/elpinal/modules) 39 | contains my previous implementation of F-ing modules in Haskell. 40 | 41 | ## Reference 42 | 43 | Andreas Rossberg, Claudio V. Russo and Derek Dreyer. 44 | F-ing modules. 45 | Journal of Functional Programming, 24(5), 2014. 46 | [PDF](https://people.mpi-sws.org/~rossberg/f-ing/f-ing-jfp.pdf). 47 | -------------------------------------------------------------------------------- /src/bin/f_ing.rs: -------------------------------------------------------------------------------- 1 | use structopt::StructOpt; 2 | 3 | use failure::format_err; 4 | use failure::Error; 5 | use failure::ResultExt; 6 | 7 | use colored::*; 8 | 9 | use modules::rrd2014; 10 | use modules::rrd2014::internal; 11 | use modules::rrd2014::internal::dynamic; 12 | use modules::rrd2014::parser; 13 | use modules::rrd2014::Module; 14 | 15 | macro_rules! exitln { 16 | ( $code:expr, $($x:expr),* ) => { 17 | { 18 | eprintln!($($x),*); 19 | std::process::exit($code); 20 | } 21 | } 22 | } 23 | 24 | #[derive(StructOpt, Debug)] 25 | #[structopt(name = "f-ing", author = "", version_short = "v")] 26 | /// F-ing modules. 27 | enum Opt { 28 | #[structopt(name = "parse")] 29 | /// Parses a program. 30 | Parse { 31 | /// Input filename 32 | #[structopt(name = "filename")] 33 | file: String, 34 | }, 35 | 36 | #[structopt(name = "typecheck")] 37 | /// Typechecks a program. 38 | Typecheck { 39 | /// Input filename 40 | #[structopt(name = "filename")] 41 | file: String, 42 | 43 | /// Output filename 44 | #[structopt(short = "o")] 45 | output: Option, 46 | }, 47 | 48 | #[structopt(name = "typecheck-internal")] 49 | /// Translates a program into an internal program, and then typechecks it to ensure type 50 | /// soundness. 51 | TypecheckInternal { 52 | /// Input filename 53 | #[structopt(name = "filename")] 54 | file: String, 55 | }, 56 | 57 | #[structopt(name = "exec")] 58 | /// Executes a program. 59 | Exec { 60 | /// Input filename 61 | #[structopt(name = "filename")] 62 | file: String, 63 | }, 64 | } 65 | 66 | fn main() { 67 | if let Err(e) = run(Opt::from_args()) { 68 | exitln!(1, "{}", e); 69 | } 70 | } 71 | 72 | fn run(opt: Opt) -> Result<(), Error> { 73 | match opt { 74 | Opt::Parse { file } => { 75 | println!("{:?}", parse(file)?); 76 | } 77 | Opt::Typecheck { file, output } => match elaborate(parse(file)?)? { 78 | (t, asig, _) => { 79 | println!("{}:", "signature".bright_cyan().bold()); 80 | println!("{:?}", asig); 81 | println!(); 82 | println!("{}:", "translated F\u{03c9} term".bright_cyan().bold()); 83 | println!("{:?}", t); 84 | if let Some(f) = output { 85 | std::fs::write(f, format!("{:#?}", t))?; 86 | } 87 | } 88 | }, 89 | Opt::TypecheckInternal { file } => match elaborate(parse(file)?)? { 90 | (t, asig, gtenv) => { 91 | let ty = internal::typecheck(&t, gtenv).with_context(|e| { 92 | format!( 93 | "{}:\n{}", 94 | "[bug(unsound)] internal type error".bright_red().bold(), 95 | e 96 | ) 97 | })?; 98 | let expect = asig.into(); 99 | if ty.equal(&expect) { 100 | println!("{}", "The translation is sound.".bright_green().bold()); 101 | println!("{}", "internal type:".bright_cyan().bold()); 102 | println!("{:?}", ty); 103 | } else { 104 | Err(format_err!( 105 | "{}:\ntype mismatch:\n{:?}\nand\n{:?}", 106 | "[bug] invariant violation".bright_red().bold(), 107 | ty, 108 | expect 109 | ))?; 110 | } 111 | } 112 | }, 113 | Opt::Exec { file } => match elaborate(parse(file)?)? { 114 | (t, asig, gtenv) => { 115 | let ty = internal::typecheck(&t, gtenv).with_context(|e| { 116 | format!( 117 | "{}:\n{}", 118 | "[bug(unsound)] internal type error".bright_red().bold(), 119 | e 120 | ) 121 | })?; 122 | let expect = asig.into(); 123 | if ty.equal(&expect) { 124 | let v = dynamic::reduce(t)?; 125 | println!("{}:", "result".bright_green().bold()); 126 | println!("{:?}", v); 127 | } else { 128 | Err(format_err!( 129 | "{}:\ntype mismatch:\n{:?}\nand\n{:?}", 130 | "[bug] invariant violation".bright_red().bold(), 131 | ty, 132 | expect 133 | ))?; 134 | } 135 | } 136 | }, 137 | } 138 | Ok(()) 139 | } 140 | 141 | fn parse

(file: P) -> Result 142 | where 143 | P: AsRef, 144 | { 145 | parser::parse_file(&file) 146 | } 147 | 148 | fn elaborate( 149 | m: Module, 150 | ) -> Result<(internal::Term, rrd2014::AbstractSig, Vec), Error> { 151 | Ok(rrd2014::elaborate(m) 152 | .with_context(|e| format!("{}:\n{}", "type error".bright_red().bold(), e))?) 153 | } 154 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Modules 2 | 3 | #![feature(bind_by_move_pattern_guards)] 4 | #![feature(never_type)] 5 | #![feature(try_from)] 6 | 7 | pub mod rrd2014; 8 | 9 | use failure::bail; 10 | use failure::Fallible; 11 | 12 | use rrd2014::internal; 13 | use rrd2014::internal::dynamic; 14 | use rrd2014::parser; 15 | 16 | pub fn exec(src: I) -> Fallible<()> 17 | where 18 | I: IntoIterator, 19 | { 20 | let t = typecheck(src)?; 21 | let _ = dynamic::reduce(t)?; 22 | Ok(()) 23 | } 24 | 25 | pub fn typecheck(src: I) -> Fallible 26 | where 27 | I: IntoIterator, 28 | { 29 | let m = parser::parse(src)?; 30 | let (t, asig, gtenv) = rrd2014::elaborate(m)?; 31 | let ty = internal::typecheck(&t, gtenv)?; 32 | let expected = asig.into(); 33 | if !ty.equal(&expected) { 34 | bail!("invariant violation"); 35 | } 36 | Ok(t) 37 | } 38 | -------------------------------------------------------------------------------- /src/rrd2014/internal.rs: -------------------------------------------------------------------------------- 1 | //! The internal language. 2 | 3 | use std::borrow::Cow; 4 | use std::collections::HashMap; 5 | use std::collections::HashSet; 6 | use std::convert::TryFrom; 7 | use std::hash::BuildHasher; 8 | use std::hash::Hash; 9 | use std::iter::FromIterator; 10 | 11 | use failure::Fail; 12 | 13 | use super::BinOp; 14 | use super::Purity; 15 | 16 | pub mod dynamic; 17 | 18 | #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 19 | pub struct Name(String); 20 | 21 | #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 22 | pub enum Label { 23 | Label(Name), 24 | } 25 | 26 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 27 | pub enum Variable { 28 | Variable(usize), 29 | Generated(usize), 30 | } 31 | 32 | use Variable::Variable as V; 33 | 34 | #[derive(Clone, Debug, PartialEq)] 35 | pub struct Record(HashMap); 36 | 37 | #[derive(Clone, Debug, PartialEq)] 38 | pub enum Kind { 39 | Mono, 40 | Fun(Box, Box), 41 | } 42 | 43 | #[derive(Clone, Debug, PartialEq)] 44 | pub enum Type { 45 | Var(Variable), 46 | Fun(Box, Box), 47 | Record(Record), 48 | 49 | /// A universal type. 50 | Forall(Kind, Box), 51 | 52 | /// An existential type. 53 | Some(Kind, Box), 54 | 55 | Abs(Kind, Box), 56 | App(Box, Box), 57 | Int, 58 | Bool, 59 | } 60 | 61 | #[derive(Clone, Debug, PartialEq)] 62 | pub enum Term { 63 | Var(Variable), 64 | Abs(Type, Box), 65 | App(Box, Box), 66 | Record(Record), 67 | 68 | /// A projection from a record via a label. 69 | Proj(Box, Label), 70 | 71 | /// A polymorphic function. 72 | Poly(Kind, Box), 73 | 74 | /// An instantiation. 75 | Inst(Box, Type), 76 | 77 | /// An existential introduction. 78 | /// `Pack(witness, t, ty)` represents *pack [`witness`, `t`] as `ty`*. 79 | Pack(Type, Box, Type), 80 | 81 | /// An existential elimination. 82 | Unpack(Box, Box), 83 | 84 | Int(isize), 85 | Bool(bool), 86 | If(Box, Box, Box), 87 | BinOp(BinOp, Box, Box), 88 | 89 | /// Just a syntax sugar for `App(Abs(ty, t2), t1)`, but convenient for debugging and it reduces 90 | /// the size of terms. 91 | Let(Box, Box), 92 | } 93 | 94 | #[derive(Debug, PartialEq)] 95 | pub struct Env { 96 | /// A type environment. 97 | /// Variable 0 denotes the last introduced type variable. 98 | tenv: Vec<(Kind, S)>, 99 | 100 | venv: Vec>, 101 | 102 | /// A type environment for generated variables. 103 | /// Variable 0 denotes the first introduced type variable. 104 | gtenv: Vec, 105 | 106 | /// A name-to-index map. 107 | nmap: HashMap, 108 | 109 | /// A counter to generate fresh type variables for type inference. 110 | n: usize, 111 | } 112 | 113 | pub struct EnvState(HashMap); 114 | 115 | #[derive(Clone, Debug, PartialEq)] 116 | pub struct EnvAbs { 117 | /// A type environment. 118 | /// Variable 0 denotes the last introduced type variable. 119 | tenv: Vec<(Kind, S)>, 120 | 121 | venv: Vec>, 122 | } 123 | 124 | #[derive(Clone, Debug, Default, PartialEq)] 125 | pub struct Context<'a> { 126 | tenv: Vec>, 127 | venv: Vec>, 128 | gtenv: Vec, 129 | } 130 | 131 | #[derive(Debug, Fail, PartialEq)] 132 | pub enum KindError { 133 | #[fail(display = "kind mismatch: {:?} and {:?}", _0, _1)] 134 | KindMismatch(Kind, Kind), 135 | 136 | #[fail(display = "not function kind: {:?}", _0)] 137 | NotFunction(Kind), 138 | 139 | #[fail(display = "type {:?} does not have mono kind: {}", _0, _1)] 140 | NotMono(Type, NotMonoError), 141 | 142 | #[fail(display = "label {:?} in record: {}", _0, _1)] 143 | Record(Label, Box), 144 | 145 | #[fail(display = "environment error: {}", _0)] 146 | Env(EnvError), 147 | 148 | #[fail(display = "function's domain type {:?}: {}", _0, _1)] 149 | Domain(Type, NotMonoError), 150 | 151 | #[fail(display = "function's codomain type {:?}: {}", _0, _1)] 152 | Codomain(Type, NotMonoError), 153 | } 154 | 155 | #[derive(Debug, Fail, PartialEq)] 156 | pub enum TypeError { 157 | #[fail(display = "type mismatch: {:?} and {:?}", _0, _1)] 158 | TypeMismatch(Type, Type), 159 | 160 | #[fail(display = "not function type: {:?}", _0)] 161 | NotFunction(Type), 162 | 163 | #[fail( 164 | display = "missing label {:?} in {:?}, which is the type of {:?}", 165 | _2, _1, _0 166 | )] 167 | MissingLabel(Term, Record, Label), 168 | 169 | #[fail(display = "not record type: {:?}", _0)] 170 | NotRecord(Type), 171 | 172 | #[fail(display = "not universal type: {:?}", _0)] 173 | NotForall(Type), 174 | 175 | #[fail(display = "not existential type: {:?}", _0)] 176 | NotSome(Type), 177 | 178 | #[fail(display = "not boolean type: {:?}", _0)] 179 | NotBool(Type), 180 | 181 | #[fail(display = "environment error: {}", _0)] 182 | Env(EnvError), 183 | 184 | #[fail(display = "kind error: {}", _0)] 185 | KindError(KindError), 186 | 187 | #[fail(display = "in application of {:?} to {:?}: {}", _0, _1, _2)] 188 | Application(Box, Box, Box), 189 | 190 | #[fail(display = "in packing [{:?}, {:?}] as {:?}: {}", _0, _1, _2, _3)] 191 | Pack(Box, Box, Box, Box), 192 | 193 | #[fail(display = "instantiation of {:?} with {:?}: {}", _0, _1, _2)] 194 | Inst(Box, Type, KindError), 195 | } 196 | 197 | #[derive(Clone, Debug, Default, PartialEq)] 198 | pub struct Subst(HashMap); 199 | 200 | pub trait Substitution { 201 | fn apply(&mut self, s: &Subst); 202 | } 203 | 204 | impl Default for Env { 205 | fn default() -> Self { 206 | Env { 207 | tenv: vec![], 208 | venv: vec![], 209 | gtenv: vec![], 210 | nmap: HashMap::new(), 211 | n: 0, 212 | } 213 | } 214 | } 215 | 216 | /// Free generated type variables. 217 | pub trait Fgtv { 218 | fn fgtv(&self) -> HashSet; 219 | } 220 | 221 | pub trait Shift { 222 | fn shift_above(&mut self, c: usize, d: isize); 223 | 224 | fn shift(&mut self, d: isize) { 225 | self.shift_above(0, d) 226 | } 227 | } 228 | 229 | impl Shift for Type { 230 | fn shift_above(&mut self, c: usize, d: isize) { 231 | let mut f = |c0, v: usize| { 232 | if c0 <= v { 233 | Ok(Type::Var(V(v).add(d))) 234 | } else { 235 | Ok(Type::Var(V(v))) 236 | } 237 | }; 238 | self.map_never_error(&mut f, c); 239 | } 240 | } 241 | 242 | impl Shift for Variable { 243 | fn shift_above(&mut self, c: usize, d: isize) { 244 | if let V(ref mut n) = *self { 245 | if c <= *n { 246 | *n = usize::try_from(isize::try_from(*n).unwrap() + d).unwrap(); 247 | } 248 | } 249 | } 250 | } 251 | 252 | impl Shift for Kind { 253 | fn shift_above(&mut self, _: usize, _: isize) {} 254 | } 255 | 256 | impl Shift for Record { 257 | fn shift_above(&mut self, c: usize, d: isize) { 258 | self.0.values_mut().for_each(|x| x.shift_above(c, d)) 259 | } 260 | } 261 | 262 | impl Shift for Term { 263 | fn shift_above(&mut self, c: usize, d: isize) { 264 | use Term::*; 265 | match *self { 266 | Var(_) | Int(_) | Bool(_) => (), 267 | Abs(ref mut ty, ref mut t) => { 268 | ty.shift_above(c, d); 269 | t.shift_above(c, d); 270 | } 271 | App(ref mut t1, ref mut t2) => { 272 | t1.shift_above(c, d); 273 | t2.shift_above(c, d); 274 | } 275 | Record(ref mut r) => r.shift_above(c, d), 276 | Proj(ref mut t, _) => t.shift_above(c, d), 277 | Poly(ref mut k, ref mut t) => { 278 | k.shift_above(c + 1, d); 279 | t.shift_above(c + 1, d); 280 | } 281 | Inst(ref mut t, ref mut ty) => { 282 | t.shift_above(c, d); 283 | ty.shift_above(c, d); 284 | } 285 | Pack(ref mut ty1, ref mut t, ref mut ty2) => { 286 | ty1.shift_above(c, d); 287 | t.shift_above(c, d); 288 | ty2.shift_above(c + 1, d); 289 | } 290 | Unpack(ref mut t1, ref mut t2) => { 291 | t1.shift_above(c, d); 292 | t2.shift_above(c + 1, d); 293 | } 294 | If(ref mut t1, ref mut t2, ref mut t3) => { 295 | t1.shift_above(c, d); 296 | t2.shift_above(c, d); 297 | t3.shift_above(c, d); 298 | } 299 | BinOp(_, ref mut t1, ref mut t2) => { 300 | t1.shift_above(c, d); 301 | t2.shift_above(c, d); 302 | } 303 | Let(ref mut t1, ref mut t2) => { 304 | t1.shift_above(c, d); 305 | t2.shift_above(c, d); 306 | } 307 | } 308 | } 309 | } 310 | 311 | impl Shift for Box { 312 | fn shift_above(&mut self, c: usize, d: isize) { 313 | (**self).shift_above(c, d) 314 | } 315 | } 316 | 317 | impl Shift for Option { 318 | fn shift_above(&mut self, c: usize, d: isize) { 319 | if let Some(x) = self.as_mut() { 320 | x.shift_above(c, d); 321 | } 322 | } 323 | } 324 | 325 | impl Shift for Vec { 326 | fn shift_above(&mut self, c: usize, d: isize) { 327 | self.iter_mut().for_each(|x| { 328 | x.shift_above(c, d); 329 | }); 330 | } 331 | } 332 | 333 | impl Shift for HashMap { 334 | fn shift_above(&mut self, c: usize, d: isize) { 335 | self.values_mut().for_each(|x| { 336 | x.shift_above(c, d); 337 | }); 338 | } 339 | } 340 | 341 | impl Substitution for Option { 342 | fn apply(&mut self, s: &Subst) { 343 | self.iter_mut().for_each(|x| x.apply(s)); 344 | } 345 | } 346 | 347 | impl Substitution for Vec { 348 | fn apply(&mut self, s: &Subst) { 349 | self.iter_mut().for_each(|x| x.apply(s)); 350 | } 351 | } 352 | 353 | impl Substitution for (S, T) { 354 | fn apply(&mut self, s: &Subst) { 355 | self.0.apply(s); 356 | self.1.apply(s); 357 | } 358 | } 359 | 360 | impl Substitution for HashMap { 361 | fn apply(&mut self, s: &Subst) { 362 | self.values_mut().for_each(|x| x.apply(s)); 363 | } 364 | } 365 | 366 | impl Substitution for Record { 367 | fn apply(&mut self, s: &Subst) { 368 | self.0.apply(s) 369 | } 370 | } 371 | 372 | impl Substitution for Kind { 373 | fn apply(&mut self, _: &Subst) {} 374 | } 375 | 376 | impl Substitution for Type { 377 | fn apply(&mut self, s: &Subst) { 378 | use Type::*; 379 | match *self { 380 | Var(ref mut v) => { 381 | if let Option::Some(ty) = s.0.get(v) { 382 | *self = ty.clone(); 383 | } 384 | } 385 | Fun(ref mut ty1, ref mut ty2) => { 386 | ty1.apply(s); 387 | ty2.apply(s); 388 | } 389 | Record(ref mut r) => r.apply(s), 390 | Forall(ref mut k, ref mut ty) => { 391 | let s = &s.clone().shift(1); 392 | k.apply(s); 393 | ty.apply(s); 394 | } 395 | Some(ref mut k, ref mut ty) => { 396 | let s = &s.clone().shift(1); 397 | k.apply(s); 398 | ty.apply(s); 399 | } 400 | Abs(ref mut k, ref mut ty) => { 401 | let s = &s.clone().shift(1); 402 | k.apply(s); 403 | ty.apply(s); 404 | } 405 | App(ref mut ty1, ref mut ty2) => { 406 | ty1.apply(s); 407 | ty2.apply(s); 408 | } 409 | Int | Bool => (), 410 | } 411 | } 412 | } 413 | 414 | impl Substitution for Term { 415 | fn apply(&mut self, s: &Subst) { 416 | use Term::*; 417 | match *self { 418 | Var(_) | Int(_) | Bool(_) => (), 419 | Abs(ref mut ty, ref mut t) => { 420 | ty.apply(s); 421 | t.apply(s); 422 | } 423 | App(ref mut t1, ref mut t2) => { 424 | t1.apply(s); 425 | t2.apply(s); 426 | } 427 | Record(ref mut r) => r.apply(s), 428 | Proj(ref mut t, _) => t.apply(s), 429 | Poly(ref mut k, ref mut t) => { 430 | let s = &s.clone().shift(1); 431 | k.apply(s); 432 | t.apply(s); 433 | } 434 | Inst(ref mut t, ref mut ty) => { 435 | t.apply(s); 436 | ty.apply(s); 437 | } 438 | Pack(ref mut ty1, ref mut t, ref mut ty2) => { 439 | ty1.apply(s); 440 | t.apply(s); 441 | let s = &s.clone().shift(1); 442 | ty2.apply(s); 443 | } 444 | Unpack(ref mut t1, ref mut t2) => { 445 | t1.apply(s); 446 | let s = &s.clone().shift(1); 447 | t2.apply(s); 448 | } 449 | If(ref mut t1, ref mut t2, ref mut t3) => { 450 | t1.apply(s); 451 | t2.apply(s); 452 | t3.apply(s); 453 | } 454 | BinOp(_, ref mut t1, ref mut t2) => { 455 | t1.apply(s); 456 | t2.apply(s); 457 | } 458 | Let(ref mut t1, ref mut t2) => { 459 | t1.apply(s); 460 | t2.apply(s); 461 | } 462 | } 463 | } 464 | } 465 | 466 | impl Substitution for Subst { 467 | fn apply(&mut self, s: &Subst) { 468 | self.0.values_mut().for_each(|ty| ty.apply(s)); 469 | } 470 | } 471 | 472 | impl Substitution for Env { 473 | fn apply(&mut self, s: &Subst) { 474 | self.tenv.iter_mut().for_each(|p| p.0.apply(s)); 475 | self.venv.iter_mut().for_each(|x| x.apply(s)); 476 | } 477 | } 478 | 479 | impl Fgtv for Kind { 480 | fn fgtv(&self) -> HashSet { 481 | HashSet::default() 482 | } 483 | } 484 | 485 | impl Fgtv for Variable { 486 | fn fgtv(&self) -> HashSet { 487 | if let Variable::Generated(n) = *self { 488 | HashSet::from_iter(Some(n)) 489 | } else { 490 | HashSet::new() 491 | } 492 | } 493 | } 494 | 495 | impl Fgtv for Type { 496 | fn fgtv(&self) -> HashSet { 497 | use Type::*; 498 | match *self { 499 | Var(Variable::Generated(n)) => HashSet::from_iter(vec![n]), 500 | Var(_) | Int | Bool => HashSet::new(), 501 | Fun(ref ty1, ref ty2) => { 502 | let mut s = ty1.fgtv(); 503 | s.extend(ty2.fgtv()); 504 | s 505 | } 506 | Record(ref r) => r.0.values().flat_map(|ty| ty.fgtv()).collect(), 507 | App(ref ty1, ref ty2) => { 508 | let mut s = ty1.fgtv(); 509 | s.extend(ty2.fgtv()); 510 | s 511 | } 512 | Forall(ref k, ref ty) | Some(ref k, ref ty) => { 513 | let mut s = k.fgtv(); 514 | s.extend(ty.fgtv()); 515 | s 516 | } 517 | _ => unimplemented!("{:?}", self), 518 | } 519 | } 520 | } 521 | 522 | impl Fgtv for Env { 523 | fn fgtv(&self) -> HashSet { 524 | self.venv.iter().flat_map(|x| x.fgtv()).collect() 525 | } 526 | } 527 | 528 | impl Fgtv for Option { 529 | fn fgtv(&self) -> HashSet { 530 | match *self { 531 | Some(ref x) => x.fgtv(), 532 | None => HashSet::new(), 533 | } 534 | } 535 | } 536 | 537 | impl From for TypeError { 538 | fn from(e: EnvError) -> Self { 539 | TypeError::Env(e) 540 | } 541 | } 542 | 543 | impl From for TypeError { 544 | fn from(e: KindError) -> Self { 545 | TypeError::KindError(e) 546 | } 547 | } 548 | 549 | impl From for Type { 550 | fn from(st: super::SemanticSig) -> Self { 551 | use super::SemanticSig::*; 552 | match st { 553 | AtomicTerm(_, ty) => ty, 554 | AtomicType(mut ty, k) => { 555 | ty.shift(1); 556 | Type::forall( 557 | vec![Kind::fun(k, Kind::Mono)], 558 | Type::fun( 559 | Type::app(Type::var(0), ty.clone()), 560 | Type::app(Type::var(0), ty), 561 | ), 562 | ) 563 | } 564 | AtomicSig(asig) => { 565 | let ty = Type::from(asig); 566 | Type::fun(ty.clone(), ty) 567 | } 568 | StructureSig(m) => Type::Record( 569 | m.into_iter() 570 | .map(|(l, ssig)| (l, Type::from(ssig))) 571 | .collect(), 572 | ), 573 | FunctorSig(u) => u.into(), 574 | Applicative(u) => u.into(), 575 | } 576 | } 577 | } 578 | 579 | impl> From> for Type { 580 | fn from(ex: super::Existential) -> Self { 581 | Type::some( 582 | ex.0.qs.into_iter().rev().map(|p| p.0).collect::>(), 583 | ex.0.body.into(), 584 | ) 585 | } 586 | } 587 | 588 | impl> From> for Type { 589 | fn from(u: super::Universal) -> Self { 590 | Type::forall( 591 | u.0.qs.into_iter().rev().map(|p| p.0).collect::>(), 592 | u.0.body.into(), 593 | ) 594 | } 595 | } 596 | 597 | impl From for Type { 598 | fn from(f: super::Fun) -> Self { 599 | Type::fun(f.0.into(), f.1.into()) 600 | } 601 | } 602 | 603 | impl From for Type { 604 | fn from(f: super::Applicative) -> Self { 605 | Type::fun(f.0.into(), f.1.into()) 606 | } 607 | } 608 | 609 | impl> From> for Type { 610 | fn from(x: Box) -> Self { 611 | (*x).into() 612 | } 613 | } 614 | 615 | impl From for Term { 616 | fn from(st: super::SemanticTerm) -> Self { 617 | use super::SemanticTerm as ST; 618 | match st { 619 | ST::Term(t) => t, 620 | ST::Type(mut ty, k) => { 621 | ty.shift(1); 622 | Term::poly( 623 | vec![Kind::fun(k, Kind::Mono)], 624 | Term::abs(Type::app(Type::var(0), ty), Term::var(0)), 625 | ) 626 | } 627 | ST::Sig(asig) => Term::abs(Type::from(asig), Term::var(0)), 628 | } 629 | } 630 | } 631 | 632 | impl From for Label { 633 | fn from(id: super::Ident) -> Self { 634 | Label::Label(Name::from(id)) 635 | } 636 | } 637 | 638 | impl<'a> From<&'a super::Ident> for Label { 639 | fn from(id: &'a super::Ident) -> Self { 640 | Label::Label(Name::from(id.clone())) 641 | } 642 | } 643 | 644 | impl From for Label { 645 | fn from(name: Name) -> Self { 646 | Label::Label(name) 647 | } 648 | } 649 | 650 | impl<'a> From<&'a str> for Label { 651 | fn from(s: &str) -> Self { 652 | Label::Label(Name::from(s)) 653 | } 654 | } 655 | 656 | impl<'a> From<&'a str> for Name { 657 | fn from(s: &str) -> Self { 658 | Name(s.to_string()) 659 | } 660 | } 661 | 662 | impl From for Name { 663 | fn from(s: String) -> Self { 664 | Name(s) 665 | } 666 | } 667 | 668 | impl From for Name { 669 | fn from(id: super::Ident) -> Self { 670 | id.0 671 | } 672 | } 673 | 674 | impl<'a> From<&'a super::Ident> for &'a Name { 675 | fn from(id: &'a super::Ident) -> Self { 676 | &id.0 677 | } 678 | } 679 | 680 | impl TryFrom

(filename: P) -> Fallible 918 | where 919 | P: AsRef, 920 | { 921 | use std::fs::File; 922 | let mut s = String::new(); 923 | let mut f = File::open(filename)?; 924 | f.read_to_string(&mut s)?; 925 | parse(s.chars()) 926 | } 927 | 928 | #[cfg(test)] 929 | mod tests { 930 | #![warn(dead_code)] 931 | 932 | use super::*; 933 | 934 | #[test] 935 | fn lambda() { 936 | let mut l = Lexer::new(vec!['λ']); 937 | assert_eq!( 938 | l.lex(), 939 | Ok(Token { 940 | kind: TokenKind::Lambda, 941 | pos: Default::default(), 942 | }) 943 | ); 944 | } 945 | 946 | #[test] 947 | fn int_literal() { 948 | let mut l = Lexer::new(vec!['0', '1', '_', '9']); 949 | assert_eq!( 950 | l.lex(), 951 | Ok(Token { 952 | kind: TokenKind::IntLit(19), 953 | pos: Default::default(), 954 | }) 955 | ); 956 | } 957 | 958 | #[test] 959 | fn lexer() { 960 | let mut l = Lexer::new(vec!['s', 't', 'r', 'u', 'c', 't', ' ', 'e', 'n', 'd']); 961 | 962 | assert_eq!( 963 | l.lex(), 964 | Ok(Token { 965 | kind: TokenKind::Struct, 966 | pos: Default::default(), 967 | }) 968 | ); 969 | 970 | assert_eq!( 971 | l.lex(), 972 | Ok(Token { 973 | kind: TokenKind::End, 974 | pos: Position::new(1, 8) 975 | }) 976 | ); 977 | } 978 | 979 | #[test] 980 | fn parse_expr() { 981 | let mut p = Parser::new(vec![Token { 982 | kind: TokenKind::IntLit(33), 983 | pos: Default::default(), 984 | }]); 985 | assert_eq!(p.expr_atom(), Ok(Expr::Int(33))); 986 | 987 | let mut p = Parser::new(vec![Token { 988 | kind: TokenKind::IntLit(33), 989 | pos: Default::default(), 990 | }]); 991 | assert_eq!(p.expr(), Ok(Expr::Int(33))); 992 | 993 | let mut p = Parser::new(vec![Token { 994 | kind: TokenKind::ident("a"), 995 | pos: Default::default(), 996 | }]); 997 | assert_eq!(p.expr(), Ok(Expr::path(Module::Ident(Ident::from("a"))))); 998 | 999 | let mut p = Parser::new(vec![ 1000 | Token { 1001 | kind: TokenKind::ident("a"), 1002 | pos: Default::default(), 1003 | }, 1004 | Token { 1005 | kind: TokenKind::ident("a"), 1006 | pos: Default::default(), 1007 | }, 1008 | ]); 1009 | assert_eq!( 1010 | p.expr(), 1011 | Ok(Expr::app( 1012 | Expr::path(Module::Ident(Ident::from("a"))), 1013 | Expr::path(Module::Ident(Ident::from("a"))) 1014 | )) 1015 | ); 1016 | } 1017 | 1018 | #[test] 1019 | fn parse_type() { 1020 | let mut p = Parser::new(vec![Token { 1021 | kind: TokenKind::Int, 1022 | pos: Default::default(), 1023 | }]); 1024 | assert_eq!(p.type_atom(), Ok(Type::Int)); 1025 | 1026 | let mut p = Parser::new(vec![Token { 1027 | kind: TokenKind::Int, 1028 | pos: Default::default(), 1029 | }]); 1030 | assert_eq!(p.r#type(), Ok(Type::Int)); 1031 | 1032 | let mut p = Parser::new(vec![Token { 1033 | kind: TokenKind::Ident("t".to_string()), 1034 | pos: Default::default(), 1035 | }]); 1036 | assert_eq!(p.r#type(), Ok(Type::path(Module::Ident(Ident::from("t"))))); 1037 | } 1038 | 1039 | #[test] 1040 | fn parse_signature() { 1041 | let mut p = Parser::new(vec![ 1042 | Token { 1043 | kind: TokenKind::Sig, 1044 | pos: Default::default(), 1045 | }, 1046 | Token { 1047 | kind: TokenKind::Type, 1048 | pos: Default::default(), 1049 | }, 1050 | Token { 1051 | kind: TokenKind::Ident("x".to_string()), 1052 | pos: Default::default(), 1053 | }, 1054 | Token { 1055 | kind: TokenKind::Equal, 1056 | pos: Default::default(), 1057 | }, 1058 | Token { 1059 | kind: TokenKind::Ident("t".to_string()), 1060 | pos: Default::default(), 1061 | }, 1062 | Token { 1063 | kind: TokenKind::End, 1064 | pos: Default::default(), 1065 | }, 1066 | ]); 1067 | assert_eq!( 1068 | p.signature(), 1069 | Ok(Sig::Seq(vec![Decl::ManType( 1070 | Ident::from("x"), 1071 | Type::path(Module::Ident(Ident::from("t"))) 1072 | )])) 1073 | ); 1074 | } 1075 | 1076 | #[test] 1077 | fn parse_decl() { 1078 | let mut p = Parser::new(vec![ 1079 | Token { 1080 | kind: TokenKind::Type, 1081 | pos: Default::default(), 1082 | }, 1083 | Token { 1084 | kind: TokenKind::Ident("x".to_string()), 1085 | pos: Default::default(), 1086 | }, 1087 | Token { 1088 | kind: TokenKind::Equal, 1089 | pos: Default::default(), 1090 | }, 1091 | Token { 1092 | kind: TokenKind::Ident("t".to_string()), 1093 | pos: Default::default(), 1094 | }, 1095 | ]); 1096 | assert_eq!( 1097 | p.decl(), 1098 | Ok(Decl::ManType( 1099 | Ident::from("x"), 1100 | Type::path(Module::Ident(Ident::from("t"))) 1101 | )) 1102 | ); 1103 | } 1104 | 1105 | #[test] 1106 | fn parse_binding() { 1107 | let mut p = Parser::new(vec![ 1108 | Token { 1109 | kind: TokenKind::Type, 1110 | pos: Default::default(), 1111 | }, 1112 | Token { 1113 | kind: TokenKind::Ident("t".to_string()), 1114 | pos: Default::default(), 1115 | }, 1116 | Token { 1117 | kind: TokenKind::Equal, 1118 | pos: Default::default(), 1119 | }, 1120 | Token { 1121 | kind: TokenKind::Int, 1122 | pos: Default::default(), 1123 | }, 1124 | ]); 1125 | assert_eq!(p.binding(), Ok(Binding::Type(Ident::from("t"), Type::Int))); 1126 | 1127 | let mut p = Parser::new(vec![ 1128 | Token { 1129 | kind: TokenKind::Val, 1130 | pos: Default::default(), 1131 | }, 1132 | Token { 1133 | kind: TokenKind::Ident("x".to_string()), 1134 | pos: Default::default(), 1135 | }, 1136 | Token { 1137 | kind: TokenKind::Equal, 1138 | pos: Default::default(), 1139 | }, 1140 | Token { 1141 | kind: TokenKind::IntLit(3), 1142 | pos: Default::default(), 1143 | }, 1144 | ]); 1145 | assert_eq!( 1146 | p.binding(), 1147 | Ok(Binding::Val(Ident::from("x"), Expr::Int(3))) 1148 | ); 1149 | 1150 | let mut p = Parser::new(vec![ 1151 | Token { 1152 | kind: TokenKind::Type, 1153 | pos: Default::default(), 1154 | }, 1155 | Token { 1156 | kind: TokenKind::Ident("x".to_string()), 1157 | pos: Default::default(), 1158 | }, 1159 | Token { 1160 | kind: TokenKind::Equal, 1161 | pos: Default::default(), 1162 | }, 1163 | Token { 1164 | kind: TokenKind::Ident("t".to_string()), 1165 | pos: Default::default(), 1166 | }, 1167 | ]); 1168 | assert_eq!( 1169 | p.binding(), 1170 | Ok(Binding::Type( 1171 | Ident::from("x"), 1172 | Type::path(Module::Ident(Ident::from("t"))) 1173 | )) 1174 | ); 1175 | } 1176 | 1177 | #[test] 1178 | fn parse_module() { 1179 | let mut p = Parser::new(vec![]); 1180 | assert_eq!(p.module(), Err(ParseError::UnexpectedEOF)); 1181 | 1182 | let mut p = Parser::new(vec![ 1183 | Token { 1184 | kind: TokenKind::Struct, 1185 | pos: Default::default(), 1186 | }, 1187 | Token { 1188 | kind: TokenKind::End, 1189 | pos: Default::default(), 1190 | }, 1191 | ]); 1192 | assert_eq!(p.module(), Ok(Module::Seq(vec![]))); 1193 | 1194 | let mut p = Parser::new(vec![ 1195 | Token { 1196 | kind: TokenKind::Struct, 1197 | pos: Default::default(), 1198 | }, 1199 | Token { 1200 | kind: TokenKind::Type, 1201 | pos: Default::default(), 1202 | }, 1203 | Token { 1204 | kind: TokenKind::Ident("t".to_string()), 1205 | pos: Default::default(), 1206 | }, 1207 | Token { 1208 | kind: TokenKind::Equal, 1209 | pos: Default::default(), 1210 | }, 1211 | Token { 1212 | kind: TokenKind::Int, 1213 | pos: Default::default(), 1214 | }, 1215 | Token { 1216 | kind: TokenKind::End, 1217 | pos: Default::default(), 1218 | }, 1219 | ]); 1220 | assert_eq!( 1221 | p.module(), 1222 | Ok(Module::Seq(vec![Binding::Type( 1223 | Ident::from("t"), 1224 | Type::Int 1225 | )])) 1226 | ); 1227 | } 1228 | } 1229 | -------------------------------------------------------------------------------- /tests/integration.rs: -------------------------------------------------------------------------------- 1 | use modules::exec; 2 | use modules::typecheck; 3 | 4 | macro_rules! assert_exec { 5 | ($s:expr) => {{ 6 | let r = exec($s.chars()); 7 | assert!(r.is_ok(), "{:?}", r.unwrap_err()); 8 | }}; 9 | } 10 | 11 | macro_rules! assert_typecheck { 12 | ($s:expr) => {{ 13 | let r = typecheck($s.chars()); 14 | assert!(r.is_ok(), "{:?}", r.unwrap_err()); 15 | }}; 16 | } 17 | 18 | #[test] 19 | fn test_execution() { 20 | assert_exec!("struct end"); 21 | assert_exec!("struct val x = 1 end"); 22 | 23 | assert_exec!( 24 | "struct 25 | val x = 1 26 | val y = 1 27 | end" 28 | ); 29 | 30 | assert_exec!( 31 | "struct 32 | module M = struct end 33 | 34 | module W = struct 35 | val x = 1 36 | end 37 | end" 38 | ); 39 | 40 | assert_exec!( 41 | "struct 42 | val a = 1 43 | val b = 1 44 | val c = 1 45 | end" 46 | ); 47 | 48 | assert_exec!( 49 | "struct 50 | val x = 20 51 | 52 | module W = struct 53 | val y = 40 54 | val f = λa.a 55 | end 56 | end" 57 | ); 58 | 59 | assert_exec!( 60 | "struct 61 | module M = fun X : sig end => 62 | ( struct 63 | module M = struct type t = int end 64 | end 65 | ).M 66 | 67 | module E = struct end 68 | 69 | type t = (M E).t 70 | type s = (M E).t 71 | 72 | module W = struct 73 | val x = λa.a 74 | val f = λa.a 75 | end 76 | end" 77 | ); 78 | } 79 | 80 | #[test] 81 | fn test_typecheck() { 82 | assert_typecheck!("struct end"); 83 | assert_typecheck!("struct val x = 1 end"); 84 | 85 | assert_typecheck!( 86 | "struct 87 | val x = 1 88 | val y = 1 89 | end" 90 | ); 91 | 92 | assert_typecheck!( 93 | "struct 94 | module M = fun X : sig end => 95 | ( struct 96 | module M = struct type t = int end 97 | end 98 | ).M 99 | 100 | module E = struct end 101 | 102 | type t = (M E).t 103 | type s = (M E).t 104 | 105 | module W = struct 106 | val x = λa.a 107 | val f = λa.a 108 | end 109 | 110 | module Y = W :> sig 111 | val x : t -> s 112 | val f : s -> t 113 | end 114 | end" 115 | ); 116 | } 117 | --------------------------------------------------------------------------------