mirror of
https://github.com/HigherOrderCO/Kind.git
synced 2024-10-05 19:27:30 +03:00
reorganize repo, split files
This commit is contained in:
parent
10da6d2afb
commit
21dd404798
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
/target
|
||||
.tmp/
|
||||
.kind21/
|
||||
plans.txt
|
||||
.check.hvm1
|
||||
demo/
|
||||
|
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
@ -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
3
book/.fill.tmp
Normal 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
297
book/_main.kind2
Normal 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
83
src/book/mod.rs
Normal 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
35
src/book/parse.rs
Normal 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
13
src/book/show.rs
Normal 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
24
src/book/to_hvm1.rs
Normal 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
62
src/info/mod.rs
Normal 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
80
src/info/parse.rs
Normal 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
23
src/info/show.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
784
src/main.rs
784
src/main.rs
@ -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
228
src/term/mod.rs
Normal 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
219
src/term/parse.rs
Normal 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
104
src/term/show.rs
Normal 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
115
src/term/to_hvm1.rs
Normal 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)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user