reorganize repo, split files

This commit is contained in:
Victor Taelin 2024-03-01 14:28:42 -03:00
parent 10da6d2afb
commit 21dd404798
18 changed files with 1314 additions and 781 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
/target
.tmp/
.kind21/
plans.txt
.check.hvm1
demo/

4
Cargo.lock generated
View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "TSPL"
version = "0.0.4"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8ec3e7412fb948ebd3410595e15e7f80c12bf7958ffb83a7f6ff34942505f9"
checksum = "c1ed463bdafa4b9eea9fe4120a51abb90289275c4f3411d344de2787567cb6ae"
dependencies = [
"highlight_error",
]

View File

@ -8,6 +8,6 @@ name = "kind2"
path = "src/main.rs"
[dependencies]
TSPL = "0.0.4"
TSPL = "0.0.6"
highlight_error = "0.1.1"
im = "15.1.0"

3
book/.fill.tmp Normal file
View File

@ -0,0 +1,3 @@
if I take 1 screenshot of my macbook every minute, and store it as a PNG (1920x1080), how much storage will that need, in average, per day? make an educated calculation.
{{FILL_HERE}}

297
book/_main.kind2 Normal file
View File

@ -0,0 +1,297 @@
dup
: ∀(A: *)
∀(x: A)
(Pair A A)
= λA λx (Pair.new A A x x)
_main
: ∀(a: Bool) ∀(b: Bool) Bool
//= λa λb (Bool.match a λa(Bool) (Bool.match b _ Bool.true Bool.true) Bool.true)
= λa λb (Bool.if a _ (Bool.if b _ ?A Bool.true) Bool.true)
//Main
//: ∀(b: Bool) (~b λx(*) Nat String)
//= λb (~b ?A Nat.zero "foo")
//Main
//: ∀(a: #U60)
//∀(b: #U60)
//#U60
//= λa λb
//#(> a b)
//(?A Bool.true) == (~b λx(*) Nat String)
//Main = (List.cons ?A #1 (List.cons ?B #2 (List.nil ?C)))
//Main
//: #U60
//= "foo"
//Main
//: ∀(P: ∀(x: Bool) *)
//∀(f: ∀(x: Bool) (P x))
//(P (Bool.not (Bool.not Bool.true)))
//= λP λf
//?a
//TYPE_MISMATCH
//- expected: (Pair (Maybe V) (String.Map V))
//- detected: (Pair (Maybe V) (BBT String V))
//- bad_term: (BBT.got String V String.cmp key map)
//./String.Map.kind2
//20 | (BBT.got String V String.cmp key map)
//(List.cons (Pair Char Char) (Pair.new Char Char Char #8) // '\b'
//(List.nil (Pair Char Char)))
//Main
//: (IO Unit)
//= (IO.run Unit
//(IO.bind Unit Unit (IO.print.do "hello") λx
//(IO.bind Kind.Book Unit (Kind.load "Bool") λbook
//(IO.bind Unit Unit (IO.print.do (Kind.Book.to_hvm book)) λx
//(IO.done Unit Unit.one)))))
//Main
//= Kind.API.check
//Main = Kind.load.dependency
//Main
//: Unit
//= let map = (String.Map.new Unit)
//let map = (String.Map.set Unit "Bool" Unit.one map)
//let map = (String.Map.set Unit "Bool.true" Unit.one map)
//let has = (String.Map.has Unit "Bool.false" map)
//(HVM.print Unit (Bool.show has)
//Unit.one)
//Main
//: (IO Unit)
//= (IO.run Unit
//(IO.load Unit "B.kind2" λfile
//(IO.print Unit file λx
//(IO.done Unit Unit.one))))
//FOO
//: Kind.Book
//= (HVM.load Kind.Book "B.kind2" λdata (Kind.Book.parse data))
//Main
//: (String.Map Kind.Book)
//=
////(HVM.load ?k "B.kind2" λcode
////let book = (Kind.Book.parse code)
//let book = (HVM.load ?k "B.kind2" λdata (Kind.Book.parse data))
//let seen = (String.Map.new Kind.Book)
//let seen = (String.Map.set Kind.Book "Bool" book seen)
//seen
////)
//Main
//: (String.Map Unit)
//= let unit = Unit.one
//let seen = (String.Map.new Unit)
//let seen = (String.Map.set Unit "Bool" unit seen)
//seen
//: (String.Map Kind.Book)
//= let book = (Kind.load "Bool")
//book
//(HVM.print Unit (Kind.Book.show book)
//Unit.one)
//Main = Kind.load.code
//Main = Kind.load.go.defs
//Main
//: Unit
//=
////= (HVM.print Unit (Kind.Book.to_hvm (Kind.API.load "Bool.and"))
//Unit.one
//)
//Main
//: (Maybe #U60)
//= let map = (String.Map.new #U60)
//let map = (String.Map.set #U60 "foo" #1 map)
//let map = (String.Map.set #U60 "bar" #2 map)
//let map = (String.Map.set #U60 "tic" #3 map)
//let map = (String.Map.set #U60 "tac" #4 map)
//let val = (String.Map.get #U60 "bar" map)
//val
//Main
//: Kind.Book
//=
//let book = (Kind.API.load "Bool.and")
//book
//let code = (Kind.Book.to_hvm book)
//let refs = (Kind.Book.get_refs book)
//(HVM.print Unit code
//Unit.one)
//BOOK
//: String
//= "id = λx x
//Bool : * = $self ∀(P: ∀(x: Bool) *) ∀(t: (P Bool.true)) ∀(f: (P Bool.false)) (P self)
//Bool.true : Bool = ~λP λt λf t
//Bool.false : Bool = ~λP λt λf f
//"
//Main
//: String
//= (Kind.Book.show (Kind.Book.parse BOOK))
//Main = Kind.Term.parser.app
//Main
//: String
//= let P = λx(String)
//let done = λcode λok (~ok λx(String) "A" "B")
//let fail = λerror "C"
//(~(Parser.is_eof " k skdafjkfd") P done fail)
//Main
//: String
//= let CON = String.concat
//let P = λx(String)
//let done = λcode λvalue (CON "done: " (CON code (CON " ## RESULT={{" (CON value "}}"))))
//let fail = λcode λvalue (CON "fail: " code)
//let parse = (Parser.until Char (Parser.text "ABC") Parser.take)
////let parse = (Parser.bind Unit String (Parser.text "ABC") λx(Parser.pure String "ok"))
//(~(parse "oi tudo bem bar aaaaaaaa tic tac") P done fail)
//Main = Parser.until
//Main
//: String
//= let CON = String.concat
//let parse = (Parser.char.escaped 'n' #32)
//let P = λx(String)
//let done = λcode λvalue (CON code (CON " || " (String.cons value String.nil)))
//let fail = λcode λvalue "fail"
//(~(parse "\nfoo") P done fail)
//Main = Parser.char
//Main
//: String
//= let OPT = (List.cons (Parser String))
//let END = (List.nil (Parser String))
//let CON = String.concat
//let P = λx(String)
//let done = λcode λvalue (CON "done: " (CON (String.cons value String.nil) (CON " ## left: " code)))
//let fail = λcode λvalue (CON "fail: " code)
//(~(Parser.char "\\bc") P done fail)
//Main = Parser.until
//Main = Char.escapes
//Main = Kind.Term.parser
//Main = Kind.Scope.find
//Main = List.fold
//Main
//: (List.Folder #U60)
//= λP λcons λnil (cons #0 (cons #1 (cons #2 nil)))
//Main
//: #U60
//= let list =
//(List.cons #U60 #1
//(List.cons #U60 #2
//(List.cons #U60 #3
//(List.nil #U60))))
//((List.fold #U60 list) #U60 λhλt#(+ h t) #0)
//Main
//: String
//= let OPT = (List.cons (Parser String))
//let END = (List.nil (Parser String))
//let CON = String.concat
//let NIL = String.nil
//let P = λx(String)
//let done = λcode λvalue (CON "done: " (CON value (CON " ## left: " code)))
//let fail = λcode λerror (CON "fail: " code)
//let opts =
//(OPT (Parser.bind Unit String (Parser.text (String.cons Char.slash (String.cons 'n' String.nil))) λx
//(Parser.pure String "parsed_0"))
//(OPT (Parser.bind Unit String (Parser.text "farinha") λx
//(Parser.pure String "parsed_1"))
//(OPT (Parser.bind Unit String (Parser.text "alpiste") λx
//(Parser.pure String "parsed_2"))
//END)))
//let text = "\nalpiste medula oblongata"
//(~(Parser.options String opts text) P done fail)
//Main
//: String
//= let P = λx(String)
//let done = λcode λvalue (CON "done: " (CON (Bool.if value String "Y" "N") (CON " ## left: " code)))
//let fail = λerror (CON "fail: " error)
//(~(Parser.test "testador de" "testador de testes") P done fail)
//Main
//: String
//= let P = λx(String)
//let new = λcode λword word
//(~(Parser.word Char.is_name "foo bar tic tac") P new)
//Main
//: Bool
//= (Char.is_name 'D')
//Main
//: String
//= (String.cons 'a' String.nil)
//Main
//: String
//= let str = " foo bar"
//(String.skip str)
//Main
//: (Maybe #U60)
//= let list =
//(List.cons #U60 #10
//(List.cons #U60 #20
//(List.cons #U60 #30
//(List.cons #U60 #40
//(List.cons #U60 #50
//(List.nil #U60))))))
//(List.find #U60 (U60.equal #30) list)
//Main
//: Bool
//= (String.equal "abcd" "abcd")
//Main
//: String
//= (U60.name #703)
//Main
//: String
//= #match x = #2 {
//#0: "0"
//#+: #match y = x-1 {
//#0: "1"
//#+: ">"
//}: String
//}: String

83
src/book/mod.rs Normal file
View File

@ -0,0 +1,83 @@
use crate::{*};
use std::collections::BTreeMap;
use std::collections::BTreeSet;
mod parse;
mod show;
mod to_hvm1;
// <book> ::=
// DEF_ANN | <name> : <term> = <term> <book>
// DEF_VAL | <name> = <term> <book>
// END | <eof>
#[derive(Clone, Debug)]
pub struct Book {
pub defs: BTreeMap<String, Term>,
pub fids: BTreeMap<String, u64>,
}
impl Book {
pub fn new() -> Self {
Book {
defs: BTreeMap::new(),
fids: BTreeMap::new(),
}
}
pub fn load(name: &str) -> Result<Self, String> {
fn load_go(name: &str, book: &mut Book) -> Result<(), String> {
//println!("... {}", name);
if !book.defs.contains_key(name) {
let file = format!("./{}.kind2", name);
let text = std::fs::read_to_string(&file).map_err(|_| format!("Could not read file: {}", file))?;
let fid = book.get_file_id(&file);
//println!("... parsing: {}", name);
let defs = KindParser::new(&text).parse_book(fid)?;
//println!("... parsed: {}", name);
for (def_name, def_value) in &defs.defs {
book.defs.insert(def_name.clone(), def_value.clone());
}
//println!("laoding deps for: {}", name);
for (_, def_term) in defs.defs.into_iter() {
let mut dependencies = BTreeSet::new();
def_term.get_free_vars(im::Vector::new(), &mut dependencies);
//println!("{} deps: {:?}", name, dependencies);
for ref_name in dependencies {
load_go(&ref_name, book)?;
}
}
}
return Ok(());
}
let mut book = Book::new();
load_go(name, &mut book)?;
load_go("String", &mut book)?;
load_go("String.cons", &mut book)?;
load_go("String.nil", &mut book)?;
//println!("DONE!");
Ok(book)
}
pub fn get_file_id(&mut self, name: &str) -> u64 {
if let Some(id) = self.fids.get(name) {
*id
} else {
let id = self.fids.len() as u64 + 1;
self.fids.insert(name.to_string(), id);
id
}
}
// FIXME: asymptotics
pub fn get_file_name(&self, id: u64) -> Option<String> {
for (name, &fid) in &self.fids {
if fid == id {
return Some(name.clone());
}
}
None
}
}

35
src/book/parse.rs Normal file
View File

@ -0,0 +1,35 @@
use crate::{*};
use std::collections::BTreeMap;
use std::collections::BTreeSet;
impl<'i> KindParser<'i> {
pub fn parse_def(&mut self, fid: u64) -> Result<(String, Term), String> {
self.skip_trivia();
let nam = self.parse_name()?;
self.skip_trivia();
if self.peek_one() == Some(':') {
self.consume(":")?;
let typ = self.parse_term(fid)?;
self.consume("=")?;
let val = self.parse_term(fid)?;
Ok((nam, Term::Ann { val: Box::new(val), typ: Box::new(typ) }))
} else {
self.consume("=")?;
let val = self.parse_term(fid)?;
Ok((nam, val))
}
}
pub fn parse_book(&mut self, fid: u64) -> Result<Book, String> {
let mut book = Book::new();
while *self.index() < self.input().len() {
let (name, term) = self.parse_def(fid)?;
book.defs.insert(name, term);
self.skip_trivia();
}
Ok(book)
}
}

13
src/book/show.rs Normal file
View File

@ -0,0 +1,13 @@
use crate::{*};
impl Book {
pub fn show(&self) -> String {
let mut book_str = String::new();
for (name, term) in &self.defs {
book_str.push_str(&format!("{} = {}\n", name, term.show()));
}
book_str
}
}

24
src/book/to_hvm1.rs Normal file
View File

@ -0,0 +1,24 @@
use crate::{*};
use std::collections::BTreeMap;
use std::collections::BTreeSet;
impl Book {
pub fn to_hvm1(&self) -> String {
let mut used = BTreeSet::new();
let mut code = String::new();
for (name, term) in &self.defs {
let metas = term.count_metas();
let mut lams = String::new();
for i in 0 .. term.count_metas() {
lams = format!("{} λ_{}", lams, i);
}
let subs = (0 .. metas).map(|h| format!("(Pair \"{}\" None)", h)).collect::<Vec<_>>().join(",");
code.push_str(&format!("Book.{} = (Ref \"{}\" [{}] {}{})\n", name, name, subs, lams, term.to_hvm1(im::Vector::new(), &mut 0)));
used.insert(name.clone());
}
code
}
}

62
src/info/mod.rs Normal file
View File

@ -0,0 +1,62 @@
use crate::{*};
mod parse;
mod show;
// <info> ::=
// FOUND | #found{?<name> <term>}
// ERROR | #error{<term> <term> <term> <uint>}
// SOLVE | #solve{_<name> <term>}
// VAGUE | #vague{_<name>}
#[derive(Clone, Debug)]
pub enum Info {
Found {
nam: String,
typ: Term,
ctx: Vec<Term>,
},
Error {
exp: Term,
det: Term,
bad: Term,
src: Src,
},
Solve {
nam: String,
val: Term,
},
Vague {
nam: String,
}
}
impl Info {
pub fn pretty(&self, book: &Book) -> String {
match self {
Info::Found { nam, typ, ctx } => {
let msg = format!("?{} :: {}", nam, typ.show());
let ctx = ctx.iter().map(|x| x.show()).collect::<Vec<_>>().join("\n- ");
format!("\x1b[1mFOUND:\x1b[0m {}{}", msg, ctx)
},
Info::Error { exp, det, bad, src } => {
let exp = format!("- expected: \x1b[32m{}\x1b[0m", exp.show());
let det = format!("- detected: \x1b[31m{}\x1b[0m", det.show());
let bad = format!("- bad_term: \x1b[2m{}\x1b[0m", bad.show());
let file = book.get_file_name(src.fid).unwrap_or_else(|| "unknown_file".to_string());
let text = std::fs::read_to_string(&file).unwrap_or_else(|_| "Could not read source file.".to_string());
let orig = highlight_error(src.ini as usize, src.end as usize, &text);
let src = format!("\x1b[4m{}\x1b[0m\n{}", file, orig);
format!("\x1b[1mERROR:\x1b[0m\n{}\n{}\n{}\n{}", exp, det, bad, src)
},
Info::Solve { nam, val } => {
format!("SOLVE: _{} = {}", nam, val.show())
},
Info::Vague { nam } => {
format!("VAGUE: _{}", nam)
}
}
}
}

80
src/info/parse.rs Normal file
View File

@ -0,0 +1,80 @@
use crate::{*};
impl<'i> KindParser<'i> {
pub fn parse_info(&mut self) -> Result<Info, String> {
self.skip_trivia();
match self.peek_one() {
Some('#') => {
self.consume("#")?;
match self.peek_one() {
Some('f') => {
self.consume("found")?;
self.consume("{")?;
let nam = self.parse_name()?;
let typ = self.parse_term(0)?;
self.consume("[")?;
let mut ctx = Vec::new();
while self.peek_one() != Some(']') {
ctx.push(self.parse_term(0)?);
self.skip_trivia();
}
self.consume("]")?;
self.consume("}")?;
Ok(Info::Found { nam, typ, ctx })
}
Some('e') => {
self.consume("error")?;
self.consume("{")?;
let exp = self.parse_term(0)?;
let det = self.parse_term(0)?;
let bad = self.parse_term(0)?;
let src = Src::from_u64(self.parse_u64()?);
self.consume("}")?;
Ok(Info::Error {
exp: exp,
det: det,
bad: bad,
src: src,
})
}
Some('s') => {
self.consume("solve")?;
self.consume("{")?;
let nam = self.parse_name()?;
let val = self.parse_term(0)?;
self.consume("}")?;
Ok(Info::Solve { nam, val })
}
Some('v') => {
self.consume("vague")?;
self.consume("{")?;
let nam = self.parse_name()?;
self.consume("}")?;
Ok(Info::Vague { nam })
}
_ => self.expected("info type (solve, found, error)"),
}
}
_ => self.expected("# (start of info)"),
}
}
pub fn parse_infos(&mut self) -> Result<Vec<Info>, String> {
let mut infos = Vec::new();
while *self.index() < self.input().len() {
let parsed_info = self.parse_info();
match parsed_info {
Ok(msg) => {
infos.push(msg);
self.skip_trivia();
}
Err(_) => {
break;
}
}
}
Ok(infos)
}
}

23
src/info/show.rs Normal file
View File

@ -0,0 +1,23 @@
use crate::{*};
impl Info {
pub fn show(&self) -> String {
match self {
Info::Found { nam, typ, ctx } => {
let ctx = ctx.iter().map(|x| x.show()).collect::<Vec<_>>().join(" ");
format!("#found{{?{} {} [{}]}}", nam, typ.show(), ctx)
},
Info::Error { exp, det, bad, src } => {
format!("#error{{{} {} {} {}}}", exp.show(), det.show(), bad.show(), src.to_u64())
},
Info::Solve { nam, val } => {
format!("#solve{{_{} {}}}", nam, val.show())
},
Info::Vague { nam } => {
format!("#vague{{?{}}}", nam)
}
}
}
}

View File

@ -743,19 +743,19 @@
(Context.show.ann (Ann val typ) dep) = (String.join ["{" (Show (Normal 0 val dep) dep) ": " (Show (Normal 0 typ dep) dep) "}"])
(Context.show.ann term dep) = (Show (Normal 0 term dep) dep)
(Message.show (Found name type ctx dep)) =
(Info.show (Found name type ctx dep)) =
let type = (Show (Normal 1 type dep) dep)
let ctx = (String.tail (Context.show ctx dep))
(String.join ["#found{" name " " type " [" ctx "]}"])
(Message.show (Error src detected expected value dep)) =
(Info.show (Error src detected expected value dep)) =
let det = (Show (Normal 1 detected dep) dep)
let exp = (Show (Normal 1 expected dep) dep)
let val = (Show (Normal 0 value dep) dep)
(String.join ["#error{" exp " " det " " val " " (U60.show src) "}"])
(Message.show (Solve name term dep)) =
(Info.show (Solve name term dep)) =
let term = (Show (Normal 1 term dep) dep)
(String.join ["#solve{" name " " term "}"])
(Message.show (Vague name)) =
(Info.show (Vague name)) =
(String.join ["#vague{" name "}"])
// Compilation
@ -836,7 +836,7 @@ Compile.primitives = [
// case true:
(API.check (Ref nam sub def))
// case false:
(API.check.vague sub)))
(API.check.log logs 1)))
// case fail:
λlogs λerror
(API.check.log logs
@ -852,14 +852,14 @@ Compile.primitives = [
// Moves solutions from the checker logs to a ref's subst list.
(API.check.fill sub (List.cons (Solve k v d) xs)) = (Pair.get (API.check.fill sub xs) λokλmap(Pair 1 (Map.set λxλy(Same x y) k (Some v) sub)))
(API.check.fill sub (List.cons message xs)) = (API.check.fill sub xs)
(API.check.fill sub (List.cons info xs)) = (API.check.fill sub xs)
(API.check.fill sub List.nil) = (Pair 0 sub)
// Prints all messages returned by the checker.
(API.check.log (List.cons msg msgs) then) = (HVM.print (Message.show msg) (API.check.log msgs then))
(API.check.log (List.cons msg msgs) then) = (HVM.print (Info.show msg) (API.check.log msgs then))
(API.check.log List.nil then) = then
// Reports solved holdes
(API.check.vague (List.cons (Pair name None) xs)) = (HVM.print (Message.show (Vague name)) (& 0 (API.check.vague xs)))
(API.check.vague (List.cons (Pair name None) xs)) = (HVM.print (Info.show (Vague name)) (& 0 (API.check.vague xs)))
(API.check.vague (List.cons (Pair name (Some x)) xs)) = (API.check.vague xs)
(API.check.vague List.nil) = 1

View File

@ -1,781 +1,23 @@
#![allow(dead_code)]
#![allow(unused_imports)]
mod book;
mod info;
mod term;
use book::{*};
use info::{*};
use term::{*};
use TSPL::Parser;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use highlight_error::highlight_error;
use std::env;
use std::fs::File;
use std::io::Write;
use std::process::Command;
use highlight_error::highlight_error;
#[derive(Clone, Copy, Debug)]
enum Oper {
Add , Sub , Mul , Div ,
Mod , Eq , Ne , Lt ,
Gt , Lte , Gte , And ,
Or , Xor , Lsh , Rsh ,
}
// <term> ::=
// ALL | ∀(<name>: <term>) <term>
// LAM | λ<name> <term>
// APP | (<term> <term>)
// ANN | {<term>: <term>}
// SLF | $(<name>: <term>) <term>
// INS | ~<term>
// SET | *
// U60 | #U60
// NUM | #<uint>
// OP2 | #(<oper> <term> <term>)
// MAT | #match <name> = <term> { #0: <term>; #+: <term> }: <term>
// MET | ?<name>
// HOL | _
// CHR | '<char>'
// STR | "<string>"
// LET | let <name> = <term> <term>
// VAR | <name>
#[derive(Clone, Debug)]
enum Term {
All { nam: String, inp: Box<Term>, bod: Box<Term> },
Lam { nam: String, bod: Box<Term> },
App { fun: Box<Term>, arg: Box<Term> },
Ann { val: Box<Term>, typ: Box<Term> },
Slf { nam: String, typ: Box<Term>, bod: Box<Term> },
Ins { val: Box<Term> },
Set,
U60,
Num { val: u64 },
Op2 { opr: Oper, fst: Box<Term>, snd: Box<Term> },
Mat { nam: String, x: Box<Term>, z: Box<Term>, s: Box<Term>, p: Box<Term> },
Txt { txt: String },
Let { nam: String, val: Box<Term>, bod: Box<Term> },
Var { nam: String },
Hol { nam: String },
Met {},
Src { src: u64, val: Box<Term> },
}
#[derive(Clone, Debug)]
// <book> ::=
// DEF_ANN | <name> : <term> = <term> <book>
// DEF_VAL | <name> = <term> <book>
// END | <eof>
struct Book {
defs: BTreeMap<String, Term>,
fids: BTreeMap<String, u64>,
}
// <message> ::=
// FOUND | #found{?<name> <term>}
// ERROR | #error{<term> <term> <term> <uint>}
// SOLVE | #solve{_<name> <term>}
// VAGUE | #vague{_<name>}
#[derive(Clone, Debug)]
enum Message {
Found {
nam: String,
typ: Term,
ctx: Vec<Term>,
},
Error {
exp: Term,
det: Term,
bad: Term,
src: u64,
},
Solve {
nam: String,
val: Term,
},
Vague {
nam: String,
}
}
fn name(numb: usize) -> String {
let mut name = String::new();
let mut numb = numb as i64;
loop {
name.insert(0, ((97 + (numb % 26)) as u8) as char);
numb = numb / 26 - 1;
if numb < 0 { break; }
}
name
}
pub fn new_src(fid: u64, ini: u64, end: u64) -> u64 {
(fid << 40) | (ini << 20) | end
}
pub fn src_fid(src: u64) -> u64 {
src >> 40
}
pub fn src_ini(src: u64) -> u64 {
(src >> 20) & 0xFFFFF
}
pub fn src_end(src: u64) -> u64 {
src & 0xFFFFF
}
pub fn cons<A>(vector: &im::Vector<A>, value: A) -> im::Vector<A> where A: Clone {
let mut new_vector = vector.clone();
new_vector.push_back(value);
new_vector
}
impl Oper {
fn show(&self) -> &'static str {
match self {
Oper::Add => "+",
Oper::Sub => "-",
Oper::Mul => "*",
Oper::Div => "/",
Oper::Mod => "%",
Oper::Eq => "==",
Oper::Ne => "!=",
Oper::Lt => "<",
Oper::Gt => ">",
Oper::Lte => "<=",
Oper::Gte => ">=",
Oper::And => "&",
Oper::Or => "|",
Oper::Xor => "^",
Oper::Lsh => "<<",
Oper::Rsh => ">>",
}
}
fn to_hvm1(&self) -> &'static str {
match self {
Oper::Add => "ADD",
Oper::Sub => "SUB",
Oper::Mul => "MUL",
Oper::Div => "DIV",
Oper::Mod => "MOD",
Oper::Eq => "EQ",
Oper::Ne => "NE",
Oper::Lt => "LT",
Oper::Gt => "GT",
Oper::Lte => "LTE",
Oper::Gte => "GTE",
Oper::And => "AND",
Oper::Or => "OR",
Oper::Xor => "XOR",
Oper::Lsh => "LSH",
Oper::Rsh => "RSH",
}
}
}
impl Term {
fn show(&self) -> String {
match self {
Term::All { nam, inp, bod } => format!("∀({}: {}) {}", nam, inp.show(), bod.show()),
Term::Lam { nam, bod } => format!("λ{} {}", nam, bod.show()),
Term::App { fun, arg } => format!("({} {})", fun.show(), arg.show()),
Term::Ann { val, typ } => format!("{{{}: {}}}", val.show(), typ.show()),
Term::Slf { nam, typ, bod } => format!("$({}: {}) {}", nam, typ.show(), bod.show()),
Term::Ins { val } => format!("~{}", val.show()),
Term::Set => "*".to_string(),
Term::U60 => "#U60".to_string(),
Term::Num { val } => format!("#{}", val),
Term::Op2 { opr, fst, snd } => format!("#({} {} {})", opr.show(), fst.show(), snd.show()),
Term::Mat { nam, x, z, s, p } => format!("#match {} = {} {{ #0: {}; #+: {} }}: {}", nam, x.show(), z.show(), s.show(), p.show()),
Term::Txt { txt } => format!("\"{}\"", txt),
Term::Let { nam, val, bod } => format!("let {} = {} in {}", nam, val.show(), bod.show()),
Term::Hol { nam } => format!("?{}", nam),
Term::Met {} => format!("_"),
Term::Var { nam } => nam.clone(),
Term::Src { src: _, val } => val.show(),
}
}
fn to_hvm1(&self, env: im::Vector<String>, met: &mut usize) -> String {
fn binder(name: &str) -> String {
format!("x{}", name.replace("-", "._."))
}
match self {
Term::All { nam, inp, bod } => format!("(All \"{}\" {} λ{} {})", nam, inp.to_hvm1(env.clone(),met), binder(nam), bod.to_hvm1(cons(&env, nam.clone()),met)),
Term::Lam { nam, bod } => format!("(Lam \"{}\" λ{} {})", nam, binder(nam), bod.to_hvm1(cons(&env, nam.clone()),met)),
Term::App { fun, arg } => format!("(App {} {})", fun.to_hvm1(env.clone(),met), arg.to_hvm1(env.clone(),met)),
Term::Ann { val, typ } => format!("(Ann {} {})", val.to_hvm1(env.clone(),met), typ.to_hvm1(env.clone(),met)),
Term::Slf { nam, typ, bod } => format!("(Slf \"{}\" {} λ{} {})", nam, typ.to_hvm1(env.clone(),met), binder(nam), bod.to_hvm1(cons(&env, nam.clone()),met)),
Term::Ins { val } => format!("(Ins {})", val.to_hvm1(env.clone(),met)),
Term::Set => "(Set)".to_string(),
Term::U60 => "(U60)".to_string(),
Term::Num { val } => format!("(Num {})", val),
Term::Op2 { opr, fst, snd } => format!("(Op2 {} {} {})", opr.to_hvm1(), fst.to_hvm1(env.clone(),met), snd.to_hvm1(env.clone(),met)),
Term::Mat { nam, x, z, s, p } => format!("(Mat \"{}\" {} {} λ{} {} λ{} {})", nam, x.to_hvm1(env.clone(),met), z.to_hvm1(env.clone(),met), binder(&format!("{}-1",nam)), s.to_hvm1(cons(&env, format!("{}-1",nam)),met), binder(nam), p.to_hvm1(cons(&env, nam.clone()),met)),
Term::Txt { txt } => format!("(Txt \"{}\")", txt),
Term::Let { nam, val, bod } => format!("(Let \"{}\" {} λ{} {})", nam, val.to_hvm1(env.clone(),met), binder(nam), bod.to_hvm1(cons(&env, nam.clone()),met)),
Term::Hol { nam } => format!("(Hol \"{}\" [{}])", nam, env.iter().map(|n| binder(n)).collect::<Vec<_>>().join(",")),
Term::Met {} => { let n = *met; *met += 1; format!("(Met \"{}\" {})", n, format!("_{}",n)) },
Term::Var { nam } => if env.contains(nam) { format!("{}", binder(nam)) } else { format!("(Book.{})", nam) },
Term::Src { src, val } => format!("(Src {} {})", src, val.to_hvm1(env,met)),
}
}
fn get_free_vars(&self, env: im::Vector<String>, free_vars: &mut BTreeSet<String>) {
match self {
Term::All { nam, inp, bod } => {
inp.get_free_vars(env.clone(), free_vars);
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Lam { nam, bod } => {
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::App { fun, arg } => {
fun.get_free_vars(env.clone(), free_vars);
arg.get_free_vars(env.clone(), free_vars);
},
Term::Ann { val, typ } => {
val.get_free_vars(env.clone(), free_vars);
typ.get_free_vars(env.clone(), free_vars);
},
Term::Slf { nam, typ, bod } => {
typ.get_free_vars(env.clone(), free_vars);
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Ins { val } => {
val.get_free_vars(env.clone(), free_vars);
},
Term::Set => {},
Term::U60 => {},
Term::Num { val: _ } => {},
Term::Op2 { opr: _, fst, snd } => {
fst.get_free_vars(env.clone(), free_vars);
snd.get_free_vars(env.clone(), free_vars);
},
Term::Mat { nam, x, z, s, p } => {
x.get_free_vars(env.clone(), free_vars);
z.get_free_vars(env.clone(), free_vars);
s.get_free_vars(cons(&env, format!("{}-1",nam)), free_vars);
p.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Txt { txt: _ } => {},
Term::Let { nam, val, bod } => {
val.get_free_vars(env.clone(), free_vars);
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Hol { nam: _ } => {},
Term::Met {} => {},
Term::Src { src: _, val } => {
val.get_free_vars(env, free_vars);
},
Term::Var { nam } => {
if !env.contains(nam) {
free_vars.insert(nam.clone());
}
},
}
}
fn count_metas(&self) -> usize {
match self {
Term::All { nam: _, inp, bod } => { inp.count_metas() + bod.count_metas() }
Term::Lam { nam: _, bod } => { bod.count_metas() },
Term::App { fun, arg } => { fun.count_metas() + arg.count_metas() },
Term::Ann { val, typ } => { val.count_metas() + typ.count_metas() },
Term::Slf { nam: _, typ, bod } => { typ.count_metas() + bod.count_metas() },
Term::Ins { val } => { val.count_metas() },
Term::Set => 0,
Term::U60 => 0,
Term::Num { val: _ } => 0,
Term::Op2 { opr: _, fst, snd } => { fst.count_metas() + snd.count_metas() },
Term::Mat { nam: _, x, z, s, p } => { x.count_metas() + z.count_metas() + s.count_metas() + p.count_metas() },
Term::Txt { txt: _ } => 0,
Term::Let { nam: _, val, bod } => { val.count_metas() + bod.count_metas() },
Term::Hol { nam: _ } => 0,
Term::Met {} => 1,
Term::Var { nam: _ } => 0,
Term::Src { src: _, val } => { val.count_metas() }
}
}
}
impl Message {
fn show(&self) -> String {
match self {
Message::Found { nam, typ, ctx } => {
let ctx = ctx.iter().map(|x| x.show()).collect::<Vec<_>>().join(" ");
format!("#found{{?{} {} [{}]}}", nam, typ.show(), ctx)
},
Message::Error { exp, det, bad, src } => {
format!("#error{{{} {} {} {}}}", exp.show(), det.show(), bad.show(), src)
},
Message::Solve { nam, val } => {
format!("#solve{{_{} {}}}", nam, val.show())
},
Message::Vague { nam } => {
format!("#vague{{?{}}}", nam)
}
}
}
fn pretty(&self, book: &Book) -> String {
match self {
Message::Found { nam, typ, ctx } => {
let msg = format!("?{} :: {}", nam, typ.show());
let ctx = ctx.iter().map(|x| x.show()).collect::<Vec<_>>().join("\n- ");
format!("\x1b[1mHOLE:\x1b[0m {}{}", msg, ctx)
},
Message::Error { exp, det, bad, src } => {
let exp = format!("- expected: \x1b[32m{}\x1b[0m", exp.show());
let det = format!("- detected: \x1b[31m{}\x1b[0m", det.show());
let bad = format!("- bad_term: \x1b[2m{}\x1b[0m", bad.show());
let file = book.get_file_name(src_fid(*src)).unwrap_or_else(|| "unknown_file".to_string());
let text = std::fs::read_to_string(&file).unwrap_or_else(|_| "Could not read source file.".to_string());
let orig = highlight_error(src_ini(*src) as usize, src_end(*src) as usize, &text);
let src = format!("\x1b[4m{}\x1b[0m\n{}", file, orig);
format!("\x1b[1mERROR:\x1b[0m\n{}\n{}\n{}\n{}", exp, det, bad, src)
},
Message::Solve { nam, val } => {
format!("SOLVE: _{} = {}", nam, val.show())
},
Message::Vague { nam } => {
format!("VAGUE: _{}", nam)
}
}
}
}
TSPL::new_parser!(KindParser);
impl<'i> KindParser<'i> {
fn parse_oper(&mut self) -> Result<Oper, String> {
self.skip_trivia();
match self.peek_one() {
Some('+') => { self.advance_one(); Ok(Oper::Add) }
Some('-') => { self.advance_one(); Ok(Oper::Sub) }
Some('*') => { self.advance_one(); Ok(Oper::Mul) }
Some('/') => { self.advance_one(); Ok(Oper::Div) }
Some('%') => { self.advance_one(); Ok(Oper::Mod) }
Some('=') => { self.consume("==")?; Ok(Oper::Eq) }
Some('!') => { self.consume("!=")?; Ok(Oper::Ne) }
Some('<') => {
match self.peek_many(2) {
Some("<=") => { self.advance_many(2); Ok(Oper::Lte) }
Some("<<") => { self.advance_many(2); Ok(Oper::Lsh) }
_ => { self.advance_one(); Ok(Oper::Lt) }
}
}
Some('>') => {
match self.peek_many(2) {
Some(">=") => { self.advance_many(2); Ok(Oper::Gte) }
Some(">>") => { self.advance_many(2); Ok(Oper::Rsh) }
_ => { self.advance_one(); Ok(Oper::Gt) }
}
}
Some('&') => { self.advance_one(); Ok(Oper::And) }
Some('|') => { self.advance_one(); Ok(Oper::Or) }
Some('^') => { self.advance_one(); Ok(Oper::Xor) }
_ => self.expected("operator"),
}
}
fn parse_term(&mut self, fid: u64) -> Result<Term, String> {
self.skip_trivia();
match self.peek_one() {
Some('∀') => {
let ini = *self.index() as u64;
self.consume("")?;
self.consume("(")?;
let nam = self.parse_name()?;
self.consume(":")?;
let inp = Box::new(self.parse_term(fid)?);
self.consume(")")?;
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::All { nam, inp, bod }) })
}
Some('λ') => {
let ini = *self.index() as u64;
self.consume("λ")?;
let nam = self.parse_name()?;
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Lam { nam, bod }) })
}
Some('(') => {
let ini = *self.index() as u64;
self.consume("(")?;
let fun = Box::new(self.parse_term(fid)?);
let mut args = Vec::new();
while self.peek_one() != Some(')') {
args.push(Box::new(self.parse_term(fid)?));
self.skip_trivia();
}
self.consume(")")?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
let mut app = fun;
for arg in args {
app = Box::new(Term::App { fun: app, arg });
}
Ok(Term::Src { src, val: app })
}
Some('{') => {
let ini = *self.index() as u64;
self.consume("{")?;
let val = Box::new(self.parse_term(fid)?);
self.consume(":")?;
let typ = Box::new(self.parse_term(fid)?);
self.consume("}")?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Ann { val, typ }) })
}
Some('$') => {
let ini = *self.index() as u64;
self.consume("$")?;
self.consume("(")?;
let nam = self.parse_name()?;
self.consume(":")?;
let typ = Box::new(self.parse_term(fid)?);
self.consume(")")?;
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Slf { nam, typ, bod }) })
}
Some('~') => {
let ini = *self.index() as u64;
self.consume("~")?;
let val = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Ins { val }) })
}
Some('*') => {
let ini = *self.index() as u64;
self.consume("*")?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Set) })
}
Some('#') => {
let ini = *self.index() as u64;
self.consume("#")?;
match self.peek_one() {
Some('U') => {
self.consume("U60")?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::U60) })
}
Some('(') => {
self.consume("(")?;
let opr = self.parse_oper()?;
let fst = Box::new(self.parse_term(fid)?);
let snd = Box::new(self.parse_term(fid)?);
self.consume(")")?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Op2 { opr, fst, snd }) })
}
Some('m') => {
self.consume("match")?;
let nam = self.parse_name()?;
self.consume("=")?;
let x = Box::new(self.parse_term(fid)?);
self.consume("{")?;
self.consume("#0")?;
self.consume(":")?;
let z = Box::new(self.parse_term(fid)?);
self.consume("#+")?;
self.consume(":")?;
let s = Box::new(self.parse_term(fid)?);
self.consume("}")?;
self.consume(":")?;
let p = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Mat { nam, x, z, s, p }) })
}
Some(_) => {
let val = self.parse_u64()?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Num { val }) })
}
_ => {
self.expected("numeric-expression")
}
}
}
Some('?') => {
let ini = *self.index() as u64;
self.consume("?")?;
let nam = self.parse_name()?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Hol { nam }) })
}
Some('_') => {
let ini = *self.index() as u64;
self.consume("_")?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Met {}) })
}
Some('\'') => {
let ini = *self.index() as u64;
let chr = self.parse_quoted_char()?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Num { val: chr as u64 }) })
}
Some('"') => {
let ini = *self.index() as u64;
let txt = self.parse_quoted_string()?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Txt { txt }) })
}
_ => {
if self.peek_many(4) == Some("let ") {
let ini = *self.index() as u64;
self.advance_many(4);
let nam = self.parse_name()?;
self.consume("=")?;
let val = Box::new(self.parse_term(fid)?);
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Let { nam, val, bod }) })
} else {
let ini = *self.index() as u64;
let nam = self.parse_name()?;
let end = *self.index() as u64;
let src = new_src(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Var { nam }) })
}
}
}
}
fn parse_def(&mut self, fid: u64) -> Result<(String, Term), String> {
self.skip_trivia();
let nam = self.parse_name()?;
self.skip_trivia();
if self.peek_one() == Some(':') {
self.consume(":")?;
let typ = self.parse_term(fid)?;
self.consume("=")?;
let val = self.parse_term(fid)?;
Ok((nam, Term::Ann { val: Box::new(val), typ: Box::new(typ) }))
} else {
self.consume("=")?;
let val = self.parse_term(fid)?;
Ok((nam, val))
}
}
fn parse_book(&mut self, fid: u64) -> Result<Book, String> {
let mut book = Book::new();
while *self.index() < self.input().len() {
let (name, term) = self.parse_def(fid)?;
book.defs.insert(name, term);
self.skip_trivia();
}
Ok(book)
}
fn parse_message(&mut self) -> Result<Message, String> {
self.skip_trivia();
match self.peek_one() {
Some('#') => {
self.consume("#")?;
match self.peek_one() {
Some('f') => {
self.consume("found")?;
self.consume("{")?;
let nam = self.parse_name()?;
let typ = self.parse_term(0)?;
self.consume("[")?;
let mut ctx = Vec::new();
while self.peek_one() != Some(']') {
ctx.push(self.parse_term(0)?);
self.skip_trivia();
}
self.consume("]")?;
self.consume("}")?;
Ok(Message::Found { nam, typ, ctx })
}
Some('e') => {
self.consume("error")?;
self.consume("{")?;
let exp = self.parse_term(0)?;
let det = self.parse_term(0)?;
let bad = self.parse_term(0)?;
let src = self.parse_u64()?;
self.consume("}")?;
Ok(Message::Error {
exp: exp,
det: det,
bad: bad,
src: src,
})
}
Some('s') => {
self.consume("solve")?;
self.consume("{")?;
let nam = self.parse_name()?;
let val = self.parse_term(0)?;
self.consume("}")?;
Ok(Message::Solve { nam, val })
}
Some('v') => {
self.consume("vague")?;
self.consume("{")?;
let nam = self.parse_name()?;
self.consume("}")?;
Ok(Message::Vague { nam })
}
_ => self.expected("message type (solve, found, error)"),
}
}
_ => self.expected("# (start of message)"),
}
}
fn parse_messages(&mut self) -> Result<Vec<Message>, String> {
let mut messages = Vec::new();
while *self.index() < self.input().len() {
let parsed_message = self.parse_message();
match parsed_message {
Ok(msg) => {
messages.push(msg);
self.skip_trivia();
}
Err(_) => {
break;
}
}
}
Ok(messages)
}
}
impl Book {
fn new() -> Self {
Book {
defs: BTreeMap::new(),
fids: BTreeMap::new(),
}
}
fn to_hvm1(&self) -> String {
let mut used = BTreeSet::new();
let mut code = String::new();
for (name, term) in &self.defs {
let metas = term.count_metas();
let mut lams = String::new();
for i in 0 .. term.count_metas() {
lams = format!("{} λ_{}", lams, i);
}
let subs = (0 .. metas).map(|h| format!("(Pair \"{}\" None)", h)).collect::<Vec<_>>().join(",");
code.push_str(&format!("Book.{} = (Ref \"{}\" [{}] {}{})\n", name, name, subs, lams, term.to_hvm1(im::Vector::new(), &mut 0)));
used.insert(name.clone());
}
code
}
fn show(&self) -> String {
let mut book_str = String::new();
for (name, term) in &self.defs {
book_str.push_str(&format!("{} = {}\n", name, term.show()));
}
book_str
}
fn load(name: &str) -> Result<Self, String> {
fn load_go(name: &str, book: &mut Book) -> Result<(), String> {
//println!("... {}", name);
if !book.defs.contains_key(name) {
let file = format!("./{}.kind2", name);
let text = std::fs::read_to_string(&file).map_err(|_| format!("Could not read file: {}", file))?;
let fid = book.get_file_id(&file);
//println!("... parsing: {}", name);
let defs = KindParser::new(&text).parse_book(fid)?;
//println!("... parsed: {}", name);
for (def_name, def_value) in &defs.defs {
book.defs.insert(def_name.clone(), def_value.clone());
}
//println!("laoding deps for: {}", name);
for (_, def_term) in defs.defs.into_iter() {
let mut dependencies = BTreeSet::new();
def_term.get_free_vars(im::Vector::new(), &mut dependencies);
//println!("{} deps: {:?}", name, dependencies);
for ref_name in dependencies {
load_go(&ref_name, book)?;
}
}
}
return Ok(());
}
let mut book = Book::new();
load_go(name, &mut book)?;
load_go("String", &mut book)?;
load_go("String.cons", &mut book)?;
load_go("String.nil", &mut book)?;
//println!("DONE!");
Ok(book)
}
fn get_file_id(&mut self, name: &str) -> u64 {
if let Some(id) = self.fids.get(name) {
*id
} else {
let id = self.fids.len() as u64 + 1;
self.fids.insert(name.to_string(), id);
id
}
}
// FIXME: asymptotics
fn get_file_name(&self, id: u64) -> Option<String> {
for (name, &fid) in &self.fids {
if fid == id {
return Some(name.clone());
}
}
None
}
//fn inject_sources(&self, input: &str) -> Result<String, String> {
//let mut result = input.to_string();
//let ini_sym = "##LOC{";
//let end_sym = "}LOC##";
//while let (Some(ini), Some(end)) = (result.find(ini_sym), result.find(end_sym)) {
//let got = &result[ini + ini_sym.len()..end];
//let loc = got.parse::<u64>().map_err(|_| "Failed to parse location")?;
//let fid = src_fid(loc);
//let ini = src_ini(loc) as usize;
//let end = src_end(loc) as usize;
//if loc == 0 {
//result = result.replace(&format!("{}{}{}", ini_sym, got, end_sym), "");
//} else if let Some(file_name) = self.get_file_name(fid) {
//let source_file = std::fs::read_to_string(&file_name).map_err(|_| "Failed to read source file")?;
//let context_str = highlight_error(ini, end, &source_file);
//let context_str = format!("\x1b[4m{}\x1b[0m\n{}", file_name, context_str);
//result = result.replace(&format!("{}{}{}", ini_sym, got, end_sym), &context_str);
//} else {
//return Err("File ID not found".to_string());
//}
//}
//Ok(result)
//}
}
fn generate_check_hvm1(book: &Book, command: &str, arg: &str) -> String {
//let used_defs = book.defs.keys().collect::<Vec<_>>().iter().map(|name| format!("(Pair \"{}\" Book.{})", name, name)).collect::<Vec<_>>().join(" ");
let kind_hvm1 = include_str!("./kind2.hvm1");
@ -805,6 +47,8 @@ fn main() {
"check" | "run" => {
match Book::load(arg) {
Ok(book) => {
println!("{}", book.show());
// Generates the HVM1 checker.
let check_hvm1 = generate_check_hvm1(&book, cmd, arg);
let mut file = File::create(".check.hvm1").expect("Failed to create '.check.hvm1'.");
@ -815,8 +59,8 @@ fn main() {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
// Parses and print stdout messages.
let parsed = KindParser::new(&stdout).parse_messages();
// Parses and print stdout infos.
let parsed = KindParser::new(&stdout).parse_infos();
match parsed {
Ok(msgs) => {
for msg in &msgs {

228
src/term/mod.rs Normal file
View File

@ -0,0 +1,228 @@
use crate::{*};
use std::collections::BTreeSet;
mod parse;
mod show;
mod to_hvm1;
#[derive(Clone, Copy, Debug)]
pub enum Oper {
Add , Sub , Mul , Div ,
Mod , Eq , Ne , Lt ,
Gt , Lte , Gte , And ,
Or , Xor , Lsh , Rsh ,
}
#[derive(Clone, Debug)]
pub struct Src {
pub ini: u64,
pub end: u64,
pub fid: u64,
}
// <term> ::=
// ALL | ∀(<name>: <term>) <term>
// LAM | λ<name> <term>
// APP | (<term> <term>)
// ANN | {<term>: <term>}
// SLF | $(<name>: <term>) <term>
// INS | ~<term>
// SET | *
// U60 | #U60
// NUM | #<uint>
// OP2 | #(<oper> <term> <term>)
// MAT | #match <name> = <term> { #0: <term>; #+: <term> }: <term>
// MET | ?<name>
// HOL | _
// CHR | '<char>'
// STR | "<string>"
// LET | let <name> = <term> <term>
// VAR | <name>
#[derive(Clone, Debug)]
pub enum Term {
All { nam: String, inp: Box<Term>, bod: Box<Term> },
Lam { nam: String, bod: Box<Term> },
App { fun: Box<Term>, arg: Box<Term> },
Ann { val: Box<Term>, typ: Box<Term> },
Slf { nam: String, typ: Box<Term>, bod: Box<Term> },
Ins { val: Box<Term> },
Set,
U60,
Num { val: u64 },
Op2 { opr: Oper, fst: Box<Term>, snd: Box<Term> },
Mat { nam: String, x: Box<Term>, z: Box<Term>, s: Box<Term>, p: Box<Term> },
Txt { txt: String },
Let { nam: String, val: Box<Term>, bod: Box<Term> },
Var { nam: String },
Hol { nam: String },
Met {},
Src { src: Src, val: Box<Term> },
}
impl Src {
pub fn new(fid: u64, ini: u64, end: u64) -> Self {
Src { ini, end, fid }
}
pub fn to_u64(&self) -> u64 {
(self.fid << 40) | (self.ini << 20) | self.end
}
pub fn from_u64(src: u64) -> Self {
let fid = src >> 40;
let ini = (src >> 20) & 0xFFFFF;
let end = src & 0xFFFFF;
Src { ini, end, fid }
}
}
fn name(numb: usize) -> String {
let mut name = String::new();
let mut numb = numb as i64;
loop {
name.insert(0, ((97 + (numb % 26)) as u8) as char);
numb = numb / 26 - 1;
if numb < 0 { break; }
}
name
}
pub fn cons<A>(vector: &im::Vector<A>, value: A) -> im::Vector<A> where A: Clone {
let mut new_vector = vector.clone();
new_vector.push_back(value);
new_vector
}
impl Term {
pub fn get_free_vars(&self, env: im::Vector<String>, free_vars: &mut BTreeSet<String>) {
match self {
Term::All { nam, inp, bod } => {
inp.get_free_vars(env.clone(), free_vars);
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Lam { nam, bod } => {
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::App { fun, arg } => {
fun.get_free_vars(env.clone(), free_vars);
arg.get_free_vars(env.clone(), free_vars);
},
Term::Ann { val, typ } => {
val.get_free_vars(env.clone(), free_vars);
typ.get_free_vars(env.clone(), free_vars);
},
Term::Slf { nam, typ, bod } => {
typ.get_free_vars(env.clone(), free_vars);
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Ins { val } => {
val.get_free_vars(env.clone(), free_vars);
},
Term::Set => {},
Term::U60 => {},
Term::Num { val: _ } => {},
Term::Op2 { opr: _, fst, snd } => {
fst.get_free_vars(env.clone(), free_vars);
snd.get_free_vars(env.clone(), free_vars);
},
Term::Mat { nam, x, z, s, p } => {
x.get_free_vars(env.clone(), free_vars);
z.get_free_vars(env.clone(), free_vars);
s.get_free_vars(cons(&env, format!("{}-1",nam)), free_vars);
p.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Txt { txt: _ } => {},
Term::Let { nam, val, bod } => {
val.get_free_vars(env.clone(), free_vars);
bod.get_free_vars(cons(&env, nam.clone()), free_vars);
},
Term::Hol { nam: _ } => {},
Term::Met {} => {},
Term::Src { src: _, val } => {
val.get_free_vars(env, free_vars);
},
Term::Var { nam } => {
if !env.contains(nam) {
free_vars.insert(nam.clone());
}
},
}
}
pub fn count_metas(&self) -> usize {
match self {
Term::All { inp, bod, .. } => {
let inp = inp.count_metas();
let bod = bod.count_metas();
inp + bod
},
Term::Lam { bod, .. } => {
let bod = bod.count_metas();
bod
},
Term::App { fun, arg } => {
let fun = fun.count_metas();
let arg = arg.count_metas();
fun + arg
},
Term::Ann { val, typ } => {
let val = val.count_metas();
let typ = typ.count_metas();
val + typ
},
Term::Slf { typ, bod, .. } => {
let typ = typ.count_metas();
let bod = bod.count_metas();
typ + bod
},
Term::Ins { val } => {
let val = val.count_metas();
val
},
Term::Set => {
0
},
Term::U60 => {
0
},
Term::Num { .. } => {
0
},
Term::Op2 { fst, snd, .. } => {
let fst = fst.count_metas();
let snd = snd.count_metas();
fst + snd
},
Term::Mat { x, z, s, p, .. } => {
let x = x.count_metas();
let z = z.count_metas();
let s = s.count_metas();
let p = p.count_metas();
x + z + s + p
},
Term::Txt { .. } => {
0
},
Term::Let { val, bod, .. } => {
let val = val.count_metas();
let bod = bod.count_metas();
val + bod
},
Term::Hol { .. } => {
0
},
Term::Met { .. } => {
1
},
Term::Var { .. } => {
0
},
Term::Src { val, .. } => {
let val = val.count_metas();
val
},
}
}
}

219
src/term/parse.rs Normal file
View File

@ -0,0 +1,219 @@
use crate::{*};
impl<'i> KindParser<'i> {
pub fn parse_oper(&mut self) -> Result<Oper, String> {
self.skip_trivia();
match self.peek_one() {
Some('+') => { self.advance_one(); Ok(Oper::Add) }
Some('-') => { self.advance_one(); Ok(Oper::Sub) }
Some('*') => { self.advance_one(); Ok(Oper::Mul) }
Some('/') => { self.advance_one(); Ok(Oper::Div) }
Some('%') => { self.advance_one(); Ok(Oper::Mod) }
Some('=') => { self.consume("==")?; Ok(Oper::Eq) }
Some('!') => { self.consume("!=")?; Ok(Oper::Ne) }
Some('<') => {
match self.peek_many(2) {
Some("<=") => { self.advance_many(2); Ok(Oper::Lte) }
Some("<<") => { self.advance_many(2); Ok(Oper::Lsh) }
_ => { self.advance_one(); Ok(Oper::Lt) }
}
}
Some('>') => {
match self.peek_many(2) {
Some(">=") => { self.advance_many(2); Ok(Oper::Gte) }
Some(">>") => { self.advance_many(2); Ok(Oper::Rsh) }
_ => { self.advance_one(); Ok(Oper::Gt) }
}
}
Some('&') => { self.advance_one(); Ok(Oper::And) }
Some('|') => { self.advance_one(); Ok(Oper::Or) }
Some('^') => { self.advance_one(); Ok(Oper::Xor) }
_ => self.expected("operator"),
}
}
pub fn parse_term(&mut self, fid: u64) -> Result<Term, String> {
self.skip_trivia();
match self.peek_one() {
Some('∀') => {
let ini = *self.index() as u64;
self.consume("")?;
self.consume("(")?;
let nam = self.parse_name()?;
self.consume(":")?;
let inp = Box::new(self.parse_term(fid)?);
self.consume(")")?;
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::All { nam, inp, bod }) })
}
Some('λ') => {
let ini = *self.index() as u64;
self.consume("λ")?;
let nam = self.parse_name()?;
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Lam { nam, bod }) })
}
Some('(') => {
let ini = *self.index() as u64;
self.consume("(")?;
let fun = Box::new(self.parse_term(fid)?);
let mut args = Vec::new();
while self.peek_one() != Some(')') {
args.push(Box::new(self.parse_term(fid)?));
self.skip_trivia();
}
self.consume(")")?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
let mut app = fun;
for arg in args {
app = Box::new(Term::App { fun: app, arg });
}
Ok(Term::Src { src, val: app })
}
Some('{') => {
let ini = *self.index() as u64;
self.consume("{")?;
let val = Box::new(self.parse_term(fid)?);
self.consume(":")?;
let typ = Box::new(self.parse_term(fid)?);
self.consume("}")?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Ann { val, typ }) })
}
Some('$') => {
let ini = *self.index() as u64;
self.consume("$")?;
self.consume("(")?;
let nam = self.parse_name()?;
self.consume(":")?;
let typ = Box::new(self.parse_term(fid)?);
self.consume(")")?;
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Slf { nam, typ, bod }) })
}
Some('~') => {
let ini = *self.index() as u64;
self.consume("~")?;
let val = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Ins { val }) })
}
Some('*') => {
let ini = *self.index() as u64;
self.consume("*")?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Set) })
}
Some('#') => {
let ini = *self.index() as u64;
self.consume("#")?;
match self.peek_one() {
Some('U') => {
self.consume("U60")?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::U60) })
}
Some('(') => {
self.consume("(")?;
let opr = self.parse_oper()?;
let fst = Box::new(self.parse_term(fid)?);
let snd = Box::new(self.parse_term(fid)?);
self.consume(")")?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Op2 { opr, fst, snd }) })
}
Some('m') => {
self.consume("match")?;
let nam = self.parse_name()?;
self.consume("=")?;
let x = Box::new(self.parse_term(fid)?);
self.consume("{")?;
self.consume("#0")?;
self.consume(":")?;
let z = Box::new(self.parse_term(fid)?);
self.consume("#+")?;
self.consume(":")?;
let s = Box::new(self.parse_term(fid)?);
self.consume("}")?;
self.consume(":")?;
let p = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Mat { nam, x, z, s, p }) })
}
Some(_) => {
let val = self.parse_u64()?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Num { val }) })
}
_ => {
self.expected("numeric-expression")
}
}
}
Some('?') => {
let ini = *self.index() as u64;
self.consume("?")?;
let nam = self.parse_name()?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Hol { nam }) })
}
Some('_') => {
let ini = *self.index() as u64;
self.consume("_")?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Met {}) })
}
Some('\'') => {
let ini = *self.index() as u64;
let chr = self.parse_quoted_char()?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Num { val: chr as u64 }) })
}
Some('"') => {
let ini = *self.index() as u64;
let txt = self.parse_quoted_string()?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Txt { txt }) })
}
_ => {
if self.peek_many(4) == Some("let ") {
let ini = *self.index() as u64;
self.advance_many(4);
let nam = self.parse_name()?;
self.consume("=")?;
let val = Box::new(self.parse_term(fid)?);
let bod = Box::new(self.parse_term(fid)?);
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Let { nam, val, bod }) })
} else {
let ini = *self.index() as u64;
let nam = self.parse_name()?;
let end = *self.index() as u64;
let src = Src::new(fid, ini, end);
Ok(Term::Src { src, val: Box::new(Term::Var { nam }) })
}
}
}
}
}

104
src/term/show.rs Normal file
View File

@ -0,0 +1,104 @@
use crate::{*};
impl Oper {
pub fn show(&self) -> &'static str {
match self {
Oper::Add => "+",
Oper::Sub => "-",
Oper::Mul => "*",
Oper::Div => "/",
Oper::Mod => "%",
Oper::Eq => "==",
Oper::Ne => "!=",
Oper::Lt => "<",
Oper::Gt => ">",
Oper::Lte => "<=",
Oper::Gte => ">=",
Oper::And => "&",
Oper::Or => "|",
Oper::Xor => "^",
Oper::Lsh => "<<",
Oper::Rsh => ">>",
}
}
}
impl Term {
pub fn show(&self) -> String {
match self {
Term::All { nam, inp, bod } => {
let inp = inp.show();
let bod = bod.show();
format!("∀({}: {}) {}", nam, inp, bod)
},
Term::Lam { nam, bod } => {
let bod = bod.show();
format!("λ{} {}", nam, bod)
},
Term::App { fun, arg } => {
let fun = fun.show();
let arg = arg.show();
format!("({} {})", fun, arg)
},
Term::Ann { val, typ } => {
let val = val.show();
let typ = typ.show();
format!("{{{}: {}}}", val, typ)
},
Term::Slf { nam, typ, bod } => {
let typ = typ.show();
let bod = bod.show();
format!("$({}: {}) {}", nam, typ, bod)
},
Term::Ins { val } => {
let val = val.show();
format!("~{}", val)
},
Term::Set => {
"*".to_string()
},
Term::U60 => {
"#U60".to_string()
},
Term::Num { val } => {
format!("#{}", val)
},
Term::Op2 { opr, fst, snd } => {
let fst = fst.show();
let snd = snd.show();
format!("#({} {} {})", opr.show(), fst, snd)
},
Term::Mat { nam, x, z, s, p } => {
let x = x.show();
let z = z.show();
let s = s.show();
let p = p.show();
format!("#match {} = {} {{ #0: {}; #+: {} }}: {}", nam, x, z, s, p)
},
Term::Txt { txt } => {
format!("\"{}\"", txt)
},
Term::Let { nam, val, bod } => {
let val = val.show();
let bod = bod.show();
format!("let {} = {} in {}", nam, val, bod)
},
Term::Hol { nam } => {
format!("?{}", nam)
},
Term::Met {} => {
format!("_")
},
Term::Var { nam } => {
nam.clone()
},
Term::Src { src: _, val } => {
val.show()
},
}
}
}

115
src/term/to_hvm1.rs Normal file
View File

@ -0,0 +1,115 @@
use crate::{*};
impl Oper {
pub fn to_hvm1(&self) -> &'static str {
match self {
Oper::Add => "ADD",
Oper::Sub => "SUB",
Oper::Mul => "MUL",
Oper::Div => "DIV",
Oper::Mod => "MOD",
Oper::Eq => "EQ",
Oper::Ne => "NE",
Oper::Lt => "LT",
Oper::Gt => "GT",
Oper::Lte => "LTE",
Oper::Gte => "GTE",
Oper::And => "AND",
Oper::Or => "OR",
Oper::Xor => "XOR",
Oper::Lsh => "LSH",
Oper::Rsh => "RSH",
}
}
}
impl Term {
pub fn to_hvm1(&self, env: im::Vector<String>, met: &mut usize) -> String {
fn binder(name: &str) -> String {
format!("x{}", name.replace("-", "._."))
}
match self {
Term::All { nam, inp, bod } => {
let inp = inp.to_hvm1(env.clone(), met);
let bod = bod.to_hvm1(cons(&env, nam.clone()), met);
format!("(All \"{}\" {} λ{} {})", nam, inp, binder(nam), bod)
},
Term::Lam { nam, bod } => {
let bod = bod.to_hvm1(cons(&env, nam.clone()), met);
format!("(Lam \"{}\" λ{} {})", nam, binder(nam), bod)
},
Term::App { fun, arg } => {
let fun = fun.to_hvm1(env.clone(), met);
let arg = arg.to_hvm1(env.clone(), met);
format!("(App {} {})", fun, arg)
},
Term::Ann { val, typ } => {
let val = val.to_hvm1(env.clone(), met);
let typ = typ.to_hvm1(env.clone(), met);
format!("(Ann {} {})", val, typ)
},
Term::Slf { nam, typ, bod } => {
let typ = typ.to_hvm1(env.clone(), met);
let bod = bod.to_hvm1(cons(&env, nam.clone()), met);
format!("(Slf \"{}\" {} λ{} {})", nam, typ, binder(nam), bod)
},
Term::Ins { val } => {
let val = val.to_hvm1(env.clone(), met);
format!("(Ins {})", val)
},
Term::Set => {
"(Set)".to_string()
},
Term::U60 => {
"(U60)".to_string()
},
Term::Num { val } => {
format!("(Num {})", val)
},
Term::Op2 { opr, fst, snd } => {
let fst = fst.to_hvm1(env.clone(), met);
let snd = snd.to_hvm1(env.clone(), met);
format!("(Op2 {} {} {})", opr.to_hvm1(), fst, snd)
},
Term::Mat { nam, x, z, s, p } => {
let x = x.to_hvm1(env.clone(), met);
let z = z.to_hvm1(env.clone(), met);
let s = s.to_hvm1(cons(&env, format!("{}-1", nam)), met);
let p = p.to_hvm1(cons(&env, nam.clone()), met);
format!("(Mat \"{}\" {} {} λ{} {} λ{} {})", nam, x, z, binder(&format!("{}-1", nam)), s, binder(nam), p)
},
Term::Txt { txt } => {
format!("(Txt \"{}\")", txt)
},
Term::Let { nam, val, bod } => {
let val = val.to_hvm1(env.clone(), met);
let bod = bod.to_hvm1(cons(&env, nam.clone()), met);
format!("(Let \"{}\" {} λ{} {})", nam, val, binder(nam), bod)
},
Term::Hol { nam } => {
let env_str = env.iter().map(|n| binder(n)).collect::<Vec<_>>().join(",");
format!("(Hol \"{}\" [{}])", nam, env_str)
},
Term::Met {} => {
let n = *met;
*met += 1;
format!("(Met \"{}\" {})", n, format!("_{}", n))
},
Term::Var { nam } => {
if env.contains(nam) {
format!("{}", binder(nam))
} else {
format!("(Book.{})", nam)
}
},
Term::Src { src, val } => {
let val = val.to_hvm1(env, met);
format!("(Src {} {})", src.to_u64(), val)
},
}
}
}