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:
committed by
Chris Fallin
parent
38da2cee3e
commit
6ffb02d9f6
221
cranelift/isle/Cargo.lock
generated
221
cranelift/isle/Cargo.lock
generated
@@ -2,6 +2,30 @@
|
||||
# It is not intended for manual editing.
|
||||
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]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
@@ -22,12 +46,39 @@ dependencies = [
|
||||
"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]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -44,7 +95,7 @@ dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"textwrap 0.11.0",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
@@ -58,6 +109,12 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
@@ -67,11 +124,18 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_ci"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
|
||||
|
||||
[[package]]
|
||||
name = "isle"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"miette",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -83,6 +147,7 @@ dependencies = [
|
||||
"env_logger",
|
||||
"isle",
|
||||
"log",
|
||||
"miette",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -100,6 +165,73 @@ dependencies = [
|
||||
"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]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
@@ -118,12 +250,69 @@ dependencies = [
|
||||
"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]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "syn"
|
||||
version = "1.0.77"
|
||||
@@ -135,6 +324,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
@@ -144,6 +343,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "thiserror"
|
||||
version = "1.0.29"
|
||||
@@ -164,6 +374,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-linebreak"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
|
||||
dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
|
||||
@@ -7,4 +7,5 @@ license = "Apache-2.0 WITH LLVM-exception"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
miette = "3.0.0"
|
||||
thiserror = "1.0.29"
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::lexer::Pos;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// The parsed form of an ISLE file.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Defs {
|
||||
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.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//! Compilation process, from AST to Sema to Sequences of Insts.
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::error::Result;
|
||||
use crate::{ast, codegen, sema};
|
||||
|
||||
/// 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 termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?;
|
||||
Ok(codegen::codegen(&typeenv, &termenv))
|
||||
|
||||
@@ -1,26 +1,56 @@
|
||||
//! Error types.
|
||||
|
||||
use miette::{Diagnostic, SourceCode, SourceSpan};
|
||||
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.
|
||||
#[derive(thiserror::Error, Clone, Debug)]
|
||||
#[derive(thiserror::Error, Diagnostic, Clone, Debug)]
|
||||
pub enum Error {
|
||||
/// An I/O error.
|
||||
#[error(transparent)]
|
||||
IoError(Arc<std::io::Error>),
|
||||
|
||||
/// The input ISLE source has an error.
|
||||
#[error("{}:{}:{}: {}", .filename, .pos.line, .pos.col, .msg)]
|
||||
CompileError {
|
||||
/// The input ISLE source has a parse error.
|
||||
#[error("parse error: {msg}")]
|
||||
#[diagnostic()]
|
||||
ParseError {
|
||||
/// The error message.
|
||||
msg: String,
|
||||
/// The ISLE source filename where the error occurs.
|
||||
filename: String,
|
||||
/// The position within the file that the error occurs at.
|
||||
pos: Pos,
|
||||
|
||||
/// The input ISLE source.
|
||||
#[source_code]
|
||||
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 {
|
||||
@@ -28,3 +58,81 @@ impl From<std::io::Error> for Error {
|
||||
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(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
//! Lexer for the ISLE language.
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::error::Result;
|
||||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// The lexer.
|
||||
///
|
||||
@@ -11,7 +12,13 @@ pub struct Lexer<'a> {
|
||||
/// Arena of filenames from the input source.
|
||||
///
|
||||
/// 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>,
|
||||
buf: Cow<'a, [u8]>,
|
||||
pos: Pos,
|
||||
@@ -36,11 +43,11 @@ pub struct Pos {
|
||||
|
||||
impl Pos {
|
||||
/// 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)
|
||||
}
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
@@ -66,7 +73,8 @@ impl<'a> Lexer<'a> {
|
||||
/// Create a new lexer for the given source contents and filename.
|
||||
pub fn from_str(s: &'a str, filename: &'a str) -> Lexer<'a> {
|
||||
let mut l = Lexer {
|
||||
filenames: vec![filename.to_string()],
|
||||
filenames: vec![filename.into()],
|
||||
file_texts: vec![s.into()],
|
||||
file_starts: vec![0],
|
||||
buf: Cow::Borrowed(s.as_bytes()),
|
||||
pos: Pos {
|
||||
@@ -82,22 +90,27 @@ impl<'a> Lexer<'a> {
|
||||
}
|
||||
|
||||
/// 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());
|
||||
let file_contents: Vec<String> = filenames
|
||||
|
||||
let file_contents: Vec<Arc<str>> = filenames
|
||||
.iter()
|
||||
.map(|f| {
|
||||
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();
|
||||
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 buf = String::new();
|
||||
for file in file_contents {
|
||||
for file in &file_contents {
|
||||
file_starts.push(buf.len());
|
||||
buf += &file;
|
||||
buf += "\n";
|
||||
@@ -105,6 +118,7 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
let mut l = Lexer {
|
||||
filenames,
|
||||
file_texts: file_contents,
|
||||
buf: Cow::Owned(buf.into_bytes()),
|
||||
file_starts,
|
||||
pos: Pos {
|
||||
|
||||
@@ -22,10 +22,13 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn error(&self, pos: Pos, msg: String) -> Error {
|
||||
Error::CompileError {
|
||||
filename: self.lexer.filenames[pos.file].clone(),
|
||||
pos,
|
||||
Error::ParseError {
|
||||
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 {
|
||||
defs,
|
||||
filenames: self.lexer.filenames.clone(),
|
||||
file_texts: self.lexer.file_texts.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,7 @@ use crate::ast;
|
||||
use crate::error::*;
|
||||
use crate::lexer::Pos;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// 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>>;
|
||||
use std::sync::Arc;
|
||||
|
||||
declare_id!(
|
||||
/// The id of an interned symbol.
|
||||
@@ -60,7 +56,12 @@ pub struct TypeEnv {
|
||||
/// Arena of input ISLE source filenames.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
@@ -444,9 +445,10 @@ impl Expr {
|
||||
|
||||
impl TypeEnv {
|
||||
/// 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 {
|
||||
filenames: defs.filenames.clone(),
|
||||
file_texts: defs.file_texts.clone(),
|
||||
syms: vec![],
|
||||
sym_map: HashMap::new(),
|
||||
types: vec![],
|
||||
@@ -523,11 +525,11 @@ impl TypeEnv {
|
||||
Ok(tyenv)
|
||||
}
|
||||
|
||||
fn return_errors(&mut self) -> SemaResult<()> {
|
||||
if self.errors.len() > 0 {
|
||||
Err(std::mem::take(&mut self.errors))
|
||||
} else {
|
||||
Ok(())
|
||||
fn return_errors(&mut self) -> Result<()> {
|
||||
match self.errors.len() {
|
||||
0 => Ok(()),
|
||||
1 => Err(self.errors.pop().unwrap()),
|
||||
_ => Err(Error::Errors(std::mem::take(&mut self.errors))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,10 +606,13 @@ impl TypeEnv {
|
||||
}
|
||||
|
||||
fn error(&self, pos: Pos, msg: String) -> Error {
|
||||
Error::CompileError {
|
||||
filename: self.filenames[pos.file].clone(),
|
||||
pos,
|
||||
Error::TypeError {
|
||||
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 {
|
||||
/// 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 {
|
||||
terms: vec![],
|
||||
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 {
|
||||
Ok(a) => a,
|
||||
Err(_) => {
|
||||
|
||||
@@ -10,3 +10,4 @@ log = "0.4"
|
||||
isle = { version = "*", path = "../isle/" }
|
||||
env_logger = { version = "0.8", default-features = false }
|
||||
clap = "2.33"
|
||||
miette = { version = "3.0.0", features = ["fancy"] }
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
use clap::{App, Arg};
|
||||
use isle::{compile, lexer, parser};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
|
||||
use isle::{error, lexer, parser, compile};
|
||||
|
||||
fn main() -> Result<(), error::Error> {
|
||||
fn main() -> Result<()> {
|
||||
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")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.author("Chris Fallin <chris@cfallin.org>")
|
||||
@@ -37,31 +47,14 @@ fn main() -> Result<(), error::Error> {
|
||||
|
||||
let lexer = lexer::Lexer::from_files(input_files)?;
|
||||
let mut parser = parser::Parser::new(lexer);
|
||||
let defs = match parser.parse_defs() {
|
||||
Ok(defs) => 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);
|
||||
}
|
||||
};
|
||||
let defs = parser.parse_defs()?;
|
||||
let code = compile::compile(&defs)?;
|
||||
|
||||
{
|
||||
use std::io::Write;
|
||||
let mut f = std::fs::File::create(output_file)?;
|
||||
writeln!(&mut f, "{}", code)?;
|
||||
let mut f = std::fs::File::create(output_file).into_diagnostic()?;
|
||||
writeln!(&mut f, "{}", code).into_diagnostic()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user