mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-10-26 13:38:47 +03:00
Merge remote-tracking branch 'origin/experimental' into experimental
This commit is contained in:
commit
8614962426
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
@ -351,6 +357,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exitcode"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
|
||||
|
||||
[[package]]
|
||||
name = "fixed-hash"
|
||||
version = "0.7.0"
|
||||
@ -606,7 +618,9 @@ dependencies = [
|
||||
name = "kind-cli"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.29",
|
||||
"exitcode",
|
||||
"kind-checker",
|
||||
"kind-driver",
|
||||
"kind-query",
|
||||
@ -628,6 +642,7 @@ dependencies = [
|
||||
name = "kind-driver"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dashmap",
|
||||
"fxhash",
|
||||
"hvm",
|
||||
@ -656,6 +671,7 @@ dependencies = [
|
||||
name = "kind-pass"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fxhash",
|
||||
"im-rc",
|
||||
"kind-derive",
|
||||
|
77
FEATURES.md
Normal file
77
FEATURES.md
Normal file
@ -0,0 +1,77 @@
|
||||
It's a entirely new compiler in the 0.3 version. A lot of the features are just simple increments to the old ones but they really help with DX. Lets start by the lexical features:
|
||||
|
||||
- Identifiers cannot start with dot
|
||||
- We can have numbers in a lot of formats now like:
|
||||
- `0xFF`, `0XFF`, `0o17`, `0O17`, `0b10`, `0B10` and decimals.
|
||||
- `0u60` and `0u120`, `0n` that describes u120 and u60 literals.
|
||||
- Numbers can contain lots of underscores (just use one between digits please,
|
||||
we will change it in the future) e.g `100_000_000`
|
||||
- There's a distinction between Upper identifiers and Lower identifiers. Upper cased identifiers
|
||||
can contain a single `'/'` between two parts, if the second part is available then the first one is the name that will be replaced by an 'use' statement.
|
||||
- each string char and the char inside a char token can contain escape sequences in a looot of format. like `\x12` `\u1234` `\n` `\r` `\t` `\0` `\\` `\'` `\"`
|
||||
- Comments with `/* */` that can be nested :)
|
||||
|
||||
The syntatic features are almost all the same with some small changes.
|
||||
|
||||
- Attributes are a little bit more complex and can be seen in some formats.
|
||||
- Single identifier like: #inline
|
||||
- With arguments like: #derive[match, open]
|
||||
- With value like: #kdl_name = Joestar
|
||||
|
||||
- Use statements are in the format `use A as B` and they rename upper cased identifiers like `B/c` to `A.c`
|
||||
|
||||
- Type definitions now support indices and are in the .kind2 files! e.g:
|
||||
```js
|
||||
// Parameters are always in the context like `t` but `n` isnt.
|
||||
type Vec (t: Type) ~ (n: Nat) {
|
||||
cons <size: Nat> (x: t) (xs: Vec t size) : Vec t (Nat.succ size)
|
||||
nil : Vec t Nat.zero
|
||||
}
|
||||
```
|
||||
You can use the `match` eliminator to destruct this vec without having to pattern match on this (but you have to derive `match`).
|
||||
```js
|
||||
Main : U60
|
||||
Main =
|
||||
match Vec (Vec.cons 1 Vec.nil) {
|
||||
cons xs .. => 0
|
||||
nil => 1
|
||||
}
|
||||
```
|
||||
Take a look at the section about `match patterns` in order to understand the `xs` and `..` inside the `cons` case.
|
||||
|
||||
- Record definitions :D
|
||||
```js
|
||||
record User {
|
||||
constructor new
|
||||
name : String
|
||||
age : U60
|
||||
}
|
||||
```
|
||||
You can use the `destruct` notation if you want to destruct a record but you have to derive `open` to make this feature work. `#derive[open]` before the record definition.
|
||||
```js
|
||||
// Using
|
||||
Main : U60
|
||||
Main = let User.new name .. = User.new "abe" 21
|
||||
name
|
||||
```
|
||||
|
||||
- Entries stay all the same, except that you cannot put repeated names because it would make the named parameter process a bit harder.
|
||||
Btw, you can make something like
|
||||
```js
|
||||
Dio (n: U60) (i: U60) : Type
|
||||
|
||||
// Named parameters :sunglasses:
|
||||
Main {
|
||||
Dio (i = 2) (n = 4)
|
||||
}
|
||||
```
|
||||
|
||||
- All the current syntax sugars are:
|
||||
- Sigma types
|
||||
- Substitutions
|
||||
- Do notation
|
||||
- Match
|
||||
- Let
|
||||
- If
|
||||
|
||||
- Doc strings (useful for the future) using `///`
|
@ -22,7 +22,7 @@ Pure functions are defined via equations, as in [Haskell](https://www.haskell.or
|
||||
// Applies a function to every element of a list
|
||||
map <a> <b> (list: List a) (f: a -> b) : List b
|
||||
map a b Nil f = Nil
|
||||
map a b (Cons head tail) f = Cons (f x) (map tail f)
|
||||
map a b (Cons head tail) f = Cons (f head) (map tail f)
|
||||
```
|
||||
|
||||
Side-effective programs are written via monadic monads, resembling [Rust](https://www.rust-lang.org/) and [TypeScript](https://www.typescriptlang.org/):
|
||||
|
@ -465,14 +465,6 @@ List.nil)
|
||||
|
||||
But underneath the hood, what an implicit argument actually does is automatically put holes in these places.
|
||||
|
||||
Moreover, single holes can be shortened as `!`. So it can also be written as:
|
||||
|
||||
```
|
||||
List.cons!(List.cons!(1, List.cons!(2, List.nil!)),
|
||||
List.cons!(List.cons!(3, List.cons!(4, List.nil!)),
|
||||
List.nil!))
|
||||
```
|
||||
|
||||
Of course, in this particular example, we can just use the list notation directly:
|
||||
|
||||
```
|
||||
|
@ -19,4 +19,6 @@ kind-report = { path = "../kind-report" }
|
||||
kind-checker = { path = "../kind-checker" }
|
||||
kind-query = { path = "../kind-query" }
|
||||
|
||||
clap = { version = "4.0.10", features = ["derive"] }
|
||||
clap = { version = "4.0.10", features = ["derive"] }
|
||||
anyhow = "1.0.66"
|
||||
exitcode = "1.1.2"
|
@ -3,6 +3,7 @@ use std::time::Instant;
|
||||
use std::{fmt, io};
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use driver::resolution::ResolutionError;
|
||||
use kind_driver::session::Session;
|
||||
use kind_report::data::{Diagnostic, Log};
|
||||
use kind_report::report::{FileCache, Report};
|
||||
@ -33,7 +34,7 @@ pub struct Cli {
|
||||
pub no_color: bool,
|
||||
|
||||
/// How much concurrency in HVM
|
||||
#[arg(short, long)]
|
||||
#[arg(long)]
|
||||
pub tids: Option<usize>,
|
||||
|
||||
/// Prints all of the functions and their evaluation
|
||||
@ -129,8 +130,8 @@ pub fn compile_in_session<T>(
|
||||
root: PathBuf,
|
||||
file: String,
|
||||
compiled: bool,
|
||||
fun: &mut dyn FnMut(&mut Session) -> Result<T, ()>,
|
||||
) -> Result<T, ()> {
|
||||
fun: &mut dyn FnMut(&mut Session) -> anyhow::Result<T>,
|
||||
) -> anyhow::Result<T> {
|
||||
let (rx, tx) = std::sync::mpsc::channel();
|
||||
|
||||
let mut session = Session::new(root, rx);
|
||||
@ -149,7 +150,8 @@ pub fn compile_in_session<T>(
|
||||
|
||||
let diagnostics = tx.try_iter().collect::<Vec<Box<dyn Diagnostic>>>();
|
||||
|
||||
if diagnostics.is_empty() && res.is_ok() {
|
||||
if diagnostics.is_empty() {
|
||||
|
||||
render_to_stderr(
|
||||
&render_config,
|
||||
&session,
|
||||
@ -159,19 +161,27 @@ pub fn compile_in_session<T>(
|
||||
Log::Checked(start.elapsed())
|
||||
},
|
||||
);
|
||||
|
||||
eprintln!();
|
||||
Ok(res.unwrap())
|
||||
|
||||
res
|
||||
} else {
|
||||
render_to_stderr(&render_config, &session, &Log::Failed(start.elapsed()));
|
||||
eprintln!();
|
||||
|
||||
for diagnostic in diagnostics {
|
||||
render_to_stderr(&render_config, &session, &diagnostic)
|
||||
}
|
||||
Err(())
|
||||
|
||||
match res {
|
||||
Ok(_) => Err(ResolutionError.into()),
|
||||
Err(res) => Err(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_cli(config: Cli) -> Result<(), ()> {
|
||||
pub fn run_cli(config: Cli) -> anyhow::Result<()> {
|
||||
|
||||
kind_report::check_if_colors_are_supported(config.no_color);
|
||||
|
||||
let render_config = kind_report::check_if_utf8_is_supported(config.ascii, 2);
|
||||
@ -262,6 +272,9 @@ pub fn run_cli(config: Cli) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn main() -> Result<(), ()> {
|
||||
run_cli(Cli::parse())
|
||||
pub fn main() {
|
||||
match run_cli(Cli::parse()) {
|
||||
Ok(_) => std::process::exit(0),
|
||||
Err(_) => std::process::exit(1),
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ kind-target-kdl = { path = "../kind-target-kdl" }
|
||||
|
||||
hvm = { git = "https://github.com/Kindelia/HVM.git" }
|
||||
|
||||
anyhow = "1.0.66"
|
||||
strsim = "0.10.0"
|
||||
fxhash = "0.2.1"
|
||||
dashmap = "5.4.0"
|
@ -56,7 +56,7 @@ impl Diagnostic for DriverError {
|
||||
DriverError::MultiplePaths(ident, paths) => DiagnosticFrame {
|
||||
code: 101,
|
||||
severity: Severity::Error,
|
||||
title: "Multiple definitions for the same name".to_string(),
|
||||
title: "Ambiguous definition location for the same name".to_string(),
|
||||
subtitles: paths
|
||||
.iter()
|
||||
.map(|path| Subtitle::Phrase(Color::Fst, vec![Word::White(path.display().to_string())]))
|
||||
|
@ -5,6 +5,7 @@ use kind_report::report::FileCache;
|
||||
use kind_span::SyntaxCtxIndex;
|
||||
|
||||
use kind_tree::{backend, concrete, desugared, untyped};
|
||||
use resolution::ResolutionError;
|
||||
use session::Session;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -25,17 +26,22 @@ pub fn type_check_book(
|
||||
session: &mut Session,
|
||||
path: &PathBuf,
|
||||
entrypoints: Vec<String>,
|
||||
tids: Option<usize>
|
||||
) -> Result<untyped::Book, ()> {
|
||||
tids: Option<usize>,
|
||||
) -> anyhow::Result<untyped::Book> {
|
||||
let concrete_book = to_book(session, path)?;
|
||||
let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?;
|
||||
|
||||
let all = desugared_book.entrs.iter().map(|x| x.0).cloned().collect();
|
||||
|
||||
let succeeded = checker::type_check(&desugared_book, session.diagnostic_sender.clone(), all, tids);
|
||||
let succeeded = checker::type_check(
|
||||
&desugared_book,
|
||||
session.diagnostic_sender.clone(),
|
||||
all,
|
||||
tids,
|
||||
);
|
||||
|
||||
if !succeeded {
|
||||
return Err(());
|
||||
return Err(ResolutionError.into());
|
||||
}
|
||||
|
||||
let mut book = erasure::erase_book(
|
||||
@ -48,14 +54,10 @@ pub fn type_check_book(
|
||||
Ok(book)
|
||||
}
|
||||
|
||||
pub fn to_book(session: &mut Session, path: &PathBuf) -> Result<concrete::Book, ()> {
|
||||
pub fn to_book(session: &mut Session, path: &PathBuf) -> anyhow::Result<concrete::Book> {
|
||||
let mut concrete_book = resolution::parse_and_store_book(session, path)?;
|
||||
|
||||
let failed = resolution::check_unbound_top_level(session, &mut concrete_book);
|
||||
|
||||
if failed {
|
||||
return Err(());
|
||||
}
|
||||
resolution::check_unbound_top_level(session, &mut concrete_book)?;
|
||||
|
||||
Ok(concrete_book)
|
||||
}
|
||||
@ -64,24 +66,29 @@ pub fn erase_book(
|
||||
session: &mut Session,
|
||||
path: &PathBuf,
|
||||
entrypoints: Vec<String>,
|
||||
) -> Result<untyped::Book, ()> {
|
||||
) -> anyhow::Result<untyped::Book> {
|
||||
let concrete_book = to_book(session, path)?;
|
||||
let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?;
|
||||
|
||||
let mut book = erasure::erase_book(
|
||||
&desugared_book,
|
||||
session.diagnostic_sender.clone(),
|
||||
entrypoints,
|
||||
)?;
|
||||
|
||||
inline_book(&mut book);
|
||||
Ok(book)
|
||||
}
|
||||
|
||||
pub fn desugar_book(session: &mut Session, path: &PathBuf) -> Result<desugared::Book, ()> {
|
||||
pub fn desugar_book(session: &mut Session, path: &PathBuf) -> anyhow::Result<desugared::Book> {
|
||||
let concrete_book = to_book(session, path)?;
|
||||
desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)
|
||||
}
|
||||
|
||||
pub fn check_erasure_book(session: &mut Session, path: &PathBuf) -> Result<desugared::Book, ()> {
|
||||
pub fn check_erasure_book(
|
||||
session: &mut Session,
|
||||
path: &PathBuf,
|
||||
) -> anyhow::Result<desugared::Book> {
|
||||
let concrete_book = to_book(session, path)?;
|
||||
desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)
|
||||
}
|
||||
@ -95,9 +102,10 @@ pub fn compile_book_to_kdl(
|
||||
session: &mut Session,
|
||||
namespace: &str,
|
||||
entrypoints: Vec<String>,
|
||||
) -> Result<kind_target_kdl::File, ()> {
|
||||
) -> anyhow::Result<kind_target_kdl::File> {
|
||||
let concrete_book = to_book(session, path)?;
|
||||
let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?;
|
||||
|
||||
let mut book = erasure::erase_book(
|
||||
&desugared_book,
|
||||
session.diagnostic_sender.clone(),
|
||||
@ -106,28 +114,29 @@ pub fn compile_book_to_kdl(
|
||||
|
||||
inline_book(&mut book);
|
||||
|
||||
kind_target_kdl::compile_book(book, session.diagnostic_sender.clone(), namespace)
|
||||
let res = kind_target_kdl::compile_book(book, session.diagnostic_sender.clone(), namespace)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn check_main_entry(session: &mut Session, book: &untyped::Book) -> Result<(), ()> {
|
||||
pub fn check_main_entry(session: &mut Session, book: &untyped::Book) -> anyhow::Result<()> {
|
||||
if !book.entrs.contains_key("Main") {
|
||||
session
|
||||
.diagnostic_sender
|
||||
.send(Box::new(DriverError::ThereIsntAMain))
|
||||
.unwrap();
|
||||
Err(())
|
||||
let err = Box::new(DriverError::ThereIsntAMain);
|
||||
session.diagnostic_sender.send(err).unwrap();
|
||||
Err(ResolutionError.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_main_desugared_entry(session: &mut Session, book: &desugared::Book) -> Result<(), ()> {
|
||||
pub fn check_main_desugared_entry(
|
||||
session: &mut Session,
|
||||
book: &desugared::Book,
|
||||
) -> anyhow::Result<()> {
|
||||
if !book.entrs.contains_key("Main") {
|
||||
session
|
||||
.diagnostic_sender
|
||||
.send(Box::new(DriverError::ThereIsntAMain))
|
||||
.unwrap();
|
||||
Err(())
|
||||
let err = Box::new(DriverError::ThereIsntAMain);
|
||||
session.diagnostic_sender.send(err).unwrap();
|
||||
Err(ResolutionError.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3,9 +3,11 @@
|
||||
//! it returns a desugared book of all of the
|
||||
//! depedencies.
|
||||
|
||||
use core::fmt;
|
||||
use fxhash::FxHashSet;
|
||||
use kind_pass::expand::expand_module;
|
||||
use kind_pass::expand::uses::expand_uses;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
@ -19,6 +21,17 @@ use kind_tree::symbol::{Ident, QualifiedIdent};
|
||||
|
||||
use crate::{errors::DriverError, session::Session};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ResolutionError;
|
||||
|
||||
impl fmt::Display for ResolutionError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "resolution error")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ResolutionError {}
|
||||
|
||||
/// The extension of kind2 files.
|
||||
const EXT: &str = "kind2";
|
||||
|
||||
@ -30,10 +43,11 @@ fn accumulate_neighbour_paths(
|
||||
raw_path: &Path,
|
||||
) -> Result<Option<PathBuf>, Box<dyn Diagnostic>> {
|
||||
let mut canon_path = raw_path.to_path_buf();
|
||||
let mut dir_file_path = raw_path.to_path_buf();
|
||||
let dir_path = raw_path.to_path_buf();
|
||||
let mut dir_file_path = canon_path.clone();
|
||||
let dir_path = canon_path.clone();
|
||||
|
||||
canon_path.set_extension(EXT);
|
||||
|
||||
dir_file_path.push("_");
|
||||
dir_file_path.set_extension(EXT);
|
||||
|
||||
@ -81,13 +95,12 @@ fn try_to_insert_new_name<'a>(
|
||||
book: &'a mut Book,
|
||||
) -> bool {
|
||||
if let Some(first_occorence) = book.names.get(ident.to_string().as_str()) {
|
||||
session
|
||||
.diagnostic_sender
|
||||
.send(Box::new(DriverError::DefinedMultipleTimes(
|
||||
first_occorence.clone(),
|
||||
ident,
|
||||
)))
|
||||
.unwrap();
|
||||
let err = Box::new(DriverError::DefinedMultipleTimes(
|
||||
first_occorence.clone(),
|
||||
ident,
|
||||
));
|
||||
|
||||
session.diagnostic_sender.send(err).unwrap();
|
||||
*failed = true;
|
||||
false
|
||||
} else {
|
||||
@ -107,29 +120,30 @@ fn module_to_book<'a>(
|
||||
for entry in module.entries {
|
||||
match entry {
|
||||
TopLevel::SumType(sum) => {
|
||||
public_names.insert(sum.name.to_string());
|
||||
let name = sum.name.to_string();
|
||||
|
||||
public_names.insert(name.clone());
|
||||
|
||||
for cons in &sum.constructors {
|
||||
let mut cons_ident = sum.name.add_segment(cons.name.to_str());
|
||||
cons_ident.range = cons.name.range;
|
||||
if try_to_insert_new_name(failed, session, cons_ident.clone(), book) {
|
||||
public_names.insert(cons_ident.to_string());
|
||||
book.count
|
||||
.insert(cons_ident.to_string(), cons.extract_book_info(&sum));
|
||||
let cons_name = cons_ident.to_string();
|
||||
public_names.insert(cons_name.clone());
|
||||
book.count.insert(cons_name, cons.extract_book_info(&sum));
|
||||
}
|
||||
}
|
||||
|
||||
if try_to_insert_new_name(failed, session, sum.name.clone(), book) {
|
||||
book.count
|
||||
.insert(sum.name.to_string(), sum.extract_book_info());
|
||||
book.entries
|
||||
.insert(sum.name.to_string(), TopLevel::SumType(sum));
|
||||
book.count.insert(name.clone(), sum.extract_book_info());
|
||||
book.entries.insert(name, TopLevel::SumType(sum));
|
||||
}
|
||||
}
|
||||
TopLevel::RecordType(rec) => {
|
||||
public_names.insert(rec.name.to_string());
|
||||
book.count
|
||||
.insert(rec.name.to_string(), rec.extract_book_info());
|
||||
let name = rec.name.to_string();
|
||||
public_names.insert(name.clone());
|
||||
book.count.insert(name.clone(), rec.extract_book_info());
|
||||
|
||||
try_to_insert_new_name(failed, session, rec.name.clone(), book);
|
||||
|
||||
let cons_ident = rec.name.add_segment(rec.constructor.to_str());
|
||||
@ -138,18 +152,18 @@ fn module_to_book<'a>(
|
||||
cons_ident.to_string(),
|
||||
rec.extract_book_info_of_constructor(),
|
||||
);
|
||||
|
||||
try_to_insert_new_name(failed, session, cons_ident, book);
|
||||
|
||||
book.entries
|
||||
.insert(rec.name.to_string(), TopLevel::RecordType(rec));
|
||||
book.entries.insert(name.clone(), TopLevel::RecordType(rec));
|
||||
}
|
||||
TopLevel::Entry(entr) => {
|
||||
let name = entr.name.to_string();
|
||||
|
||||
try_to_insert_new_name(failed, session, entr.name.clone(), book);
|
||||
public_names.insert(entr.name.to_string());
|
||||
book.count
|
||||
.insert(entr.name.to_string(), entr.extract_book_info());
|
||||
book.entries
|
||||
.insert(entr.name.to_string(), TopLevel::Entry(entr));
|
||||
public_names.insert(name.clone());
|
||||
book.count.insert(name.clone(), entr.extract_book_info());
|
||||
book.entries.insert(name, TopLevel::Entry(entr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,25 +190,19 @@ fn parse_and_store_book_by_identifier(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_and_store_book_by_path(
|
||||
session: &mut Session,
|
||||
path: &PathBuf,
|
||||
book: &mut Book,
|
||||
) -> bool {
|
||||
fn parse_and_store_book_by_path(session: &mut Session, path: &PathBuf, book: &mut Book) -> bool {
|
||||
if !path.exists() {
|
||||
session
|
||||
.diagnostic_sender
|
||||
.send(Box::new(DriverError::CannotFindFile(
|
||||
path.to_str().unwrap().to_string(),
|
||||
)))
|
||||
.unwrap();
|
||||
let err = Box::new(DriverError::CannotFindFile(
|
||||
path.to_str().unwrap().to_string(),
|
||||
));
|
||||
|
||||
session.diagnostic_sender.send(err).unwrap();
|
||||
return true;
|
||||
}
|
||||
|
||||
if session
|
||||
.loaded_paths_map
|
||||
.contains_key(&fs::canonicalize(path).unwrap())
|
||||
{
|
||||
let canon_path = &fs::canonicalize(path).unwrap();
|
||||
|
||||
if session.loaded_paths_map.contains_key(canon_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -213,15 +221,14 @@ fn parse_and_store_book_by_path(
|
||||
|
||||
let ctx_id = session.book_counter;
|
||||
session.add_path(Rc::new(fs::canonicalize(path).unwrap()), input.clone());
|
||||
let tx = session.diagnostic_sender.clone();
|
||||
|
||||
let (mut module, mut failed) =
|
||||
kind_parser::parse_book(session.diagnostic_sender.clone(), ctx_id, &input);
|
||||
let (mut module, mut failed) = kind_parser::parse_book(tx.clone(), ctx_id, &input);
|
||||
|
||||
expand_uses(&mut module, session.diagnostic_sender.clone());
|
||||
expand_uses(&mut module, tx.clone());
|
||||
expand_module(tx.clone(), &mut module);
|
||||
|
||||
expand_module(session.diagnostic_sender.clone(), &mut module);
|
||||
|
||||
let mut state = UnboundCollector::new(session.diagnostic_sender.clone(), false);
|
||||
let mut state = UnboundCollector::new(tx.clone(), false);
|
||||
state.visit_module(&mut module);
|
||||
|
||||
for idents in state.unbound.values() {
|
||||
@ -230,7 +237,7 @@ fn parse_and_store_book_by_path(
|
||||
}
|
||||
|
||||
module_to_book(&mut failed, session, module, book);
|
||||
|
||||
|
||||
for idents in state.unbound_top_level.values() {
|
||||
let fst = idents.iter().next().unwrap();
|
||||
if !book.names.contains_key(&fst.to_string()) {
|
||||
@ -251,41 +258,45 @@ fn unbound_variable(session: &mut Session, book: &Book, idents: &[Ident]) {
|
||||
|
||||
similar_names.sort_by(|x, y| x.0.total_cmp(&y.0));
|
||||
|
||||
session
|
||||
.diagnostic_sender
|
||||
.send(Box::new(DriverError::UnboundVariable(
|
||||
idents.to_vec(),
|
||||
similar_names.iter().take(5).map(|x| x.1.clone()).collect(),
|
||||
)))
|
||||
.unwrap();
|
||||
let err = Box::new(DriverError::UnboundVariable(
|
||||
idents.to_vec(),
|
||||
similar_names.iter().take(5).map(|x| x.1.clone()).collect(),
|
||||
));
|
||||
|
||||
session.diagnostic_sender.send(err).unwrap();
|
||||
}
|
||||
|
||||
pub fn parse_and_store_book(session: &mut Session, path: &PathBuf) -> Result<Book, ()> {
|
||||
pub fn parse_and_store_book(session: &mut Session, path: &PathBuf) -> anyhow::Result<Book> {
|
||||
let mut book = Book::default();
|
||||
if parse_and_store_book_by_path(session, path, &mut book) {
|
||||
Err(())
|
||||
Err(ResolutionError.into())
|
||||
} else {
|
||||
Ok(book)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_unbound_top_level(session: &mut Session, book: &mut Book) -> bool {
|
||||
pub fn check_unbound_top_level(session: &mut Session, book: &mut Book) -> anyhow::Result<()> {
|
||||
let mut failed = false;
|
||||
|
||||
let (_, unbound_tops) =
|
||||
unbound::get_book_unbound(session.diagnostic_sender.clone(), book, true);
|
||||
|
||||
for (_, unbound) in unbound_tops {
|
||||
for unbound in unbound_tops.values() {
|
||||
let res: Vec<Ident> = unbound
|
||||
.iter()
|
||||
.filter(|x| !x.generated)
|
||||
.map(|x| x.to_ident())
|
||||
.collect();
|
||||
|
||||
if !res.is_empty() {
|
||||
unbound_variable(session, book, &res);
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
failed
|
||||
if failed {
|
||||
Err(ResolutionError.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -96,8 +96,8 @@ impl<'a> Lexer<'a> {
|
||||
Some(str)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Useful as entrypoint
|
||||
#[inline]
|
||||
pub fn lex_next(&mut self) -> (Token, Range) {
|
||||
self.lex_token()
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
use fxhash::FxHashMap;
|
||||
use kind_tree::concrete::expr::Expr;
|
||||
use kind_tree::concrete::pat::{Pat, PatIdent, PatKind};
|
||||
/// Parses all of the top level structures
|
||||
/// like Book, Entry, Rule and Argument.
|
||||
use kind_tree::concrete::{
|
||||
Argument, Attribute, Entry, ExprKind, Module, Rule, Telescope, TopLevel,
|
||||
};
|
||||
|
||||
use kind_tree::concrete::*;
|
||||
use kind_tree::symbol::QualifiedIdent;
|
||||
|
||||
use crate::errors::SyntaxDiagnostic;
|
||||
@ -85,6 +82,7 @@ impl<'a> Parser<'a> {
|
||||
fn parse_rule(&mut self, name: String) -> Result<Box<Rule>, SyntaxDiagnostic> {
|
||||
let start = self.range();
|
||||
let ident;
|
||||
|
||||
if let Token::UpperId(name_id, ext) = self.get() {
|
||||
let qual = QualifiedIdent::new_static(name_id.as_str(), ext.clone(), start);
|
||||
if qual.to_string() == name {
|
||||
@ -95,6 +93,7 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
return self.fail(vec![]);
|
||||
}
|
||||
|
||||
let mut pats = Vec::new();
|
||||
while !self.get().same_variant(&Token::Eq) && !self.get().same_variant(&Token::Eof) {
|
||||
pats.push(self.parse_pat()?);
|
||||
|
@ -13,4 +13,5 @@ kind-derive = { path = "../kind-derive" }
|
||||
|
||||
linked-hash-map = "0.5.6"
|
||||
fxhash = "0.2.1"
|
||||
im-rc = "15.1.0"
|
||||
im-rc = "15.1.0"
|
||||
anyhow = "1.0.66"
|
@ -16,7 +16,7 @@ use kind_tree::{
|
||||
symbol::Ident,
|
||||
};
|
||||
|
||||
use crate::errors::PassError;
|
||||
use crate::errors::{PassError, GenericPassError};
|
||||
|
||||
pub mod app;
|
||||
pub mod attributes;
|
||||
@ -35,7 +35,7 @@ pub struct DesugarState<'a> {
|
||||
pub fn desugar_book(
|
||||
errors: Sender<Box<dyn Diagnostic>>,
|
||||
book: &concrete::Book,
|
||||
) -> Result<desugared::Book, ()> {
|
||||
) -> anyhow::Result<desugared::Book> {
|
||||
let mut state = DesugarState {
|
||||
errors,
|
||||
old_book: book,
|
||||
@ -45,7 +45,7 @@ pub fn desugar_book(
|
||||
};
|
||||
state.desugar_book(book);
|
||||
if state.failed {
|
||||
Err(())
|
||||
Err(GenericPassError.into())
|
||||
} else {
|
||||
Ok(state.new_book)
|
||||
}
|
||||
|
@ -245,7 +245,6 @@ impl<'a> DesugarState<'a> {
|
||||
use concrete::pat::PatKind;
|
||||
match &pat.data {
|
||||
PatKind::App(head, spine) => {
|
||||
// TODO: Fix lol
|
||||
let entry = self
|
||||
.old_book
|
||||
.count
|
||||
|
@ -8,7 +8,7 @@ use kind_tree::desugared;
|
||||
use kind_tree::symbol::QualifiedIdent;
|
||||
use kind_tree::untyped::{self};
|
||||
|
||||
use crate::errors::PassError;
|
||||
use crate::errors::{PassError, GenericPassError};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
enum Relevance {
|
||||
@ -54,7 +54,7 @@ pub fn erase_book(
|
||||
book: &desugared::Book,
|
||||
errs: Sender<Box<dyn Diagnostic>>,
|
||||
entrypoints: Vec<String>,
|
||||
) -> Result<untyped::Book, ()> {
|
||||
) -> anyhow::Result<untyped::Book> {
|
||||
let mut state = ErasureState {
|
||||
errs,
|
||||
book,
|
||||
@ -99,7 +99,7 @@ impl<'a> ErasureState<'a> {
|
||||
&mut self,
|
||||
book: &'a desugared::Book,
|
||||
named_entrypoints: Vec<String>,
|
||||
) -> Result<untyped::Book, ()> {
|
||||
) -> anyhow::Result<untyped::Book> {
|
||||
let mut vals = FxHashMap::default();
|
||||
|
||||
let mut entrypoints = Vec::new();
|
||||
@ -189,7 +189,7 @@ impl<'a> ErasureState<'a> {
|
||||
}
|
||||
|
||||
if self.failed {
|
||||
Err(())
|
||||
Err(GenericPassError.into())
|
||||
} else {
|
||||
Ok(new_book)
|
||||
}
|
||||
|
@ -1,7 +1,20 @@
|
||||
use std::{fmt::Display, error::Error};
|
||||
|
||||
use kind_report::data::{Color, Diagnostic, DiagnosticFrame, Marker, Severity};
|
||||
use kind_span::{Range, SyntaxCtxIndex};
|
||||
use kind_tree::symbol::Ident;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GenericPassError;
|
||||
|
||||
impl Display for GenericPassError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "generic pass error")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for GenericPassError { }
|
||||
|
||||
pub enum Sugar {
|
||||
DoNotation,
|
||||
List,
|
||||
|
@ -8,7 +8,7 @@ use tiny_keccak::Hasher;
|
||||
|
||||
pub use kindelia_lang::ast as kdl;
|
||||
|
||||
use crate::errors::KdlError;
|
||||
use crate::{errors::KdlError, GenericCompilationToHVMError};
|
||||
|
||||
pub const KDL_NAME_LEN: usize = 12;
|
||||
const U60_MAX: kdl::U120 = kdl::U120(0xFFFFFFFFFFFFFFF);
|
||||
@ -97,7 +97,7 @@ pub fn compile_book(
|
||||
book: &untyped::Book,
|
||||
sender: Sender<Box<dyn Diagnostic>>,
|
||||
namespace: &str,
|
||||
) -> Result<File, ()> {
|
||||
) -> Result<File, GenericCompilationToHVMError> {
|
||||
let mut ctx = CompileCtx::new(book, sender);
|
||||
|
||||
for (name, entry) in &book.entrs {
|
||||
@ -120,7 +120,7 @@ pub fn compile_book(
|
||||
}
|
||||
|
||||
if ctx.failed {
|
||||
return Err(());
|
||||
return Err(GenericCompilationToHVMError);
|
||||
}
|
||||
|
||||
Ok(ctx.file)
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::{sync::mpsc::Sender, fmt::Display, error::Error};
|
||||
|
||||
use flatten::flatten;
|
||||
use kind_report::data::Diagnostic;
|
||||
@ -12,11 +12,22 @@ mod flatten;
|
||||
mod linearize;
|
||||
mod subst;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GenericCompilationToHVMError;
|
||||
|
||||
impl Display for GenericCompilationToHVMError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "generic compilation to hvm error")
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for GenericCompilationToHVMError { }
|
||||
|
||||
pub fn compile_book(
|
||||
book: untyped::Book,
|
||||
sender: Sender<Box<dyn Diagnostic>>,
|
||||
namespace: &str,
|
||||
) -> Result<compile::File, ()> {
|
||||
) -> Result<compile::File, GenericCompilationToHVMError> {
|
||||
// TODO: Remove kdl_states (maybe check if they're ever called?)
|
||||
// TODO: Convert to some sort of Kindelia.Contract
|
||||
let flattened = flatten(book);
|
||||
|
@ -97,8 +97,8 @@ fn bench_exp_pure_check_unbound(b: &mut Bencher) {
|
||||
|
||||
b.iter(|| {
|
||||
books.iter_mut().map(|(session, book)| {
|
||||
let failed = resolution::check_unbound_top_level(session, book);
|
||||
assert!(!failed)
|
||||
let result = resolution::check_unbound_top_level(session, book);
|
||||
assert!(result.is_ok());
|
||||
}).fold(0, |n, _| n + 1)
|
||||
})
|
||||
}
|
||||
@ -110,8 +110,8 @@ fn bench_exp_pure_desugar(b: &mut Bencher) {
|
||||
let mut books: Vec<_> = paths.iter().map(|x| {
|
||||
let mut session = new_session();
|
||||
let mut book = resolution::parse_and_store_book(&mut session, &PathBuf::from(x)).unwrap();
|
||||
let failed = resolution::check_unbound_top_level(&mut session, &mut book);
|
||||
assert!(!failed);
|
||||
let result = resolution::check_unbound_top_level(&mut session, &mut book);
|
||||
assert!(result.is_ok());
|
||||
(session, book)
|
||||
}).collect();
|
||||
|
||||
@ -130,9 +130,9 @@ fn bench_exp_pure_erase(b: &mut Bencher) {
|
||||
let books: Vec<_> = paths.iter().map(|x| {
|
||||
let mut session = new_session();
|
||||
let mut book = resolution::parse_and_store_book(&mut session, &PathBuf::from(x)).unwrap();
|
||||
let failed = resolution::check_unbound_top_level(&mut session, &mut book);
|
||||
let result = resolution::check_unbound_top_level(&mut session, &mut book);
|
||||
let book = desugar::desugar_book(session.diagnostic_sender.clone(), &book).unwrap();
|
||||
assert!(!failed);
|
||||
assert!(result.is_ok());
|
||||
|
||||
(session, book)
|
||||
}).collect();
|
||||
@ -156,9 +156,9 @@ fn bench_exp_pure_to_hvm(b: &mut Bencher) {
|
||||
let books: Vec<_> = paths.iter().map(|x| {
|
||||
let mut session = new_session();
|
||||
let mut book = resolution::parse_and_store_book(&mut session, &PathBuf::from(x)).unwrap();
|
||||
let failed = resolution::check_unbound_top_level(&mut session, &mut book);
|
||||
let result = resolution::check_unbound_top_level(&mut session, &mut book);
|
||||
let book = desugar::desugar_book(session.diagnostic_sender.clone(), &book).unwrap();
|
||||
assert!(!failed);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let book = erasure::erase_book(
|
||||
&book,
|
||||
|
Loading…
Reference in New Issue
Block a user