Use miette for reporting errors

This gives us errors with annotated context like this:

```
Error:
  × type error: Unknown variable 'x'
    ╭─[isle_examples/let.isle:24:1]
 24 │   (Lower (B.B z))
 25 │   (A.Add x y))
    ·          ┬
    ·          ╰── Unknown variable 'x'
    ╰────
```
This commit is contained in:
Nick Fitzgerald
2021-09-28 14:51:02 -07:00
committed by Chris Fallin
parent 38da2cee3e
commit 6ffb02d9f6
10 changed files with 415 additions and 68 deletions

View File

@@ -2,6 +2,30 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "addr2line"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@@ -22,12 +46,39 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "backtrace"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@@ -44,7 +95,7 @@ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"strsim", "strsim",
"textwrap", "textwrap 0.11.0",
"unicode-width", "unicode-width",
"vec_map", "vec_map",
] ]
@@ -58,6 +109,12 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "gimli"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.19"
@@ -67,11 +124,18 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
[[package]] [[package]]
name = "isle" name = "isle"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"log", "log",
"miette",
"thiserror", "thiserror",
] ]
@@ -83,6 +147,7 @@ dependencies = [
"env_logger", "env_logger",
"isle", "isle",
"log", "log",
"miette",
] ]
[[package]] [[package]]
@@ -100,6 +165,73 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "miette"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "024831248cacc3305f5bb33d9daf9df54d6d95bf462c58f388845a17388c47fe"
dependencies = [
"atty",
"backtrace",
"miette-derive",
"once_cell",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
"term_size",
"textwrap 0.14.2",
"thiserror",
]
[[package]]
name = "miette-derive"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "074acd9c89172a516def5d82b8d90fb724fecba9dcae6fcdd88a75689601349f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "miniz_oxide"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "object"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "owo-colors"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a61765925aec40abdb23812a3a1a01fafc6ffb9da22768b2ce665a9e84e527c"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.29" version = "1.0.29"
@@ -118,12 +250,69 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "smawk"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "supports-color"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32f5b0f9e689dd52e27228469dd68b7416b60d75b7571ae9060a5f4c50048fee"
dependencies = [
"atty",
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406"
dependencies = [
"atty",
]
[[package]]
name = "supports-unicode"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2"
dependencies = [
"atty",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.77" version = "1.0.77"
@@ -135,6 +324,16 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "term_size"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.11.0"
@@ -144,6 +343,17 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.29" version = "1.0.29"
@@ -164,6 +374,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "unicode-linebreak"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.8" version = "0.1.8"

View File

@@ -7,4 +7,5 @@ license = "Apache-2.0 WITH LLVM-exception"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
miette = "3.0.0"
thiserror = "1.0.29" thiserror = "1.0.29"

View File

@@ -3,12 +3,14 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use crate::lexer::Pos; use crate::lexer::Pos;
use std::sync::Arc;
/// The parsed form of an ISLE file. /// The parsed form of an ISLE file.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct Defs { pub struct Defs {
pub defs: Vec<Def>, pub defs: Vec<Def>,
pub filenames: Vec<String>, pub filenames: Vec<Arc<str>>,
pub file_texts: Vec<Arc<str>>,
} }
/// One toplevel form in an ISLE file. /// One toplevel form in an ISLE file.

View File

@@ -1,10 +1,10 @@
//! Compilation process, from AST to Sema to Sequences of Insts. //! Compilation process, from AST to Sema to Sequences of Insts.
use crate::error::Error; use crate::error::Result;
use crate::{ast, codegen, sema}; use crate::{ast, codegen, sema};
/// Compile the given AST definitions into Rust source code. /// Compile the given AST definitions into Rust source code.
pub fn compile(defs: &ast::Defs) -> Result<String, Vec<Error>> { pub fn compile(defs: &ast::Defs) -> Result<String> {
let mut typeenv = sema::TypeEnv::from_ast(defs)?; let mut typeenv = sema::TypeEnv::from_ast(defs)?;
let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?; let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?;
Ok(codegen::codegen(&typeenv, &termenv)) Ok(codegen::codegen(&typeenv, &termenv))

View File

@@ -1,26 +1,56 @@
//! Error types. //! Error types.
use miette::{Diagnostic, SourceCode, SourceSpan};
use std::sync::Arc; use std::sync::Arc;
use crate::lexer::Pos; /// Either `Ok(T)` or `Err(isle::Error)`.
pub type Result<T> = std::result::Result<T, Error>;
/// Errors produced by ISLE. /// Errors produced by ISLE.
#[derive(thiserror::Error, Clone, Debug)] #[derive(thiserror::Error, Diagnostic, Clone, Debug)]
pub enum Error { pub enum Error {
/// An I/O error. /// An I/O error.
#[error(transparent)] #[error(transparent)]
IoError(Arc<std::io::Error>), IoError(Arc<std::io::Error>),
/// The input ISLE source has an error. /// The input ISLE source has a parse error.
#[error("{}:{}:{}: {}", .filename, .pos.line, .pos.col, .msg)] #[error("parse error: {msg}")]
CompileError { #[diagnostic()]
ParseError {
/// The error message. /// The error message.
msg: String, msg: String,
/// The ISLE source filename where the error occurs.
filename: String, /// The input ISLE source.
/// The position within the file that the error occurs at. #[source_code]
pos: Pos, src: Source,
/// The location of the parse error.
#[label("{msg}")]
span: SourceSpan,
}, },
/// The input ISLE source has a type error.
#[error("type error: {msg}")]
#[diagnostic()]
TypeError {
/// The error message.
msg: String,
/// The input ISLE source.
#[source_code]
src: Source,
/// The location of the type error.
#[label("{msg}")]
span: SourceSpan,
},
/// Multiple errors.
#[error("Found {} errors:\n\n{}",
self.unwrap_errors().len(),
DisplayErrors(self.unwrap_errors()))]
#[diagnostic()]
Errors(#[related] Vec<Error>),
} }
impl From<std::io::Error> for Error { impl From<std::io::Error> for Error {
@@ -28,3 +58,81 @@ impl From<std::io::Error> for Error {
Error::IoError(Arc::new(e)) Error::IoError(Arc::new(e))
} }
} }
impl From<Vec<Error>> for Error {
fn from(es: Vec<Error>) -> Self {
Error::Errors(es)
}
}
impl Error {
fn unwrap_errors(&self) -> &[Error] {
match self {
Error::Errors(e) => e,
_ => panic!("`isle::Error::unwrap_errors` on non-`isle::Error::Errors`"),
}
}
}
struct DisplayErrors<'a>(&'a [Error]);
impl std::fmt::Display for DisplayErrors<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for e in self.0 {
writeln!(f, "{}", e)?;
}
Ok(())
}
}
/// A source file and its contents.
#[derive(Clone)]
pub struct Source {
name: Arc<str>,
text: Arc<str>,
}
impl std::fmt::Debug for Source {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Source")
.field("name", &self.name)
.field("source", &"<redacted>");
Ok(())
}
}
impl Source {
pub(crate) fn new(name: Arc<str>, text: Arc<str>) -> Self {
Self { name, text }
}
/// Get this source's file name.
pub fn name(&self) -> &Arc<str> {
&self.name
}
/// Get this source's text contents.
pub fn text(&self) -> &Arc<str> {
&self.name
}
}
impl SourceCode for Source {
fn read_span<'a>(
&'a self,
span: &SourceSpan,
context_lines_before: usize,
context_lines_after: usize,
) -> std::result::Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
let contents = self
.text
.read_span(span, context_lines_before, context_lines_after)?;
Ok(Box::new(miette::MietteSpanContents::new_named(
self.name.to_string(),
contents.data(),
contents.span().clone(),
contents.line(),
contents.column(),
contents.line_count(),
)))
}
}

View File

@@ -1,7 +1,8 @@
//! Lexer for the ISLE language. //! Lexer for the ISLE language.
use crate::error::Error; use crate::error::Result;
use std::borrow::Cow; use std::borrow::Cow;
use std::sync::Arc;
/// The lexer. /// The lexer.
/// ///
@@ -11,7 +12,13 @@ pub struct Lexer<'a> {
/// Arena of filenames from the input source. /// Arena of filenames from the input source.
/// ///
/// Indexed via `Pos::file`. /// Indexed via `Pos::file`.
pub filenames: Vec<String>, pub filenames: Vec<Arc<str>>,
/// Arena of file source texts.
///
/// Indexed via `Pos::file`.
pub file_texts: Vec<Arc<str>>,
file_starts: Vec<usize>, file_starts: Vec<usize>,
buf: Cow<'a, [u8]>, buf: Cow<'a, [u8]>,
pos: Pos, pos: Pos,
@@ -36,11 +43,11 @@ pub struct Pos {
impl Pos { impl Pos {
/// Print this source position as `file.isle:12:34`. /// Print this source position as `file.isle:12:34`.
pub fn pretty_print(&self, filenames: &[String]) -> String { pub fn pretty_print(&self, filenames: &[Arc<str>]) -> String {
format!("{}:{}:{}", filenames[self.file], self.line, self.col) format!("{}:{}:{}", filenames[self.file], self.line, self.col)
} }
/// Print this source position as `file.isle line 12`. /// Print this source position as `file.isle line 12`.
pub fn pretty_print_line(&self, filenames: &[String]) -> String { pub fn pretty_print_line(&self, filenames: &[Arc<str>]) -> String {
format!("{} line {}", filenames[self.file], self.line) format!("{} line {}", filenames[self.file], self.line)
} }
} }
@@ -66,7 +73,8 @@ impl<'a> Lexer<'a> {
/// Create a new lexer for the given source contents and filename. /// Create a new lexer for the given source contents and filename.
pub fn from_str(s: &'a str, filename: &'a str) -> Lexer<'a> { pub fn from_str(s: &'a str, filename: &'a str) -> Lexer<'a> {
let mut l = Lexer { let mut l = Lexer {
filenames: vec![filename.to_string()], filenames: vec![filename.into()],
file_texts: vec![s.into()],
file_starts: vec![0], file_starts: vec![0],
buf: Cow::Borrowed(s.as_bytes()), buf: Cow::Borrowed(s.as_bytes()),
pos: Pos { pos: Pos {
@@ -82,22 +90,27 @@ impl<'a> Lexer<'a> {
} }
/// Create a new lexer from the given files. /// Create a new lexer from the given files.
pub fn from_files(filenames: Vec<String>) -> Result<Lexer<'a>, Error> { pub fn from_files<S>(filenames: impl IntoIterator<Item = S>) -> Result<Lexer<'a>>
where
S: AsRef<str>,
{
let filenames: Vec<Arc<str>> = filenames.into_iter().map(|f| f.as_ref().into()).collect();
assert!(!filenames.is_empty()); assert!(!filenames.is_empty());
let file_contents: Vec<String> = filenames
let file_contents: Vec<Arc<str>> = filenames
.iter() .iter()
.map(|f| { .map(|f| {
use std::io::Read; use std::io::Read;
let mut f = std::fs::File::open(f)?; let mut f = std::fs::File::open(&**f)?;
let mut s = String::new(); let mut s = String::new();
f.read_to_string(&mut s)?; f.read_to_string(&mut s)?;
Ok(s) Ok(s.into())
}) })
.collect::<Result<Vec<String>, Error>>()?; .collect::<Result<_>>()?;
let mut file_starts = vec![]; let mut file_starts = vec![];
let mut buf = String::new(); let mut buf = String::new();
for file in file_contents { for file in &file_contents {
file_starts.push(buf.len()); file_starts.push(buf.len());
buf += &file; buf += &file;
buf += "\n"; buf += "\n";
@@ -105,6 +118,7 @@ impl<'a> Lexer<'a> {
let mut l = Lexer { let mut l = Lexer {
filenames, filenames,
file_texts: file_contents,
buf: Cow::Owned(buf.into_bytes()), buf: Cow::Owned(buf.into_bytes()),
file_starts, file_starts,
pos: Pos { pos: Pos {

View File

@@ -22,10 +22,13 @@ impl<'a> Parser<'a> {
} }
fn error(&self, pos: Pos, msg: String) -> Error { fn error(&self, pos: Pos, msg: String) -> Error {
Error::CompileError { Error::ParseError {
filename: self.lexer.filenames[pos.file].clone(),
pos,
msg, msg,
src: Source::new(
self.lexer.filenames[pos.file].clone(),
self.lexer.file_texts[pos.file].clone(),
),
span: miette::SourceSpan::from((pos.offset, 1)),
} }
} }
@@ -120,6 +123,7 @@ impl<'a> Parser<'a> {
Ok(Defs { Ok(Defs {
defs, defs,
filenames: self.lexer.filenames.clone(), filenames: self.lexer.filenames.clone(),
file_texts: self.lexer.file_texts.clone(),
}) })
} }

View File

@@ -17,11 +17,7 @@ use crate::ast;
use crate::error::*; use crate::error::*;
use crate::lexer::Pos; use crate::lexer::Pos;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc;
/// Either `Ok(T)` or a one or more `Error`s.
///
/// This allows us to return multiple type errors at the same time, for example.
pub type SemaResult<T> = std::result::Result<T, Vec<Error>>;
declare_id!( declare_id!(
/// The id of an interned symbol. /// The id of an interned symbol.
@@ -60,7 +56,12 @@ pub struct TypeEnv {
/// Arena of input ISLE source filenames. /// Arena of input ISLE source filenames.
/// ///
/// We refer to these indirectly through the `Pos::file` indices. /// We refer to these indirectly through the `Pos::file` indices.
pub filenames: Vec<String>, pub filenames: Vec<Arc<str>>,
/// Arena of input ISLE source contents.
///
/// We refer to these indirectly through the `Pos::file` indices.
pub file_texts: Vec<Arc<str>>,
/// Arena of interned symbol names. /// Arena of interned symbol names.
/// ///
@@ -444,9 +445,10 @@ impl Expr {
impl TypeEnv { impl TypeEnv {
/// Construct the type environment from the AST. /// Construct the type environment from the AST.
pub fn from_ast(defs: &ast::Defs) -> SemaResult<TypeEnv> { pub fn from_ast(defs: &ast::Defs) -> Result<TypeEnv> {
let mut tyenv = TypeEnv { let mut tyenv = TypeEnv {
filenames: defs.filenames.clone(), filenames: defs.filenames.clone(),
file_texts: defs.file_texts.clone(),
syms: vec![], syms: vec![],
sym_map: HashMap::new(), sym_map: HashMap::new(),
types: vec![], types: vec![],
@@ -523,11 +525,11 @@ impl TypeEnv {
Ok(tyenv) Ok(tyenv)
} }
fn return_errors(&mut self) -> SemaResult<()> { fn return_errors(&mut self) -> Result<()> {
if self.errors.len() > 0 { match self.errors.len() {
Err(std::mem::take(&mut self.errors)) 0 => Ok(()),
} else { 1 => Err(self.errors.pop().unwrap()),
Ok(()) _ => Err(Error::Errors(std::mem::take(&mut self.errors))),
} }
} }
@@ -604,10 +606,13 @@ impl TypeEnv {
} }
fn error(&self, pos: Pos, msg: String) -> Error { fn error(&self, pos: Pos, msg: String) -> Error {
Error::CompileError { Error::TypeError {
filename: self.filenames[pos.file].clone(),
pos,
msg, msg,
src: Source::new(
self.filenames[pos.file].clone(),
self.file_texts[pos.file].clone(),
),
span: miette::SourceSpan::from((pos.offset, 1)),
} }
} }
@@ -647,7 +652,7 @@ struct BoundVar {
impl TermEnv { impl TermEnv {
/// Construct the term environment from the AST and the type environment. /// Construct the term environment from the AST and the type environment.
pub fn from_ast(tyenv: &mut TypeEnv, defs: &ast::Defs) -> SemaResult<TermEnv> { pub fn from_ast(tyenv: &mut TypeEnv, defs: &ast::Defs) -> Result<TermEnv> {
let mut env = TermEnv { let mut env = TermEnv {
terms: vec![], terms: vec![],
term_map: HashMap::new(), term_map: HashMap::new(),
@@ -689,7 +694,7 @@ impl TermEnv {
() ()
}) })
}) })
.collect::<Result<Vec<TypeId>, ()>>(); .collect::<std::result::Result<Vec<_>, _>>();
let arg_tys = match arg_tys { let arg_tys = match arg_tys {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => {

View File

@@ -10,3 +10,4 @@ log = "0.4"
isle = { version = "*", path = "../isle/" } isle = { version = "*", path = "../isle/" }
env_logger = { version = "0.8", default-features = false } env_logger = { version = "0.8", default-features = false }
clap = "2.33" clap = "2.33"
miette = { version = "3.0.0", features = ["fancy"] }

View File

@@ -1,10 +1,20 @@
use clap::{App, Arg}; use clap::{App, Arg};
use isle::{compile, lexer, parser};
use miette::{IntoDiagnostic, Result};
use isle::{error, lexer, parser, compile}; fn main() -> Result<()> {
fn main() -> Result<(), error::Error> {
let _ = env_logger::try_init(); let _ = env_logger::try_init();
let _ = miette::set_hook(Box::new(|_| {
Box::new(
miette::MietteHandlerOpts::new()
// `miette` mistakenly uses braille-optimized output for emacs's
// `M-x shell`.
.force_graphical(true)
.build(),
)
}));
let matches = App::new("isle") let matches = App::new("isle")
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.author("Chris Fallin <chris@cfallin.org>") .author("Chris Fallin <chris@cfallin.org>")
@@ -37,31 +47,14 @@ fn main() -> Result<(), error::Error> {
let lexer = lexer::Lexer::from_files(input_files)?; let lexer = lexer::Lexer::from_files(input_files)?;
let mut parser = parser::Parser::new(lexer); let mut parser = parser::Parser::new(lexer);
let defs = match parser.parse_defs() { let defs = parser.parse_defs()?;
Ok(defs) => defs, let code = compile::compile(&defs)?;
Err(error) => {
eprintln!("{}", error);
eprintln!("Failed to parse input.");
std::process::exit(1);
}
};
let code = match compile::compile(&defs) {
Ok(code) => code,
Err(errors) => {
for error in errors {
eprintln!("{}", error);
}
eprintln!("Failed to compile.");
std::process::exit(1);
}
};
{ {
use std::io::Write; use std::io::Write;
let mut f = std::fs::File::create(output_file)?; let mut f = std::fs::File::create(output_file).into_diagnostic()?;
writeln!(&mut f, "{}", code)?; writeln!(&mut f, "{}", code).into_diagnostic()?;
} }
Ok(()) Ok(())
} }