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.
|
# 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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(_) => {
|
||||||
|
|||||||
@@ -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"] }
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user