mirror of
https://github.com/HigherOrderCO/Kind.git
synced 2024-10-03 18:27:13 +03:00
use-declarations with shadowing
This commit is contained in:
parent
dc993b5de0
commit
0c34404c0b
@ -50,4 +50,4 @@ BBT.balance.lft_heavier
|
||||
rgt
|
||||
)
|
||||
use tip = (BBT.tip K V)
|
||||
(~lft P bin tip)
|
||||
(~lft P bin tip)
|
||||
|
@ -15,4 +15,4 @@ BBT.get
|
||||
use gtn = λcmp λkey (BBT.get K V cmp key next.rgt)
|
||||
(~(cmp key next.key) P ltn eql gtn cmp key)
|
||||
use tip = (Maybe.none V)
|
||||
(~map P bin tip)
|
||||
(~map P bin tip)
|
||||
|
@ -1,7 +1,9 @@
|
||||
Bool.and
|
||||
: ∀(a: Bool) ∀(b: Bool) Bool
|
||||
= λa
|
||||
use P = λa ∀(b: Bool) Bool
|
||||
use true = λb b
|
||||
use false = λb Bool.false
|
||||
(~a P true false)
|
||||
Bool.and (a: Bool) (b: Bool) : Bool =
|
||||
match b {
|
||||
Bool.true: b
|
||||
Bool.false: Bool.false
|
||||
}
|
||||
//use P = λa ∀(b: Bool) Bool
|
||||
//use true = λb b
|
||||
//use false = λb Bool.false
|
||||
//((~a P true false) b)
|
||||
|
@ -1,3 +1,2 @@
|
||||
Bool.false
|
||||
: Bool
|
||||
= ~λP λt λf f
|
||||
Bool.false : Bool =
|
||||
~λP λt λf f
|
||||
|
@ -1,7 +1,3 @@
|
||||
Bool
|
||||
: *
|
||||
= $(self: Bool)
|
||||
∀(P: ∀(x: Bool) *)
|
||||
∀(true: (P Bool.true))
|
||||
∀(false: (P Bool.false))
|
||||
(P self)
|
||||
data Bool
|
||||
| true
|
||||
| false
|
||||
|
@ -1,3 +1,2 @@
|
||||
Bool.true
|
||||
: Bool
|
||||
= ~λP λt λf t
|
||||
Bool.true : Bool =
|
||||
~λP λt λf t
|
||||
|
@ -58,4 +58,4 @@ Kind.Term
|
||||
∀(var:
|
||||
∀(nam: String) ∀(idx: Nat) (P (Kind.var nam idx))
|
||||
)
|
||||
(P self)
|
||||
(P self)
|
||||
|
@ -1,7 +1,10 @@
|
||||
List.length
|
||||
: ∀(A: *) ∀(a: (List A)) Nat
|
||||
= λA λa
|
||||
match a {
|
||||
List.cons: (Nat.succ (List.length A a.tail))
|
||||
List.nil: Nat.zero
|
||||
use List.{cons,nil}
|
||||
use Nat.{succ,zero}
|
||||
|
||||
length A (xs: (List A)) : Nat =
|
||||
match xs {
|
||||
cons:
|
||||
(succ (length A xs.tail))
|
||||
nil:
|
||||
zero
|
||||
}
|
||||
|
8
book/Monad.new.kind2
Normal file
8
book/Monad.new.kind2
Normal file
@ -0,0 +1,8 @@
|
||||
Monad.new
|
||||
: ∀(M: ∀(T: *) *)
|
||||
∀(bind: ∀(A: *) ∀(B: *) ∀(a: (M A)) ∀(b: ∀(a: A) (M B)) (M B))
|
||||
∀(pure: ∀(A: *) ∀(a: A) (M A))
|
||||
(Monad M)
|
||||
= λM λbind λpure
|
||||
~λP λnew
|
||||
(new bind pure)
|
@ -1,3 +1,3 @@
|
||||
Nat.succ
|
||||
: ∀(n: Nat) Nat
|
||||
= λn ~λP λsucc λzero (succ n)
|
||||
= λn ~λP λsucc λzero (succ n)
|
||||
|
@ -1,3 +1,3 @@
|
||||
String
|
||||
: *
|
||||
= (List Char)
|
||||
= (List Char)
|
||||
|
@ -4,4 +4,4 @@ U60.abs_diff
|
||||
use P = λx #U60
|
||||
use true = #(- b a)
|
||||
use false = #(- a b)
|
||||
(~(U60.to_bool #(< a b)) P true false)
|
||||
(~(U60.to_bool #(< a b)) P true false)
|
||||
|
@ -6,4 +6,4 @@ U60.cmp
|
||||
Cmp
|
||||
(U60.if #(< a b) Cmp Cmp.gtn Cmp.ltn)
|
||||
Cmp.eql
|
||||
)
|
||||
)
|
||||
|
@ -4,4 +4,4 @@ U60.equal
|
||||
#match x = #(== a b) {
|
||||
#0: Bool.false
|
||||
#+: Bool.true
|
||||
}: Bool
|
||||
}: Bool
|
||||
|
@ -4,4 +4,4 @@ U60.from_nat
|
||||
use P = λx #U60
|
||||
use succ = λn.pred #(+ #1 (U60.from_nat n.pred))
|
||||
use zero = #0
|
||||
(~n P succ zero)
|
||||
(~n P succ zero)
|
||||
|
@ -1,3 +1,3 @@
|
||||
U60.min
|
||||
: ∀(a: #U60) ∀(b: #U60) #U60
|
||||
= λa λb (~(U60.to_bool #(< a b)) λx #U60 a b)
|
||||
= λa λb (~(U60.to_bool #(< a b)) λx #U60 a b)
|
||||
|
@ -8,17 +8,30 @@ mod parse;
|
||||
mod show;
|
||||
|
||||
// <book> ::=
|
||||
// DEF_ANN | <name> : <term> = <term> <book>
|
||||
// DEF_VAL | <name> = <term> <book>
|
||||
// END | <eof>
|
||||
// USE | use <alias> <book>
|
||||
// ADT | <adt> <book>
|
||||
// ANN | <name> : <term> = <term> <book>
|
||||
// DEF | <name> = <term> <book>
|
||||
// END | <eof>
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Book {
|
||||
pub defs: BTreeMap<String, Term>,
|
||||
pub fids: BTreeMap<String, u64>,
|
||||
}
|
||||
|
||||
// Shadows a name on the uses map
|
||||
pub fn shadow(key: &str, uses: &Uses) -> Uses {
|
||||
let mut uses = uses.clone();
|
||||
uses.insert(key.to_string(), key.to_string());
|
||||
return uses;
|
||||
}
|
||||
|
||||
// Maps short names ("cons") to full names ("Data.List.cons")
|
||||
pub type Uses = im::HashMap<String, String>;
|
||||
|
||||
impl Book {
|
||||
|
||||
// Creates an empty book
|
||||
pub fn new() -> Self {
|
||||
Book {
|
||||
defs: BTreeMap::new(),
|
||||
@ -26,43 +39,51 @@ impl Book {
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
// Creates a book, loading a term, its dependencies, and stdlib
|
||||
pub fn boot(name: &str) -> Result<Self, String> {
|
||||
let mut book = Book::new();
|
||||
book.load(name)?;
|
||||
book.load("String")?;
|
||||
book.load("String.cons")?;
|
||||
book.load("String.nil")?;
|
||||
book.load("Nat")?;
|
||||
book.load("Nat.succ")?;
|
||||
book.load("Nat.zero")?;
|
||||
return Ok(book);
|
||||
}
|
||||
|
||||
// Handles an unbound definition
|
||||
pub fn handle_unbound(&self, file: &str, name: &str) -> Result<(), String> {
|
||||
return Err(format!("ERROR\n- unbound: '{}'\n- on_file: {}", name, file));
|
||||
}
|
||||
|
||||
// Same as load, mutably adding to a 'book'
|
||||
pub fn load(&mut self, name: &str) -> Result<(), String> {
|
||||
if !self.defs.contains_key(name) {
|
||||
// Parses a file into a new book
|
||||
let file = format!("./{}.kind2", name);
|
||||
let text = std::fs::read_to_string(&file).map_err(|_| format!("Could not read file: {}", file))?;
|
||||
let fid = self.get_file_id(&file);
|
||||
let defs = KindParser::new(&text).parse_book(name, fid)?;
|
||||
// Merges new book into book
|
||||
for (def_name, def_value) in &defs.defs {
|
||||
self.defs.insert(def_name.clone(), def_value.clone());
|
||||
}
|
||||
// Finds dependencies and loads them
|
||||
for (_, def_term) in defs.defs.into_iter() {
|
||||
let mut dependencies = BTreeSet::new();
|
||||
def_term.get_free_vars(im::Vector::new(), &mut dependencies);
|
||||
for ref_name in dependencies {
|
||||
if let Err(_) = self.load(&ref_name) {
|
||||
self.handle_unbound(&file, &ref_name)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)?;
|
||||
load_go("Nat", &mut book)?;
|
||||
load_go("Nat.succ", &mut book)?;
|
||||
load_go("Nat.zero", &mut book)?;
|
||||
//println!("DONE!");
|
||||
Ok(book)
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Gets a file id from its name
|
||||
pub fn get_file_id(&mut self, name: &str) -> u64 {
|
||||
if let Some(id) = self.fids.get(name) {
|
||||
*id
|
||||
@ -73,7 +94,7 @@ impl Book {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: asymptotics
|
||||
// Gets a file name from its id (FIXME: asymptotics)
|
||||
pub fn get_file_name(&self, id: u64) -> Option<String> {
|
||||
for (name, &fid) in &self.fids {
|
||||
if fid == id {
|
||||
|
@ -5,11 +5,50 @@ use std::collections::BTreeSet;
|
||||
|
||||
impl<'i> KindParser<'i> {
|
||||
|
||||
pub fn parse_def(&mut self, fid: u64) -> Result<(String, Term), String> {
|
||||
// Parses a top-level use-declaration
|
||||
fn parse_use(&mut self, fid: u64, nam: String, uses: &mut Uses) -> Result<(), String> {
|
||||
self.skip_trivia();
|
||||
let add = self.parse_name()?;
|
||||
self.skip_trivia();
|
||||
let nam = format!("{}{}", nam, add);
|
||||
if self.peek_one() == Some('{') {
|
||||
self.consume("{")?;
|
||||
self.skip_trivia();
|
||||
loop {
|
||||
self.parse_use(fid, nam.clone(), uses)?;
|
||||
self.skip_trivia();
|
||||
match self.peek_one() {
|
||||
Some(',') => { self.consume(",")?; continue; }
|
||||
Some('}') => { self.consume("}")?; break; }
|
||||
_ => { return self.expected("comma (`,`) or semicolon (`;`)"); }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let pts = nam.split('.').collect::<Vec<&str>>();
|
||||
let key = pts.last().unwrap().to_string();
|
||||
//println!("use {} ~> {}", key, nam);
|
||||
uses.insert(key, nam);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Parses many top-level use-declarations
|
||||
fn parse_uses(&mut self, fid: u64) -> Result<Uses, String> {
|
||||
let mut uses = im::HashMap::new();
|
||||
self.skip_trivia();
|
||||
while self.peek_many(4) == Some("use ") {
|
||||
self.consume("use")?;
|
||||
self.parse_use(fid, String::new(), &mut uses)?;
|
||||
self.skip_trivia();
|
||||
}
|
||||
return Ok(uses);
|
||||
}
|
||||
|
||||
// Parses a top-level definition (datatype or term)
|
||||
pub fn parse_def(&mut self, fid: u64, uses: &Uses) -> Result<(String, Term), String> {
|
||||
// Top-level datatype
|
||||
if self.peek_many(5) == Some("data ") {
|
||||
let adt = self.parse_adt(fid)?;
|
||||
let adt = self.parse_adt(fid, uses)?;
|
||||
let mut typ = Term::Set;
|
||||
let mut val = Term::new_adt(&adt);
|
||||
for (idx_nam, idx_typ) in adt.idxs.iter().rev() {
|
||||
@ -29,28 +68,68 @@ impl<'i> KindParser<'i> {
|
||||
// Top level definition
|
||||
self.skip_trivia();
|
||||
let nam = self.parse_name()?;
|
||||
let nam = uses.get(&nam).unwrap_or(&nam).to_string();
|
||||
self.skip_trivia();
|
||||
|
||||
// Parameters (optional)
|
||||
let mut pars = vec![];
|
||||
while self.peek_one().map_or(false, |c| c.is_ascii_alphabetic()) {
|
||||
let par = self.parse_name()?;
|
||||
self.skip_trivia();
|
||||
pars.push(par);
|
||||
}
|
||||
|
||||
// Arguments (optional)
|
||||
let mut args = vec![];
|
||||
while self.peek_one() == Some('(') {
|
||||
self.consume("(")?;
|
||||
let arg_name = self.parse_name()?;
|
||||
self.consume(":")?;
|
||||
let arg_type = self.parse_term(fid, uses)?;
|
||||
self.consume(")")?;
|
||||
args.push((arg_name, arg_type));
|
||||
self.skip_trivia();
|
||||
}
|
||||
|
||||
// Type annotation (optional)
|
||||
let mut typ;
|
||||
if self.peek_one() == Some(':') {
|
||||
self.consume(":")?;
|
||||
let typ = self.parse_term(fid)?;
|
||||
self.consume("=")?;
|
||||
let val = self.parse_term(fid)?;
|
||||
return Ok((nam, Term::Ann { chk: false, val: Box::new(val), typ: Box::new(typ) }));
|
||||
typ = self.parse_term(fid, uses)?;
|
||||
} else {
|
||||
typ = Term::Met {};
|
||||
}
|
||||
|
||||
// Value (mandatory)
|
||||
self.consume("=")?;
|
||||
let val = self.parse_term(fid)?;
|
||||
let mut val = self.parse_term(fid, uses)?;
|
||||
|
||||
return Ok((nam, val));
|
||||
// Adds arguments to val/typ
|
||||
for (arg_nam, arg_typ) in args.iter().rev() {
|
||||
typ = Term::All { nam: arg_nam.clone(), inp: Box::new(arg_typ.clone()), bod: Box::new(typ.clone()) };
|
||||
val = Term::Lam { nam: arg_nam.clone(), bod: Box::new(val.clone()) };
|
||||
}
|
||||
|
||||
// Adds parameters to val/typ
|
||||
for par in pars.iter().rev() {
|
||||
typ = Term::All { nam: par.clone(), inp: Box::new(Term::Met{}), bod: Box::new(typ.clone()) };
|
||||
val = Term::Lam { nam: par.clone(), bod: Box::new(val.clone()) };
|
||||
}
|
||||
|
||||
//println!("- def: {}", nam);
|
||||
//println!("- typ: {}", typ.show());
|
||||
//println!("- val: {}", val.show());
|
||||
|
||||
return Ok((nam, Term::Ann { chk: false, val: Box::new(val), typ: Box::new(typ) }));
|
||||
}
|
||||
|
||||
pub fn parse_book(&mut self, fid: u64) -> Result<Book, String> {
|
||||
pub fn parse_book(&mut self, name: &str, fid: u64) -> Result<Book, String> {
|
||||
let mut book = Book::new();
|
||||
let mut uses = self.parse_uses(fid)?;
|
||||
// Adds the default 'use Path.to.file'
|
||||
uses.insert(name.split('.').last().unwrap().to_string(), name.to_string());
|
||||
while *self.index() < self.input().len() {
|
||||
let (name, term) = self.parse_def(fid)?;
|
||||
let (name, term) = self.parse_def(fid, &mut uses)?;
|
||||
book.defs.insert(name, term);
|
||||
self.skip_trivia();
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
use crate::{*};
|
||||
|
||||
//./../main.rs//
|
||||
//./mod.rs//
|
||||
|
||||
impl<'i> KindParser<'i> {
|
||||
|
||||
pub fn parse_info(&mut self) -> Result<Info, String> {
|
||||
@ -15,11 +12,11 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("found")?;
|
||||
self.consume("{")?;
|
||||
let nam = self.parse_name()?;
|
||||
let typ = self.parse_term(0)?;
|
||||
let typ = self.parse_term(0, &im::HashMap::new())?;
|
||||
self.consume("[")?;
|
||||
let mut ctx = Vec::new();
|
||||
while self.peek_one() != Some(']') {
|
||||
ctx.push(self.parse_term(0)?);
|
||||
ctx.push(self.parse_term(0, &im::HashMap::new())?);
|
||||
self.skip_trivia();
|
||||
}
|
||||
self.consume("]")?;
|
||||
@ -29,9 +26,9 @@ impl<'i> KindParser<'i> {
|
||||
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 exp = self.parse_term(0, &im::HashMap::new())?;
|
||||
let det = self.parse_term(0, &im::HashMap::new())?;
|
||||
let bad = self.parse_term(0, &im::HashMap::new())?;
|
||||
let src = Src::from_u64(self.parse_u64()?);
|
||||
self.consume("}")?;
|
||||
Ok(Info::Error {
|
||||
@ -45,7 +42,7 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("solve")?;
|
||||
self.consume("{")?;
|
||||
let nam = self.parse_name()?;
|
||||
let val = self.parse_term(0)?;
|
||||
let val = self.parse_term(0, &im::HashMap::new())?;
|
||||
self.consume("}")?;
|
||||
Ok(Info::Solve { nam, val })
|
||||
}
|
||||
@ -59,7 +56,7 @@ impl<'i> KindParser<'i> {
|
||||
Some('p') => {
|
||||
self.consume("print")?;
|
||||
self.consume("{")?;
|
||||
let val = self.parse_term(0)?;
|
||||
let val = self.parse_term(0, &im::HashMap::new())?;
|
||||
self.consume("}")?;
|
||||
Ok(Info::Print { val })
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ fn main() {
|
||||
//println!("loading");
|
||||
match cmd.as_str() {
|
||||
"check" | "run" => {
|
||||
match Book::load(arg) {
|
||||
match Book::boot(arg) {
|
||||
Ok(book) => {
|
||||
// Auto-formats the definition.
|
||||
//let defn = book.defs.get(arg).unwrap();
|
||||
|
@ -15,11 +15,10 @@ pub struct ADT {
|
||||
pub ctrs: Vec<Constructor>, // constructors
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Constructor {
|
||||
pub name: String, // constructor name
|
||||
pub flds: Vec<(String,Term)>, // constructor fields
|
||||
//pub rtyp: Term, // constructor type; NOTE: refactored. now, instead of storing `rtyp=(Vec A 0)`, we store just `idxs=[0]`, for ex.
|
||||
pub idxs: Vec<Term>, // constructor type indices
|
||||
}
|
||||
|
||||
@ -564,7 +563,7 @@ impl Term {
|
||||
bod: Box::new(term)
|
||||
};
|
||||
|
||||
println!("PARSED:\n{}", term.show());
|
||||
//println!("PARSED:\n{}", term.show());
|
||||
|
||||
// 8. Return 'term'
|
||||
return term;
|
||||
@ -576,7 +575,7 @@ impl ADT {
|
||||
|
||||
// Loads an ADT from its λ-encoded file.
|
||||
pub fn load(name: &str) -> Result<ADT, String> {
|
||||
let book = Book::load(name)?;
|
||||
let book = Book::boot(name)?;
|
||||
if let Some(term) = book.defs.get(name) {
|
||||
let mut term = &term.clean();
|
||||
// Skips all Anns
|
||||
@ -719,11 +718,11 @@ impl Match {
|
||||
|
||||
impl<'i> KindParser<'i> {
|
||||
|
||||
pub fn parse_list(&mut self, fid: u64) -> Result<crate::sugar::List, String> {
|
||||
pub fn parse_list(&mut self, fid: u64, uses: &Uses) -> Result<crate::sugar::List, String> {
|
||||
self.consume("[")?;
|
||||
let mut vals = Vec::new();
|
||||
while self.peek_one() != Some(']') {
|
||||
vals.push(Box::new(self.parse_term(fid)?));
|
||||
vals.push(Box::new(self.parse_term(fid, uses)?));
|
||||
self.skip_trivia();
|
||||
if self.peek_one() == Some(',') {
|
||||
self.consume(",")?;
|
||||
@ -733,16 +732,19 @@ impl<'i> KindParser<'i> {
|
||||
return Ok(crate::sugar::List { vals });
|
||||
}
|
||||
|
||||
pub fn parse_adt(&mut self, fid: u64) -> Result<crate::sugar::ADT, String> {
|
||||
// FIXME: handle shadowing
|
||||
pub fn parse_adt(&mut self, fid: u64, uses: &Uses) -> Result<crate::sugar::ADT, String> {
|
||||
self.consume("data ")?;
|
||||
let name = self.parse_name()?;
|
||||
let mut pars = Vec::new();
|
||||
let mut idxs = Vec::new();
|
||||
let mut uses = uses.clone();
|
||||
// Parses ADT parameters (if any)
|
||||
self.skip_trivia();
|
||||
while self.peek_one().map_or(false, |c| c.is_ascii_alphabetic()) {
|
||||
let par = self.parse_name()?;
|
||||
self.skip_trivia();
|
||||
uses = shadow(&par, &uses);
|
||||
pars.push(par);
|
||||
}
|
||||
// Parses ADT fields
|
||||
@ -750,8 +752,9 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("(")?;
|
||||
let idx_name = self.parse_name()?;
|
||||
self.consume(":")?;
|
||||
let idx_type = self.parse_term(fid)?;
|
||||
let idx_type = self.parse_term(fid, &uses)?;
|
||||
self.consume(")")?;
|
||||
uses = shadow(&idx_name, &uses);
|
||||
idxs.push((idx_name, idx_type));
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -761,6 +764,7 @@ impl<'i> KindParser<'i> {
|
||||
while self.peek_one() == Some('|') {
|
||||
self.consume("|")?;
|
||||
let ctr_name = self.parse_name()?;
|
||||
let mut uses = uses.clone();
|
||||
let mut flds = Vec::new();
|
||||
// Parses constructor fields
|
||||
self.skip_trivia();
|
||||
@ -768,8 +772,9 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("(")?;
|
||||
let fld_name = self.parse_name()?;
|
||||
self.consume(":")?;
|
||||
let fld_type = self.parse_term(fid)?;
|
||||
let fld_type = self.parse_term(fid, &uses)?;
|
||||
self.consume(")")?;
|
||||
uses = shadow(&fld_name, &uses);
|
||||
flds.push((fld_name, fld_type));
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -791,7 +796,7 @@ impl<'i> KindParser<'i> {
|
||||
}
|
||||
// Parses the indices
|
||||
while self.peek_one() != Some(')') {
|
||||
let ctr_index = self.parse_term(fid)?;
|
||||
let ctr_index = self.parse_term(fid, &uses)?;
|
||||
ctr_indices.push(ctr_index);
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -817,51 +822,74 @@ impl<'i> KindParser<'i> {
|
||||
// The ADT match syntax is similar to the numeric match syntax, including the same optionals,
|
||||
// but it allows any number of <name>:<term> cases. Also, similarly to the List syntax, there
|
||||
// is no built-in "Mat" syntax on the Term type, so we must convert it to an applicative form:
|
||||
// match x = val {
|
||||
// match x:
|
||||
// List.cons: x.head
|
||||
// List.nil: #0
|
||||
// }: #U60
|
||||
// : #U60
|
||||
// Would be converted to:
|
||||
// (~val _ (λx.head λx.tail x.tail) 0)
|
||||
// Which is the same as:
|
||||
// (APP (APP (APP (INS (VAR "val")) MET) (LAM "x.head" (LAM "x.tail" (VAR "x.head")))) (NUM 0))
|
||||
pub fn parse_match(&mut self, fid: u64) -> Result<Match, String> {
|
||||
// FIXME: handle shadowing
|
||||
pub fn parse_match(&mut self, fid: u64, uses: &Uses) -> Result<Match, String> {
|
||||
// Parses the header: 'match <name> = <expr>'
|
||||
self.consume("match ")?;
|
||||
let name = self.parse_name()?;
|
||||
self.skip_trivia();
|
||||
let expr = if self.peek_one() == Some('=') {
|
||||
self.consume("=")?;
|
||||
self.parse_term(fid)?
|
||||
self.parse_term(fid, uses)?
|
||||
} else {
|
||||
Term::Var { nam: name.clone() }
|
||||
};
|
||||
// Parses the cases: '{ Type.constructor: value ... }'
|
||||
self.consume("{")?;
|
||||
let mut adt = "Empty".to_string();
|
||||
let mut cses = Vec::new();
|
||||
while self.peek_one() != Some('}') {
|
||||
let ctr_name = self.parse_name()?;
|
||||
let cse_name = self.parse_name()?;
|
||||
let cse_name = uses.get(&cse_name).unwrap_or(&cse_name).to_string();
|
||||
// Infers the local ADT name
|
||||
let adt_name = {
|
||||
let pts = cse_name.split('.').collect::<Vec<&str>>();
|
||||
if pts.len() < 2 {
|
||||
return self.expected("Type.constructor");
|
||||
} else {
|
||||
pts[..pts.len() - 1].join(".")
|
||||
}
|
||||
};
|
||||
// Sets the global ADT name
|
||||
if adt == "Empty" {
|
||||
adt = adt_name.clone();
|
||||
} else if adt != adt_name {
|
||||
return self.expected(&format!("{}.constructor", adt));
|
||||
}
|
||||
// Finds this case's constructor
|
||||
let cnm = cse_name.split('.').last().unwrap().to_string();
|
||||
let ctr = ADT::load(&adt).ok().and_then(|adt| adt.ctrs.iter().find(|ctr| ctr.name == cnm).cloned());
|
||||
if ctr.is_none() {
|
||||
return self.expected(&format!("a valid constructor ({}.{} doesn't exit)", adt_name, cnm));
|
||||
}
|
||||
// Shadows this constructor's field variables
|
||||
let mut uses = uses.clone();
|
||||
for (fld_name, _) in &ctr.unwrap().flds {
|
||||
uses = shadow(&format!("{}.{}", name, fld_name), &uses);
|
||||
}
|
||||
// Parses the return value
|
||||
self.consume(":")?;
|
||||
let ctr_body = self.parse_term(fid)?;
|
||||
cses.push((ctr_name, ctr_body));
|
||||
let cse_body = self.parse_term(fid, &uses)?;
|
||||
cses.push((cse_name, cse_body));
|
||||
self.skip_trivia();
|
||||
}
|
||||
self.consume("}")?;
|
||||
// Parses the motive: ': return_type'
|
||||
let moti = if self.peek_one() == Some(':') {
|
||||
self.consume(":")?;
|
||||
Some(self.parse_term(fid)?)
|
||||
Some(self.parse_term(fid, uses)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let adt_name = if cses.is_empty() {
|
||||
"Empty".to_string()
|
||||
} else {
|
||||
let first_case = &cses[0].0;
|
||||
let parts: Vec<&str> = first_case.split('.').collect();
|
||||
if parts.len() < 2 {
|
||||
return Err("Expected a constructor with a datatype (e.g., 'DataType.constructor')".to_string());
|
||||
}
|
||||
parts[..parts.len()-1].join(".")
|
||||
};
|
||||
Ok(Match { adt: adt_name, name, expr, cses, moti })
|
||||
return Ok(Match { adt, name, expr, cses, moti });
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{*};
|
||||
|
||||
|
||||
impl<'i> KindParser<'i> {
|
||||
|
||||
pub fn parse_oper(&mut self) -> Result<Oper, String> {
|
||||
@ -33,7 +34,7 @@ impl<'i> KindParser<'i> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_term(&mut self, fid: u64) -> Result<Term, String> {
|
||||
pub fn parse_term(&mut self, fid: u64, uses: &Uses) -> Result<Term, String> {
|
||||
self.skip_trivia();
|
||||
//println!("parsing ||{}", self.input[self.index..].replace("\n",""));
|
||||
|
||||
@ -44,9 +45,9 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("(")?;
|
||||
let nam = self.parse_name()?;
|
||||
self.consume(":")?;
|
||||
let inp = Box::new(self.parse_term(fid)?);
|
||||
let inp = Box::new(self.parse_term(fid, uses)?);
|
||||
self.consume(")")?;
|
||||
let bod = Box::new(self.parse_term(fid)?);
|
||||
let bod = Box::new(self.parse_term(fid, &shadow(&nam, uses))?);
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::All { nam, inp, bod }) });
|
||||
@ -57,7 +58,7 @@ impl<'i> KindParser<'i> {
|
||||
let ini = *self.index() as u64;
|
||||
self.consume("λ")?;
|
||||
let nam = self.parse_name()?;
|
||||
let bod = Box::new(self.parse_term(fid)?);
|
||||
let bod = Box::new(self.parse_term(fid, &shadow(&nam, uses))?);
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::Lam { nam, bod }) });
|
||||
@ -67,10 +68,10 @@ impl<'i> KindParser<'i> {
|
||||
if self.starts_with("(") {
|
||||
let ini = *self.index() as u64;
|
||||
self.consume("(")?;
|
||||
let fun = Box::new(self.parse_term(fid)?);
|
||||
let fun = Box::new(self.parse_term(fid, uses)?);
|
||||
let mut args = Vec::new();
|
||||
while self.peek_one() != Some(')') {
|
||||
args.push(Box::new(self.parse_term(fid)?));
|
||||
args.push(Box::new(self.parse_term(fid, uses)?));
|
||||
self.skip_trivia();
|
||||
}
|
||||
self.consume(")")?;
|
||||
@ -87,9 +88,9 @@ impl<'i> KindParser<'i> {
|
||||
if self.starts_with("{") {
|
||||
let ini = *self.index() as u64;
|
||||
self.consume("{")?;
|
||||
let val = Box::new(self.parse_term(fid)?);
|
||||
let val = Box::new(self.parse_term(fid, uses)?);
|
||||
self.consume(":")?;
|
||||
let typ = Box::new(self.parse_term(fid)?);
|
||||
let typ = Box::new(self.parse_term(fid, uses)?);
|
||||
self.consume("}")?;
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
@ -103,9 +104,9 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("(")?;
|
||||
let nam = self.parse_name()?;
|
||||
self.consume(":")?;
|
||||
let typ = Box::new(self.parse_term(fid)?);
|
||||
let typ = Box::new(self.parse_term(fid, uses)?);
|
||||
self.consume(")")?;
|
||||
let bod = Box::new(self.parse_term(fid)?);
|
||||
let bod = Box::new(self.parse_term(fid, &shadow(&nam, uses))?);
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::Slf { nam, typ, bod }) });
|
||||
@ -115,7 +116,7 @@ impl<'i> KindParser<'i> {
|
||||
if self.starts_with("~") {
|
||||
let ini = *self.index() as u64;
|
||||
self.consume("~")?;
|
||||
let val = Box::new(self.parse_term(fid)?);
|
||||
let val = Box::new(self.parse_term(fid, uses)?);
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::Ins { val }) });
|
||||
@ -144,8 +145,8 @@ impl<'i> KindParser<'i> {
|
||||
let ini = *self.index() as u64;
|
||||
self.consume("#(")?;
|
||||
let opr = self.parse_oper()?;
|
||||
let fst = Box::new(self.parse_term(fid)?);
|
||||
let snd = Box::new(self.parse_term(fid)?);
|
||||
let fst = Box::new(self.parse_term(fid, uses)?);
|
||||
let snd = Box::new(self.parse_term(fid, uses)?);
|
||||
self.consume(")")?;
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
@ -162,21 +163,21 @@ impl<'i> KindParser<'i> {
|
||||
self.skip_trivia();
|
||||
let x = if self.peek_one() == Some('=') {
|
||||
self.consume("=")?;
|
||||
Box::new(self.parse_term(fid)?)
|
||||
Box::new(self.parse_term(fid, uses)?)
|
||||
} else {
|
||||
Box::new(Term::Var { nam: nam.clone() })
|
||||
};
|
||||
self.consume("{")?;
|
||||
self.consume("#0")?;
|
||||
self.consume(":")?;
|
||||
let z = Box::new(self.parse_term(fid)?);
|
||||
let z = Box::new(self.parse_term(fid, uses)?);
|
||||
self.consume("#+")?;
|
||||
self.consume(":")?;
|
||||
let s = Box::new(self.parse_term(fid)?);
|
||||
let s = Box::new(self.parse_term(fid, &shadow(&format!("{}-1",nam), uses))?);
|
||||
self.consume("}")?;
|
||||
let p = if self.peek_one() == Some(':') {
|
||||
self.consume(":")?;
|
||||
Box::new(self.parse_term(fid)?)
|
||||
Box::new(self.parse_term(fid, &shadow(&nam, uses))?)
|
||||
} else {
|
||||
Box::new(Term::Met {})
|
||||
};
|
||||
@ -229,8 +230,8 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("let ")?;
|
||||
let nam = self.parse_name()?;
|
||||
self.consume("=")?;
|
||||
let val = Box::new(self.parse_term(fid)?);
|
||||
let bod = Box::new(self.parse_term(fid)?);
|
||||
let val = Box::new(self.parse_term(fid, uses)?);
|
||||
let bod = Box::new(self.parse_term(fid, &shadow(&nam, uses))?);
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::Let { nam, val, bod }) });
|
||||
@ -242,8 +243,8 @@ impl<'i> KindParser<'i> {
|
||||
self.consume("use ")?;
|
||||
let nam = self.parse_name()?;
|
||||
self.consume("=")?;
|
||||
let val = Box::new(self.parse_term(fid)?);
|
||||
let bod = Box::new(self.parse_term(fid)?);
|
||||
let val = Box::new(self.parse_term(fid, uses)?);
|
||||
let bod = Box::new(self.parse_term(fid, &shadow(&nam, uses))?);
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::Use { nam, val, bod }) });
|
||||
@ -261,7 +262,7 @@ impl<'i> KindParser<'i> {
|
||||
// LST ::= [ <term> , ... ]
|
||||
if self.starts_with("[") {
|
||||
let ini = *self.index() as u64;
|
||||
let lst = self.parse_list(fid)?;
|
||||
let lst = self.parse_list(fid, uses)?;
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
let val = Box::new(Term::new_list(&lst));
|
||||
@ -283,7 +284,7 @@ impl<'i> KindParser<'i> {
|
||||
// | ...
|
||||
if self.starts_with("data ") {
|
||||
let ini = *self.index() as u64;
|
||||
let adt = self.parse_adt(fid)?;
|
||||
let adt = self.parse_adt(fid, uses)?;
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::new_adt(&adt)) });
|
||||
@ -292,7 +293,7 @@ impl<'i> KindParser<'i> {
|
||||
// MAT ::= match <name> = <term> { <name> : <term> <...> }: <term>
|
||||
if self.starts_with("match ") {
|
||||
let ini = *self.index() as u64;
|
||||
let mat = self.parse_match(fid)?;
|
||||
let mat = self.parse_match(fid, uses)?;
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::new_match(&mat)) });
|
||||
@ -300,11 +301,19 @@ impl<'i> KindParser<'i> {
|
||||
|
||||
// VAR ::= <name>
|
||||
let ini = *self.index() as u64;
|
||||
let nam = self.parse_name()?;
|
||||
let old = self.parse_name()?;
|
||||
let nam = uses.get(&old).unwrap_or(&old).to_string();
|
||||
//if old != nam { println!("{} -> {}", old, nam); }
|
||||
let end = *self.index() as u64;
|
||||
let src = Src::new(fid, ini, end);
|
||||
return Ok(Term::Src { src, val: Box::new(Term::Var { nam }) });
|
||||
|
||||
}
|
||||
|
||||
// Parses a name that can be aliased (via the 'uses' map)
|
||||
//pub fn parse_nick(&mut self, uses: &Uses) -> Result<String, String> {
|
||||
//let nam = self.parse_name()?;
|
||||
//Ok(uses.get(&nam).cloned().unwrap_or(nam))
|
||||
//}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user