feat: made everything, only needs the error messages

This commit is contained in:
felipegchi 2023-01-23 15:01:53 -03:00
parent 0acf7ad79b
commit a87a04d5c6
12 changed files with 308 additions and 11 deletions

View File

@ -291,9 +291,9 @@ impl<'a> Visitor for Subst<'a> {
ExprKind::SeqRecord(sec) => {
use kind_tree::concrete::SeqOperation::*;
self.visit_ident(&mut sec.ident[0]);
self.visit_ident(&mut sec.name);
self.visit_expr(&mut sec.typ_);
self.visit_expr(&mut sec.typ);
match &mut sec.operation {
Set(expr) => self.visit_expr(expr),

View File

@ -879,6 +879,46 @@ impl<'a> Parser<'a> {
}
}
pub fn parse_seq(&mut self) -> Result<Box<Expr>, SyntaxDiagnostic> {
let start = self.range();
self.eat_variant(Token::Bang)?;
let typ = self.parse_atom()?;
let name = self.parse_id()?;
let mut fields = vec![];
let mut end = self.range();
while let Token::Dot = &self.get() {
self.advance();
end = self.range();
fields.push(self.parse_id()?);
}
let operation = if self.check_and_eat(Token::Eq) {
SeqOperation::Set(self.parse_expr(false)?)
} else if self.check_and_eat(Token::AtEq) {
SeqOperation::Mut(self.parse_expr(false)?)
} else {
SeqOperation::Get
};
Ok(Box::new(Expr {
data: ExprKind::SeqRecord(
SeqRecord {
typ,
name,
fields,
operation,
}
),
range: start.mix(end),
}))
}
/// The infinite hell of else ifs. But it's the most readable way
/// to check if the queue of tokens match a pattern as we need
/// some looakhead tokens.
@ -904,6 +944,8 @@ impl<'a> Parser<'a> {
self.parse_pi_or_lambda(false)
} else if self.is_sigma_type() {
self.parse_sigma_type()
} else if self.check_actual(Token::Bang) {
self.parse_seq()
} else if self.check_actual(Token::Tilde) {
self.parse_erased()
} else {

View File

@ -175,7 +175,20 @@ impl<'a> Lexer<'a> {
';' => self.single_token(Token::Semi, start),
'$' => self.single_token(Token::Dollar, start),
',' => self.single_token(Token::Comma, start),
'+' => self.single_token(Token::Plus, start),
'+' => {
self.next_char();
match self.peekable.peek() {
Some('=') => self.single_token(Token::PlusEq, start),
_ => (Token::Plus, self.mk_range(start)),
}
}
'@' => {
self.next_char();
match self.peekable.peek() {
Some('=') => self.single_token(Token::AtEq, start),
_ => (Token::At, self.mk_range(start)),
}
}
'-' => {
self.next_char();
match self.peekable.peek() {

View File

@ -75,6 +75,10 @@ pub enum Token {
BangEq,
Bang,
PlusEq,
AtEq,
At,
HashHash,
Hash,
@ -181,6 +185,9 @@ impl fmt::Display for Token {
Token::With => write!(f, "with"),
Token::Return => write!(f, "return"),
Token::Ask => write!(f, "ask"),
Token::PlusEq => write!(f, "+="),
Token::AtEq => write!(f, "@="),
Token::At => write!(f, "@"),
}
}
}

View File

@ -1,6 +1,6 @@
use kind_span::{Locatable, Range};
use kind_tree::concrete::{self, expr, Literal, TopLevel};
use kind_tree::desugared::{self};
use kind_tree::desugared::{self, Expr};
use kind_tree::symbol::{Ident, QualifiedIdent};
use crate::diagnostic::{PassDiagnostic, Sugar};
@ -79,7 +79,78 @@ impl<'a> DesugarState<'a> {
range: Range,
sub: &expr::SeqRecord,
) -> Box<desugared::Expr> {
todo!()
use concrete::SeqOperation::*;
let typ = self.desugar_expr(&sub.typ);
let mut value = vec![];
self.desugar_record_field_sequence(&mut value, typ, &sub.fields);
match &sub.operation {
Set(expr) => {
let value_ident = Ident::generate("_value");
let expr = self.desugar_expr(&expr);
let mut result = value.iter().rfold(expr, |acc, (name, field)| {
let name = name.add_segment(field.to_str()).add_segment("mut");
self.mk_desugared_ctr(
range,
name,
vec![Expr::var(value_ident.clone()), Expr::lambda(range.clone(), value_ident.clone(), acc, false)],
false,
)
});
match &mut result.data {
desugared::ExprKind::Ctr { args, .. } => {
if let desugared::ExprKind::Var { name } = &mut args[0].data {
*name = sub.name.clone()
}
},
_ => ()
}
result
},
Mut(expr) => {
let value_ident = Ident::generate("_value");
let expr = self.desugar_expr(&expr);
let mut result = value.iter().rfold(expr, |acc, (name, field)| {
let name = name.add_segment(field.to_str()).add_segment("mut");
Expr::lambda(name.range.clone(), value_ident.clone(), self.mk_desugared_ctr(
range,
name,
vec![Expr::var(value_ident.clone()), acc],
false,
), false)
});
let mut result = match result.data {
desugared::ExprKind::Lambda { body, .. } => {
body
}
_ => panic!()
};
match &mut result.data {
desugared::ExprKind::Ctr { args, .. } => {
if let desugared::ExprKind::Var { name } = &mut args[0].data {
*name = sub.name.clone()
}
},
_ => ()
}
result
}
Get => value
.iter()
.fold(Expr::var(sub.name.clone()), |acc, (name, field)| {
let name = name.add_segment(field.to_str()).add_segment("get");
self.mk_desugared_ctr(range, name, vec![acc], false)
}),
}
}
pub(crate) fn desugar_sttm(

View File

@ -23,6 +23,7 @@ pub mod attributes;
pub mod destruct;
pub mod expr;
pub mod top_level;
pub mod record_field;
pub struct DesugarState<'a> {
pub errors: Sender<Box<dyn Diagnostic>>,

View File

@ -0,0 +1,91 @@
use fxhash::FxHashMap;
use kind_tree::{
concrete::{self, TopLevel},
desugared::{self, Expr},
symbol::{Ident, QualifiedIdent},
telescope::Telescope,
};
use crate::subst::subst_on_expr;
use super::DesugarState;
impl<'a> DesugarState<'a> {
pub fn specialize_on_field(
&mut self,
typ: Box<desugared::Expr>,
) -> Option<(
QualifiedIdent,
&Telescope<concrete::Argument>,
Telescope<concrete::Argument>,
Vec<Box<Expr>>,
)> {
match typ.data {
desugared::ExprKind::Ctr { name, args } => {
let Some(TopLevel::RecordType(record)) = self.old_book.entries.get(name.to_str()) else { return None };
let entry_constructor = self.old_book.meta.get(
record
.name
.add_segment(record.constructor.to_str())
.to_str(),
)?;
Some((
name,
&record.parameters,
entry_constructor
.arguments
.clone()
.drop(record.parameters.len()),
args,
))
}
_ => None,
}
}
pub fn desugar_record_field_sequence(
&mut self,
res: &mut Vec<(QualifiedIdent, Ident)>,
typ: Box<desugared::Expr>,
fields: &[Ident],
) {
if fields.is_empty() {
return;
}
if let Some((name, params, record_fields, args)) = self.specialize_on_field(typ.clone()) {
if let Some(field) = record_fields
.iter()
.find(|x| x.name.to_str() == fields[0].to_str())
{
let key = field.name.clone();
let pair = params
.iter()
.zip(args)
.map(|(k, v)| (k.name.to_string(), v))
.collect::<FxHashMap<_, _>>();
let mut val = self.desugar_expr(
&field
.typ
.clone()
.unwrap_or_else(|| concrete::expr::Expr::typ(field.range.clone())),
);
subst_on_expr(&mut val, pair);
println!("{}", val);
res.push((name, key));
self.desugar_record_field_sequence(res, val, &fields[1..])
} else {
panic!("no field")
}
} else {
panic!("no record {}", typ)
}
}
}

View File

@ -11,3 +11,4 @@ mod diagnostic;
pub mod expand;
pub mod inline;
pub mod unbound;
pub mod subst;

View File

@ -0,0 +1,61 @@
use fxhash::FxHashMap;
use kind_tree::desugared::*;
pub fn subst_on_expr(expr: &mut Expr, substs: FxHashMap<String, Box<Expr>>) {
subst(Default::default(), expr, &substs)
}
fn subst(bindings: im_rc::HashSet<String>, expr: &mut Expr, substs: &FxHashMap<String, Box<Expr>>) {
use ExprKind::*;
match &mut expr.data {
Var { name } => {
if !bindings.contains(name.to_str()) {
if let Some(res) = substs.get(name.to_str()) {
*expr = *res.clone();
}
}
},
All { param, typ, body, .. } => {
subst(bindings.clone(), typ, substs);
let mut on_body = bindings.clone();
on_body.insert(param.to_string());
subst(on_body.clone(), body, substs);
},
Lambda { param, body, .. } => {
let mut on_body = bindings.clone();
on_body.insert(param.to_string());
subst(on_body.clone(), body, substs);
},
App { fun, args } => {
subst(bindings.clone(), fun, substs);
for arg in args.iter_mut() {
subst(bindings.clone(), &mut arg.data, substs);
}
},
Fun { name: _, args } | Ctr { name: _, args } => {
for arg in args.iter_mut() {
subst(bindings.clone(), arg, substs);
}
},
Let { name, val, next } => {
subst(bindings.clone(), val, substs);
let mut on_body = bindings.clone();
on_body.insert(name.to_string());
subst(on_body.clone(), next, substs);
},
Ann { expr, typ } => {
subst(bindings.clone(), expr, substs);
subst(bindings.clone(), typ, substs);
},
Sub { expr, .. } => {
subst(bindings.clone(), expr, substs);
},
Binary { left, right, .. } => {
subst(bindings.clone(), left, substs);
subst(bindings.clone(), right, substs);
},
_ => ()
}
}

View File

@ -638,9 +638,9 @@ impl Visitor for UnboundCollector {
ExprKind::SeqRecord(sec) => {
use kind_tree::concrete::SeqOperation::*;
self.visit_expr(&mut sec.typ_);
self.visit_expr(&mut sec.typ);
self.visit_ident(&mut sec.ident[0]);
self.visit_ident(&mut sec.name);
match &mut sec.operation {
Set(expr) => self.visit_expr(expr),

View File

@ -145,8 +145,9 @@ pub enum SeqOperation {
#[derive(Clone, Debug)]
pub struct SeqRecord {
pub typ_: Box<Expr>,
pub ident: Vec<Ident>,
pub typ: Box<Expr>,
pub name: Ident,
pub fields: Vec<Ident>,
pub operation: SeqOperation
}
@ -592,7 +593,7 @@ impl Display for Expr {
Hole => write!(f, "_"),
SeqRecord(rec) => {
use SeqOperation::*;
write!(f, "(!({}) {}", rec.typ_, rec.ident.iter().map(|x| x.to_str()).collect::<Vec<_>>().join(","))?;
write!(f, "(!({}) {} {}", rec.typ, rec.name, rec.fields.iter().map(|x| format!(".{}", x.to_str())).collect::<Vec<_>>().join(","))?;
match &rec.operation {
Set(expr) => write!(f, "+= {})", expr),
Mut(expr) => write!(f, "@= {})", expr),

View File

@ -492,6 +492,15 @@ pub fn walk_expr<T: Visitor>(ctx: &mut T, expr: &mut Expr) {
ExprKind::Hole => {}
ExprKind::Subst(subst) => ctx.visit_substitution(subst),
ExprKind::Match(matcher) => ctx.visit_match(matcher),
ExprKind::SeqRecord(_) => todo!(),
ExprKind::SeqRecord(seq) => {
ctx.visit_ident(&mut seq.name);
ctx.visit_expr(&mut seq.typ);
match &mut seq.operation {
SeqOperation::Set(expr) => ctx.visit_expr(expr),
SeqOperation::Mut(expr) => ctx.visit_expr(expr),
SeqOperation::Get => (),
}
},
}
}