From 43eeb5ca0d9fa6debe9a073378c7b5f05faf4108 Mon Sep 17 00:00:00 2001 From: felipegchi Date: Mon, 23 Jan 2023 09:52:36 -0300 Subject: [PATCH 1/4] feat: started the mutter, getter and setter feature --- crates/kind-derive/src/subst.rs | 14 +++ crates/kind-pass/src/desugar/expr.rs | 42 ++++++-- crates/kind-pass/src/unbound/mod.rs | 14 +++ crates/kind-tree/src/concrete/expr.rs | 130 +++++++++++------------ crates/kind-tree/src/concrete/mod.rs | 20 ++-- crates/kind-tree/src/concrete/visitor.rs | 1 + 6 files changed, 136 insertions(+), 85 deletions(-) diff --git a/crates/kind-derive/src/subst.rs b/crates/kind-derive/src/subst.rs index ca19e633..10cdfb1f 100644 --- a/crates/kind-derive/src/subst.rs +++ b/crates/kind-derive/src/subst.rs @@ -288,6 +288,20 @@ impl<'a> Visitor for Subst<'a> { self.visit_expr(motive); } } + ExprKind::SeqRecord(sec) => { + use kind_tree::concrete::SeqOperation::*; + + self.visit_ident(&mut sec.ident[0]); + + self.visit_expr(&mut sec.typ_); + + match &mut sec.operation { + Set(expr) => self.visit_expr(expr), + Mut(expr) => self.visit_expr(expr), + Get => (), + } + + }, } } } diff --git a/crates/kind-pass/src/desugar/expr.rs b/crates/kind-pass/src/desugar/expr.rs index 5105d88d..b18c0bac 100644 --- a/crates/kind-pass/src/desugar/expr.rs +++ b/crates/kind-pass/src/desugar/expr.rs @@ -40,15 +40,15 @@ impl<'a> DesugarState<'a> { let list_ident = QualifiedIdent::new_static("Nat", None, range); let cons_ident = list_ident.add_segment("succ"); let nil_ident = list_ident.add_segment("zero"); - + let mut res = self.mk_desugared_ctr(range, nil_ident, Vec::new(), false); for _ in 0..*num { res = self.mk_desugared_ctr(range, cons_ident.clone(), vec![res], false) } - + res - }, + } Literal::NumU120(num) => { if !self.check_implementation("U120.new", range, Sugar::U120) { return desugared::Expr::err(range); @@ -74,6 +74,14 @@ impl<'a> DesugarState<'a> { ) } + pub(crate) fn desugar_seq( + &mut self, + range: Range, + sub: &expr::SeqRecord, + ) -> Box { + todo!() + } + pub(crate) fn desugar_sttm( &mut self, bind_ident: &QualifiedIdent, @@ -157,7 +165,10 @@ impl<'a> DesugarState<'a> { let pure = self.old_book.names.get(pure_ident.to_str()); if bind.is_none() || pure.is_none() { - self.send_err(PassDiagnostic::NeedToImplementMethods(range, Sugar::DoNotation)); + self.send_err(PassDiagnostic::NeedToImplementMethods( + range, + Sugar::DoNotation, + )); return desugared::Expr::err(range); } @@ -249,7 +260,7 @@ impl<'a> DesugarState<'a> { type_name: &QualifiedIdent, var_name: &Ident, motive: &Option>, - next: &expr::Expr + next: &expr::Expr, ) -> Box { let rec = self.old_book.entries.get(type_name.to_str()); @@ -270,16 +281,23 @@ impl<'a> DesugarState<'a> { return desugared::Expr::err(range); } - let field_names : Vec<_> = record.fields.iter().map(|x| var_name.add_segment(x.0.to_str())).collect(); + let field_names: Vec<_> = record + .fields + .iter() + .map(|x| var_name.add_segment(x.0.to_str())) + .collect(); let irrelev = vec![false; field_names.len()]; - let motive = motive.as_ref().map(|x| self.desugar_expr(x)).unwrap_or_else(|| self.gen_hole_expr(range)); + let motive = motive + .as_ref() + .map(|x| self.desugar_expr(x)) + .unwrap_or_else(|| self.gen_hole_expr(range)); let spine = vec![ desugared::Expr::var(var_name.clone()), desugared::Expr::lambda(range, var_name.clone(), motive, false), - desugared::Expr::unfold_lambda(&irrelev, &field_names, self.desugar_expr(next)) + desugared::Expr::unfold_lambda(&irrelev, &field_names, self.desugar_expr(next)), ]; self.mk_desugared_fun(range, open_id, spine, false) @@ -367,7 +385,13 @@ impl<'a> DesugarState<'a> { Pair { fst, snd } => self.desugar_pair(expr.range, fst, snd), Match(matcher) => self.desugar_match(expr.range, matcher), Subst(sub) => self.desugar_sub(expr.range, sub), - Open { type_name, var_name, motive, next } => self.desugar_open(expr.range, type_name, var_name, motive, &next) + Open { + type_name, + var_name, + motive, + next, + } => self.desugar_open(expr.range, type_name, var_name, motive, &next), + SeqRecord(sec) => self.desugar_seq(expr.range, sec), } } } diff --git a/crates/kind-pass/src/unbound/mod.rs b/crates/kind-pass/src/unbound/mod.rs index a41aba85..8b2a7051 100644 --- a/crates/kind-pass/src/unbound/mod.rs +++ b/crates/kind-pass/src/unbound/mod.rs @@ -635,6 +635,20 @@ impl Visitor for UnboundCollector { } } } + ExprKind::SeqRecord(sec) => { + use kind_tree::concrete::SeqOperation::*; + + self.visit_expr(&mut sec.typ_); + + self.visit_ident(&mut sec.ident[0]); + + match &mut sec.operation { + Set(expr) => self.visit_expr(expr), + Mut(expr) => self.visit_expr(expr), + Get => (), + } + + }, } } } diff --git a/crates/kind-tree/src/concrete/expr.rs b/crates/kind-tree/src/concrete/expr.rs index a5e435c2..978a40e1 100644 --- a/crates/kind-tree/src/concrete/expr.rs +++ b/crates/kind-tree/src/concrete/expr.rs @@ -12,7 +12,7 @@ use std::fmt::{Display, Error, Formatter}; /// A binding express the positional or named argument of /// a constructor or function. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum Binding { Positional(Box), Named(Range, Ident, Box), @@ -22,7 +22,7 @@ pub enum Binding { pub type Spine = Vec; /// A binding that is used inside applications. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct AppBinding { pub data: Box, pub erased: bool, @@ -46,7 +46,7 @@ impl AppBinding { /// A case binding is a field or a rename of some field /// inside a match expression. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum CaseBinding { Field(Ident), Renamed(Ident, Ident), @@ -56,7 +56,7 @@ pub enum CaseBinding { /// strutinizer, bindings to the names of each arguments and /// a right-hand side value. The ignore_rest flag useful to just /// fill all of the case bindings that are not used with a default name. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Case { pub constructor: Ident, pub bindings: Vec, @@ -66,7 +66,7 @@ pub struct Case { /// A match block that will be desugared /// into an eliminator of a datatype. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Match { pub typ: QualifiedIdent, pub scrutinee: Ident, @@ -77,7 +77,7 @@ pub struct Match { } /// Substitution -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Substitution { pub name: Ident, pub redx: usize, @@ -85,7 +85,7 @@ pub struct Substitution { pub expr: Box, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum Literal { /// The universe of types (e.g. Type) Type, @@ -111,13 +111,13 @@ pub enum Literal { /// A destruct of a single constructor. It's a flat destruct /// and just translates into a eliminator for records. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum Destruct { Destruct(Range, QualifiedIdent, Vec, Option), Ident(Ident), } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum SttmKind { Expr(Box, Box), Ask(Destruct, Box, Box), @@ -130,13 +130,27 @@ pub enum SttmKind { /// describes the idea of `sequence` inside a monad /// each monadic action contains a `next` element that is /// desugared into a 'monadic bind'. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Sttm { pub data: SttmKind, pub range: Range, } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] +pub enum SeqOperation { + Set(Box), + Mut(Box), + Get +} + +#[derive(Clone, Debug)] +pub struct SeqRecord { + pub typ_: Box, + pub ident: Vec, + pub operation: SeqOperation +} + +#[derive(Clone, Debug)] pub enum ExprKind { /// Name of a variable Var { name: Ident }, @@ -210,12 +224,14 @@ pub enum ExprKind { type_name: QualifiedIdent, var_name: Ident, motive: Option>, - next: Box, + next: Box }, + + SeqRecord(SeqRecord) } /// Describes a single expression inside Kind2. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Expr { pub data: ExprKind, pub range: Range, @@ -292,25 +308,7 @@ impl Expr { range, }) } -} -impl Binding { - pub fn to_app_binding(&self) -> AppBinding { - match self { - Binding::Positional(expr) => { - AppBinding { - data: expr.clone(), - erased: false, - } - }, - Binding::Named(_, _, expr) => { - AppBinding { - data: expr.clone(), - erased: false, - } - }, - } - } } impl Locatable for Binding { @@ -485,34 +483,16 @@ impl Display for Match { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!(f, "match {} {}", self.typ, self.scrutinee)?; - if let Some(res) = &self.value { - write!(f, " = {}", res)?; - } - - if !self.with_vars.is_empty() { - write!(f, " with")?; - for var in &self.with_vars { - if let Some(ty) = &var.1 { - write!(f, " ({} : {})", var.0, ty)?; - } else { - write!(f, " {}", var.0)?; - } - } - } - + match &self.motive { + None => Ok(()), + Some(res) => write!(f, " : {}", res), + }?; write!(f, " {{ ")?; for case in &self.cases { write!(f, "{}; ", case)? } - - write!(f, "}}")?; - - if let Some(res) = &self.motive { - write!(f, " : {}", res)?; - } - - Ok(()) + write!(f, "}}") } } @@ -592,18 +572,8 @@ impl Display for Expr { args.iter().map(|x| format!(" {}", x)).collect::() ), Let { name, val, next } => write!(f, "(let {} = {}; {})", name, val, next), - Open { - type_name, - var_name, - motive: Some(motive), - next, - } => write!(f, "(open {} {} : {motive}; {})", type_name, var_name, next), - Open { - type_name, - var_name, - motive: None, - next, - } => write!(f, "(open {} {}; {})", type_name, var_name, next), + Open { type_name, var_name, motive: Some(motive), next } => write!(f, "(open {} {} : {motive}; {})", type_name, var_name, next), + Open { type_name, var_name, motive: None, next } => write!(f, "(open {} {}; {})", type_name, var_name, next), If { cond, then_, else_ } => { write!(f, "(if {} {{{}}} else {{{}}})", cond, then_, else_) } @@ -620,6 +590,34 @@ impl Display for Expr { Match(matcher) => write!(f, "({})", matcher), Subst(subst) => write!(f, "({})", subst), Hole => write!(f, "_"), + SeqRecord(rec) => { + use SeqOperation::*; + write!(f, "(!({}) {}", rec.typ_, rec.ident.iter().map(|x| x.to_str()).collect::>().join(","))?; + match &rec.operation { + Set(expr) => write!(f, "+= {})", expr), + Mut(expr) => write!(f, "@= {})", expr), + Get => write!(f, ")") + } + }, + } + } +} + +impl Binding { + pub fn to_app_binding(&self) -> AppBinding { + match self { + Binding::Positional(expr) => { + AppBinding { + data: expr.clone(), + erased: false, + } + }, + Binding::Named(_, _, expr) => { + AppBinding { + data: expr.clone(), + erased: false, + } + }, } } } diff --git a/crates/kind-tree/src/concrete/mod.rs b/crates/kind-tree/src/concrete/mod.rs index ee524e0e..be5ac2a0 100644 --- a/crates/kind-tree/src/concrete/mod.rs +++ b/crates/kind-tree/src/concrete/mod.rs @@ -22,7 +22,7 @@ pub mod visitor; pub use expr::*; /// A value of a attribute -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum AttributeStyle { Ident(Range, Ident), String(Range, String), @@ -34,7 +34,7 @@ pub enum AttributeStyle { /// that usually is on the top of a declaration /// and can be attached to a function declaration /// it express some compiler properties -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Attribute { pub name: Ident, pub args: Vec, @@ -48,7 +48,7 @@ pub struct Attribute { /// compiled. /// hide: that express a implicit argument (that will /// be discovered through unification). -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Argument { pub hidden: bool, pub erased: bool, @@ -60,7 +60,7 @@ pub struct Argument { /// A rule is a equation that in the left-hand-side /// contains a list of patterns @pats@ and on the /// right hand side a value. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Rule { pub name: QualifiedIdent, pub pats: Vec>, @@ -72,7 +72,7 @@ pub struct Rule { /// and has rules. The type of the function /// consists of the arguments @args@ and the /// return type @typ@. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Entry { pub name: QualifiedIdent, pub docs: Vec, @@ -86,7 +86,7 @@ pub struct Entry { /// A single cosntructor inside the algebraic data /// type definition. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Constructor { pub name: Ident, pub docs: Vec, @@ -97,7 +97,7 @@ pub struct Constructor { /// An algebraic data type definition that supports /// parametric and indexed data type definitions. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct SumTypeDecl { pub name: QualifiedIdent, pub docs: Vec, @@ -108,7 +108,7 @@ pub struct SumTypeDecl { } /// A single constructor data type. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct RecordDecl { pub name: QualifiedIdent, pub docs: Vec, @@ -126,7 +126,7 @@ impl RecordDecl { } /// All of the structures -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum TopLevel { SumType(SumTypeDecl), RecordType(RecordDecl), @@ -166,7 +166,7 @@ impl TopLevel { /// A module is a collection of top level entries /// that contains syntatic sugars. In the future /// it will contain a HashMap to local renames. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct Module { pub entries: Vec, pub uses: FxHashMap, diff --git a/crates/kind-tree/src/concrete/visitor.rs b/crates/kind-tree/src/concrete/visitor.rs index 67727256..d0e9e2be 100644 --- a/crates/kind-tree/src/concrete/visitor.rs +++ b/crates/kind-tree/src/concrete/visitor.rs @@ -492,5 +492,6 @@ pub fn walk_expr(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!(), } } From a87a04d5c6a8bb8ba381ae609ea28212567a1e8d Mon Sep 17 00:00:00 2001 From: felipegchi Date: Mon, 23 Jan 2023 15:01:53 -0300 Subject: [PATCH 2/4] feat: made everything, only needs the error messages --- crates/kind-derive/src/subst.rs | 4 +- crates/kind-parser/src/expr.rs | 42 +++++++++ crates/kind-parser/src/lexer/mod.rs | 15 +++- crates/kind-parser/src/lexer/tokens.rs | 7 ++ crates/kind-pass/src/desugar/expr.rs | 75 +++++++++++++++- crates/kind-pass/src/desugar/mod.rs | 1 + crates/kind-pass/src/desugar/record_field.rs | 91 ++++++++++++++++++++ crates/kind-pass/src/lib.rs | 1 + crates/kind-pass/src/subst.rs | 61 +++++++++++++ crates/kind-pass/src/unbound/mod.rs | 4 +- crates/kind-tree/src/concrete/expr.rs | 7 +- crates/kind-tree/src/concrete/visitor.rs | 11 ++- 12 files changed, 308 insertions(+), 11 deletions(-) create mode 100644 crates/kind-pass/src/desugar/record_field.rs create mode 100644 crates/kind-pass/src/subst.rs diff --git a/crates/kind-derive/src/subst.rs b/crates/kind-derive/src/subst.rs index 10cdfb1f..05fbd462 100644 --- a/crates/kind-derive/src/subst.rs +++ b/crates/kind-derive/src/subst.rs @@ -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), diff --git a/crates/kind-parser/src/expr.rs b/crates/kind-parser/src/expr.rs index a742a301..63ec9233 100644 --- a/crates/kind-parser/src/expr.rs +++ b/crates/kind-parser/src/expr.rs @@ -879,6 +879,46 @@ impl<'a> Parser<'a> { } } + pub fn parse_seq(&mut self) -> Result, 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 { diff --git a/crates/kind-parser/src/lexer/mod.rs b/crates/kind-parser/src/lexer/mod.rs index 4c9bf2c4..cb410502 100644 --- a/crates/kind-parser/src/lexer/mod.rs +++ b/crates/kind-parser/src/lexer/mod.rs @@ -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() { diff --git a/crates/kind-parser/src/lexer/tokens.rs b/crates/kind-parser/src/lexer/tokens.rs index fe140da8..4a21bb06 100644 --- a/crates/kind-parser/src/lexer/tokens.rs +++ b/crates/kind-parser/src/lexer/tokens.rs @@ -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, "@"), } } } diff --git a/crates/kind-pass/src/desugar/expr.rs b/crates/kind-pass/src/desugar/expr.rs index b18c0bac..6e7859f2 100644 --- a/crates/kind-pass/src/desugar/expr.rs +++ b/crates/kind-pass/src/desugar/expr.rs @@ -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 { - 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( diff --git a/crates/kind-pass/src/desugar/mod.rs b/crates/kind-pass/src/desugar/mod.rs index 5dfd1361..5316c412 100644 --- a/crates/kind-pass/src/desugar/mod.rs +++ b/crates/kind-pass/src/desugar/mod.rs @@ -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>, diff --git a/crates/kind-pass/src/desugar/record_field.rs b/crates/kind-pass/src/desugar/record_field.rs new file mode 100644 index 00000000..ded1f45a --- /dev/null +++ b/crates/kind-pass/src/desugar/record_field.rs @@ -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, + ) -> Option<( + QualifiedIdent, + &Telescope, + Telescope, + Vec>, + )> { + 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, + 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::>(); + + 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) + } + } +} diff --git a/crates/kind-pass/src/lib.rs b/crates/kind-pass/src/lib.rs index a7251658..c6a185cc 100644 --- a/crates/kind-pass/src/lib.rs +++ b/crates/kind-pass/src/lib.rs @@ -11,3 +11,4 @@ mod diagnostic; pub mod expand; pub mod inline; pub mod unbound; +pub mod subst; \ No newline at end of file diff --git a/crates/kind-pass/src/subst.rs b/crates/kind-pass/src/subst.rs new file mode 100644 index 00000000..8bca013b --- /dev/null +++ b/crates/kind-pass/src/subst.rs @@ -0,0 +1,61 @@ +use fxhash::FxHashMap; +use kind_tree::desugared::*; + +pub fn subst_on_expr(expr: &mut Expr, substs: FxHashMap>) { + subst(Default::default(), expr, &substs) +} + +fn subst(bindings: im_rc::HashSet, expr: &mut Expr, substs: &FxHashMap>) { + 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); + }, + _ => () + } +} + diff --git a/crates/kind-pass/src/unbound/mod.rs b/crates/kind-pass/src/unbound/mod.rs index 8b2a7051..2398c9f6 100644 --- a/crates/kind-pass/src/unbound/mod.rs +++ b/crates/kind-pass/src/unbound/mod.rs @@ -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), diff --git a/crates/kind-tree/src/concrete/expr.rs b/crates/kind-tree/src/concrete/expr.rs index 978a40e1..a1b76867 100644 --- a/crates/kind-tree/src/concrete/expr.rs +++ b/crates/kind-tree/src/concrete/expr.rs @@ -145,8 +145,9 @@ pub enum SeqOperation { #[derive(Clone, Debug)] pub struct SeqRecord { - pub typ_: Box, - pub ident: Vec, + pub typ: Box, + pub name: Ident, + pub fields: Vec, 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::>().join(","))?; + write!(f, "(!({}) {} {}", rec.typ, rec.name, rec.fields.iter().map(|x| format!(".{}", x.to_str())).collect::>().join(","))?; match &rec.operation { Set(expr) => write!(f, "+= {})", expr), Mut(expr) => write!(f, "@= {})", expr), diff --git a/crates/kind-tree/src/concrete/visitor.rs b/crates/kind-tree/src/concrete/visitor.rs index d0e9e2be..e840550c 100644 --- a/crates/kind-tree/src/concrete/visitor.rs +++ b/crates/kind-tree/src/concrete/visitor.rs @@ -492,6 +492,15 @@ pub fn walk_expr(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 => (), + } + }, } } From 91ed7314a6149fca459e515ed0227edd2c9a1af4 Mon Sep 17 00:00:00 2001 From: felipegchi Date: Tue, 24 Jan 2023 10:22:59 -0300 Subject: [PATCH 3/4] feat: added errors for each case --- crates/kind-cli/src/main.rs | 8 +- crates/kind-derive/src/subst.rs | 2 +- crates/kind-driver/src/resolution.rs | 2 +- crates/kind-parser/src/expr.rs | 12 ++- crates/kind-pass/src/desugar/expr.rs | 90 ++++++++++++------- crates/kind-pass/src/desugar/mod.rs | 2 + crates/kind-pass/src/desugar/record_field.rs | 30 ++++--- crates/kind-pass/src/diagnostic.rs | 61 ++++++++++++- crates/kind-pass/src/subst.rs | 2 +- crates/kind-pass/src/unbound/mod.rs | 13 ++- .../kind-tests/suite/run/GettersSyntax.golden | 1 + .../kind-tests/suite/run/GettersSyntax.kind2 | 20 +++++ .../kind-tests/suite/run/MuttersSyntax.golden | 1 + .../kind-tests/suite/run/MuttersSyntax.kind2 | 20 +++++ .../kind-tests/suite/run/SettersSyntax.golden | 1 + .../kind-tests/suite/run/SettersSyntax.kind2 | 20 +++++ crates/kind-tree/src/concrete/expr.rs | 4 +- crates/kind-tree/src/concrete/visitor.rs | 2 +- 18 files changed, 222 insertions(+), 69 deletions(-) create mode 100644 crates/kind-tests/suite/run/GettersSyntax.golden create mode 100644 crates/kind-tests/suite/run/GettersSyntax.kind2 create mode 100644 crates/kind-tests/suite/run/MuttersSyntax.golden create mode 100644 crates/kind-tests/suite/run/MuttersSyntax.kind2 create mode 100644 crates/kind-tests/suite/run/SettersSyntax.golden create mode 100644 crates/kind-tests/suite/run/SettersSyntax.kind2 diff --git a/crates/kind-cli/src/main.rs b/crates/kind-cli/src/main.rs index bc756a38..ed3703a6 100644 --- a/crates/kind-cli/src/main.rs +++ b/crates/kind-cli/src/main.rs @@ -150,7 +150,7 @@ pub fn compile_in_session( eprintln!(); render_to_stderr( - &render_config, + render_config, &session, &Log::Checking(format!("The file '{}'", file)), ); @@ -168,12 +168,12 @@ pub fn compile_in_session( contains_error = true; } - render_to_stderr(&render_config, &session, &diagnostic) + render_to_stderr(render_config, &session, &diagnostic) } if !contains_error { render_to_stderr( - &render_config, + render_config, &session, &if compiled { Log::Compiled(start.elapsed()) @@ -186,7 +186,7 @@ pub fn compile_in_session( res } else { - render_to_stderr(&render_config, &session, &Log::Failed(start.elapsed())); + render_to_stderr(render_config, &session, &Log::Failed(start.elapsed())); eprintln!(); match res { diff --git a/crates/kind-derive/src/subst.rs b/crates/kind-derive/src/subst.rs index 05fbd462..3eec615d 100644 --- a/crates/kind-derive/src/subst.rs +++ b/crates/kind-derive/src/subst.rs @@ -291,7 +291,7 @@ impl<'a> Visitor for Subst<'a> { ExprKind::SeqRecord(sec) => { use kind_tree::concrete::SeqOperation::*; - self.visit_ident(&mut sec.name); + self.visit_expr(&mut sec.expr); self.visit_expr(&mut sec.typ); diff --git a/crates/kind-driver/src/resolution.rs b/crates/kind-driver/src/resolution.rs index f607ac25..9e96b842 100644 --- a/crates/kind-driver/src/resolution.rs +++ b/crates/kind-driver/src/resolution.rs @@ -292,7 +292,7 @@ pub fn check_unbound_top_level(session: &mut Session, book: &mut Book) -> anyhow } for unbound in unbound_names.values() { - unbound_variable(session, book, &unbound); + unbound_variable(session, book, unbound); failed = true; } diff --git a/crates/kind-parser/src/expr.rs b/crates/kind-parser/src/expr.rs index 63ec9233..e29eb75b 100644 --- a/crates/kind-parser/src/expr.rs +++ b/crates/kind-parser/src/expr.rs @@ -886,7 +886,7 @@ impl<'a> Parser<'a> { let typ = self.parse_atom()?; - let name = self.parse_id()?; + let name = self.parse_atom()?; let mut fields = vec![]; @@ -899,9 +899,13 @@ impl<'a> Parser<'a> { } let operation = if self.check_and_eat(Token::Eq) { - SeqOperation::Set(self.parse_expr(false)?) + let expr = self.parse_expr(false)?; + end = expr.range; + SeqOperation::Set(expr) } else if self.check_and_eat(Token::AtEq) { - SeqOperation::Mut(self.parse_expr(false)?) + let expr = self.parse_expr(false)?; + end = expr.range; + SeqOperation::Mut(expr) } else { SeqOperation::Get }; @@ -910,7 +914,7 @@ impl<'a> Parser<'a> { data: ExprKind::SeqRecord( SeqRecord { typ, - name, + expr: name, fields, operation, } diff --git a/crates/kind-pass/src/desugar/expr.rs b/crates/kind-pass/src/desugar/expr.rs index 6e7859f2..313084ca 100644 --- a/crates/kind-pass/src/desugar/expr.rs +++ b/crates/kind-pass/src/desugar/expr.rs @@ -84,70 +84,96 @@ impl<'a> DesugarState<'a> { let typ = self.desugar_expr(&sub.typ); let mut value = vec![]; - self.desugar_record_field_sequence(&mut value, typ, &sub.fields); + self.desugar_record_field_sequence(range, &mut value, typ, &sub.fields); + + if self.failed { + return Expr::err(range) + } 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"); + let mut result = value.iter().rfold(expr, |acc, (typ, field)| { + let name = typ.add_segment(field.to_str()).add_segment("mut"); + + if self.failed || !self.check_implementation(name.to_str(), range, Sugar::Mutter(typ.to_string())) { + return desugared::Expr::err(range); + } + self.mk_desugared_ctr( range, name, - vec![Expr::var(value_ident.clone()), Expr::lambda(range.clone(), value_ident.clone(), acc, false)], + 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() - } - }, - _ => () + if let desugared::ExprKind::Ctr { args, .. } = &mut result.data { + args[0] = self.desugar_expr(&sub.expr); } 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], + + let result = value.iter().rfold(expr, |acc, (typ, field)| { + let name = typ.add_segment(field.to_str()).add_segment("mut"); + + if self.failed || !self.check_implementation(name.to_str(), range, Sugar::Mutter(typ.to_string())) { + return desugared::Expr::err(range); + } + + Expr::lambda( + name.range.clone(), + value_ident.clone(), + self.mk_desugared_ctr( + range, + name, + vec![Expr::var(value_ident.clone()), acc], + false, + ), false, - ), false) + ) }); - let mut result = match result.data { - desugared::ExprKind::Lambda { body, .. } => { - body - } - _ => panic!() + if self.failed { + return Expr::err(range) + } + + let mut result = if let desugared::ExprKind::Lambda { body, .. } = result.data { + body + } else { + self.send_err(PassDiagnostic::NeedsAField( + sub.expr.range.clone() + )); + return Expr::err(range) }; match &mut result.data { desugared::ExprKind::Ctr { args, .. } => { - if let desugared::ExprKind::Var { name } = &mut args[0].data { - *name = sub.name.clone() - } - }, - _ => () + args[0] = self.desugar_expr(&sub.expr); + } + _ => (), } result } Get => value .iter() - .fold(Expr::var(sub.name.clone()), |acc, (name, field)| { - let name = name.add_segment(field.to_str()).add_segment("get"); + .fold(self.desugar_expr(&sub.expr), |acc, (typ, field)| { + let name = typ.add_segment(field.to_str()).add_segment("get"); + + if self.failed || !self.check_implementation(name.to_str(), range, Sugar::Getter(typ.to_string())) { + return desugared::Expr::err(range); + } + self.mk_desugared_ctr(range, name, vec![acc], false) }), } diff --git a/crates/kind-pass/src/desugar/mod.rs b/crates/kind-pass/src/desugar/mod.rs index 5316c412..1e542510 100644 --- a/crates/kind-pass/src/desugar/mod.rs +++ b/crates/kind-pass/src/desugar/mod.rs @@ -44,7 +44,9 @@ pub fn desugar_book( name_count: 0, failed: false, }; + state.desugar_book(book); + if state.failed { Err(GenericPassError.into()) } else { diff --git a/crates/kind-pass/src/desugar/record_field.rs b/crates/kind-pass/src/desugar/record_field.rs index ded1f45a..123d7d1b 100644 --- a/crates/kind-pass/src/desugar/record_field.rs +++ b/crates/kind-pass/src/desugar/record_field.rs @@ -1,4 +1,5 @@ use fxhash::FxHashMap; +use kind_span::Range; use kind_tree::{ concrete::{self, TopLevel}, desugared::{self, Expr}, @@ -6,7 +7,7 @@ use kind_tree::{ telescope::Telescope, }; -use crate::subst::subst_on_expr; +use crate::{subst::subst_on_expr, diagnostic::PassDiagnostic}; use super::DesugarState; @@ -45,12 +46,13 @@ impl<'a> DesugarState<'a> { pub fn desugar_record_field_sequence( &mut self, + range: Range, res: &mut Vec<(QualifiedIdent, Ident)>, typ: Box, fields: &[Ident], - ) { + ) -> bool { if fields.is_empty() { - return; + return true; } if let Some((name, params, record_fields, args)) = self.specialize_on_field(typ.clone()) { @@ -70,22 +72,26 @@ impl<'a> DesugarState<'a> { &field .typ .clone() - .unwrap_or_else(|| concrete::expr::Expr::typ(field.range.clone())), + .unwrap_or_else(|| concrete::expr::Expr::typ(field.range)), ); - subst_on_expr(&mut val, pair); - - println!("{}", val); - res.push((name, key)); - - self.desugar_record_field_sequence(res, val, &fields[1..]) + self.desugar_record_field_sequence(range, res, val, &fields[1..]); + return true; } else { - panic!("no field") + self.send_err(PassDiagnostic::CannotFindTheField( + fields[0].range, + fields[0].to_string() + )); } } else { - panic!("no record {}", typ) + self.send_err(PassDiagnostic::CannotAccessType( + fields[0].range, + fields[0].to_string() + )); } + + false } } diff --git a/crates/kind-pass/src/diagnostic.rs b/crates/kind-pass/src/diagnostic.rs index 1b881d5d..5a03033c 100644 --- a/crates/kind-pass/src/diagnostic.rs +++ b/crates/kind-pass/src/diagnostic.rs @@ -23,6 +23,8 @@ pub enum Sugar { BoolIf, String, U120, + Getter(String), + Mutter(String), Match(String), } @@ -54,6 +56,9 @@ pub enum PassDiagnostic { DuplicatedAttributeArgument(Range, Range), CannotDerive(String, Range), AttributeDoesNotExists(Range), + NeedsAField(Range), + CannotFindTheField(Range, String), + CannotAccessType(Range, String), } // TODO: A way to build an error message with methods @@ -85,6 +90,9 @@ impl Diagnostic for PassDiagnostic { PassDiagnostic::DuplicatedAttributeArgument(range, _) => Some(range.ctx), PassDiagnostic::CannotDerive(_, range) => Some(range.ctx), PassDiagnostic::AttributeDoesNotExists(range) => Some(range.ctx), + PassDiagnostic::NeedsAField(range) => Some(range.ctx), + PassDiagnostic::CannotFindTheField(range, _) => Some(range.ctx), + PassDiagnostic::CannotAccessType(range, _) => Some(range.ctx), } } @@ -216,7 +224,9 @@ impl Diagnostic for PassDiagnostic { Sugar::BoolIf => "You must implement 'Bool.if' in order to use the if notation.".to_string(), Sugar::String => "You must implement 'String.cons' in order to use the string notation.".to_string(), Sugar::U120 => "You must implement 'U120.new' in order to use the u120 notation.".to_string(), - Sugar::Match(_) => format!("You must implement 'match' in order to use the match notation (or derive match with #derive[match])."), + Sugar::Match(_) => "You must implement 'match' in order to use the match notation (or derive match with #derive[match]).".to_string(), + Sugar::Mutter(typ) => format!("You must derive 'mutters' for '{}' in order to use this syntax", typ), + Sugar::Getter(typ) => format!("You must derive 'getters' for '{}' in order to use this syntax", typ) }], positions: vec![Marker { position: *expr_place, @@ -574,7 +584,7 @@ impl Diagnostic for PassDiagnostic { }], }, PassDiagnostic::DuplicatedAttributeArgument(first, sec) => DiagnosticFrame { - code: 209, + code: 210, severity: Severity::Warning, title: "Duplicated attribute argument".to_string(), subtitles: vec![], @@ -593,6 +603,48 @@ impl Diagnostic for PassDiagnostic { main: true, }], }, + PassDiagnostic::NeedsAField(range) => DiagnosticFrame { + code: 211, + severity: Severity::Error, + title: "This expression does not access any field.".to_string(), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *range, + color: Color::Fst, + text: "Here!".to_string(), + no_code: false, + main: true, + }], + }, + PassDiagnostic::CannotFindTheField(range, _) => DiagnosticFrame { + code: 212, + severity: Severity::Error, + title: "Cannot find the field".to_string(), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *range, + color: Color::Fst, + text: "Here!".to_string(), + no_code: false, + main: true, + }], + }, + PassDiagnostic::CannotAccessType(range, _) => DiagnosticFrame { + code: 213, + severity: Severity::Error, + title: "Cannot access the type fields.".to_string(), + subtitles: vec![], + hints: vec!["This syntax only access some types, it does not make complete type directed syntax.".to_string()], + positions: vec![Marker { + position: *range, + color: Color::Fst, + text: "Here!".to_string(), + no_code: false, + main: true, + }], + }, } } @@ -623,7 +675,10 @@ impl Diagnostic for PassDiagnostic { | AttributeExpectsAValue(_) | DuplicatedAttributeArgument(_, _) | CannotDerive(_, _) - | AttributeDoesNotExists(_) => Severity::Error + | NeedsAField(_) + | CannotFindTheField(_, _) + | CannotAccessType(_, _) + | AttributeDoesNotExists(_) => Severity::Error, } } } diff --git a/crates/kind-pass/src/subst.rs b/crates/kind-pass/src/subst.rs index 8bca013b..8ef3fa22 100644 --- a/crates/kind-pass/src/subst.rs +++ b/crates/kind-pass/src/subst.rs @@ -53,7 +53,7 @@ fn subst(bindings: im_rc::HashSet, expr: &mut Expr, substs: &FxHashMap { subst(bindings.clone(), left, substs); - subst(bindings.clone(), right, substs); + subst(bindings, right, substs); }, _ => () } diff --git a/crates/kind-pass/src/unbound/mod.rs b/crates/kind-pass/src/unbound/mod.rs index 2398c9f6..bcee9f39 100644 --- a/crates/kind-pass/src/unbound/mod.rs +++ b/crates/kind-pass/src/unbound/mod.rs @@ -471,13 +471,10 @@ impl Visitor for UnboundCollector { fn visit_literal(&mut self, range: Range, lit: &mut kind_tree::concrete::Literal) { use kind_tree::concrete::Literal::*; - match lit { - String(_) => { - let string = &mut QualifiedIdent::new_static("String", None, range); - self.visit_qualified_ident(&mut string.add_segment("cons").to_generated()); - self.visit_qualified_ident(&mut string.add_segment("nil").to_generated()); - } - _ => (), + if let String(_) = lit { + let string = &mut QualifiedIdent::new_static("String", None, range); + self.visit_qualified_ident(&mut string.add_segment("cons").to_generated()); + self.visit_qualified_ident(&mut string.add_segment("nil").to_generated()); } } @@ -640,7 +637,7 @@ impl Visitor for UnboundCollector { self.visit_expr(&mut sec.typ); - self.visit_ident(&mut sec.name); + self.visit_expr(&mut sec.expr); match &mut sec.operation { Set(expr) => self.visit_expr(expr), diff --git a/crates/kind-tests/suite/run/GettersSyntax.golden b/crates/kind-tests/suite/run/GettersSyntax.golden new file mode 100644 index 00000000..105d7d9a --- /dev/null +++ b/crates/kind-tests/suite/run/GettersSyntax.golden @@ -0,0 +1 @@ +100 \ No newline at end of file diff --git a/crates/kind-tests/suite/run/GettersSyntax.kind2 b/crates/kind-tests/suite/run/GettersSyntax.kind2 new file mode 100644 index 00000000..9e0ecbd2 --- /dev/null +++ b/crates/kind-tests/suite/run/GettersSyntax.kind2 @@ -0,0 +1,20 @@ +type Sum { + a + b + c +} + +#derive[getters] +record Identity (t: Type) { + value: t +} + +#derive[getters] +record NoTypeVar { + some_thing: Identity (Identity U60) +} + +Main : U60 +Main = + let f = NoTypeVar.new (Identity.new (Identity.new 100)) + !NoTypeVar f .some_thing .value .value \ No newline at end of file diff --git a/crates/kind-tests/suite/run/MuttersSyntax.golden b/crates/kind-tests/suite/run/MuttersSyntax.golden new file mode 100644 index 00000000..23fe0964 --- /dev/null +++ b/crates/kind-tests/suite/run/MuttersSyntax.golden @@ -0,0 +1 @@ +(NoTypeVar.new (Identity.new (Identity.new 300))) \ No newline at end of file diff --git a/crates/kind-tests/suite/run/MuttersSyntax.kind2 b/crates/kind-tests/suite/run/MuttersSyntax.kind2 new file mode 100644 index 00000000..57e92a09 --- /dev/null +++ b/crates/kind-tests/suite/run/MuttersSyntax.kind2 @@ -0,0 +1,20 @@ +type Sum { + a + b + c +} + +#derive[mutters] +record Identity (t: Type) { + value: t +} + +#derive[mutters] +record NoTypeVar { + some_thing: Identity (Identity U60) +} + +Main : NoTypeVar +Main = + let f = NoTypeVar.new (Identity.new (Identity.new 100)) + !NoTypeVar f .some_thing .value .value @= x => (+ x 200) \ No newline at end of file diff --git a/crates/kind-tests/suite/run/SettersSyntax.golden b/crates/kind-tests/suite/run/SettersSyntax.golden new file mode 100644 index 00000000..103b0bfe --- /dev/null +++ b/crates/kind-tests/suite/run/SettersSyntax.golden @@ -0,0 +1 @@ +(NoTypeVar.new (Identity.new (Identity.new 400))) \ No newline at end of file diff --git a/crates/kind-tests/suite/run/SettersSyntax.kind2 b/crates/kind-tests/suite/run/SettersSyntax.kind2 new file mode 100644 index 00000000..a6e2c494 --- /dev/null +++ b/crates/kind-tests/suite/run/SettersSyntax.kind2 @@ -0,0 +1,20 @@ +type Sum { + a + b + c +} + +#derive[mutters] +record Identity (t: Type) { + value: t +} + +#derive[mutters] +record NoTypeVar { + some_thing: Identity (Identity U60) +} + +Main : NoTypeVar +Main = + let f = NoTypeVar.new (Identity.new (Identity.new 100)) + !NoTypeVar f .some_thing .value .value = 400 \ No newline at end of file diff --git a/crates/kind-tree/src/concrete/expr.rs b/crates/kind-tree/src/concrete/expr.rs index a1b76867..d703e05f 100644 --- a/crates/kind-tree/src/concrete/expr.rs +++ b/crates/kind-tree/src/concrete/expr.rs @@ -146,7 +146,7 @@ pub enum SeqOperation { #[derive(Clone, Debug)] pub struct SeqRecord { pub typ: Box, - pub name: Ident, + pub expr: Box, pub fields: Vec, pub operation: SeqOperation } @@ -593,7 +593,7 @@ impl Display for Expr { Hole => write!(f, "_"), SeqRecord(rec) => { use SeqOperation::*; - write!(f, "(!({}) {} {}", rec.typ, rec.name, rec.fields.iter().map(|x| format!(".{}", x.to_str())).collect::>().join(","))?; + write!(f, "(!({}) {} {}", rec.typ, rec.expr, rec.fields.iter().map(|x| format!(".{}", x.to_str())).collect::>().join(","))?; match &rec.operation { Set(expr) => write!(f, "+= {})", expr), Mut(expr) => write!(f, "@= {})", expr), diff --git a/crates/kind-tree/src/concrete/visitor.rs b/crates/kind-tree/src/concrete/visitor.rs index e840550c..5fa04db4 100644 --- a/crates/kind-tree/src/concrete/visitor.rs +++ b/crates/kind-tree/src/concrete/visitor.rs @@ -493,7 +493,7 @@ pub fn walk_expr(ctx: &mut T, expr: &mut Expr) { ExprKind::Subst(subst) => ctx.visit_substitution(subst), ExprKind::Match(matcher) => ctx.visit_match(matcher), ExprKind::SeqRecord(seq) => { - ctx.visit_ident(&mut seq.name); + ctx.visit_expr(&mut seq.expr); ctx.visit_expr(&mut seq.typ); match &mut seq.operation { From 2a7df0a3c76d91f006da6577f18f6971cf327c9a Mon Sep 17 00:00:00 2001 From: felipegchi Date: Tue, 24 Jan 2023 10:27:40 -0300 Subject: [PATCH 4/4] chore: fix newlines --- crates/kind-derive/src/subst.rs | 4 ---- crates/kind-parser/src/expr.rs | 8 -------- 2 files changed, 12 deletions(-) diff --git a/crates/kind-derive/src/subst.rs b/crates/kind-derive/src/subst.rs index 3eec615d..654ed608 100644 --- a/crates/kind-derive/src/subst.rs +++ b/crates/kind-derive/src/subst.rs @@ -290,17 +290,13 @@ impl<'a> Visitor for Subst<'a> { } ExprKind::SeqRecord(sec) => { use kind_tree::concrete::SeqOperation::*; - self.visit_expr(&mut sec.expr); - self.visit_expr(&mut sec.typ); - match &mut sec.operation { Set(expr) => self.visit_expr(expr), Mut(expr) => self.visit_expr(expr), Get => (), } - }, } } diff --git a/crates/kind-parser/src/expr.rs b/crates/kind-parser/src/expr.rs index e29eb75b..abdb8d03 100644 --- a/crates/kind-parser/src/expr.rs +++ b/crates/kind-parser/src/expr.rs @@ -881,23 +881,16 @@ impl<'a> Parser<'a> { pub fn parse_seq(&mut self) -> Result, SyntaxDiagnostic> { let start = self.range(); - self.eat_variant(Token::Bang)?; - let typ = self.parse_atom()?; - let name = self.parse_atom()?; - 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) { let expr = self.parse_expr(false)?; end = expr.range; @@ -909,7 +902,6 @@ impl<'a> Parser<'a> { } else { SeqOperation::Get }; - Ok(Box::new(Expr { data: ExprKind::SeqRecord( SeqRecord {