Skip to content

Commit

Permalink
Merge pull request #625 from HigherOrderCO/multi-line-comments
Browse files Browse the repository at this point in the history
Add multi line comment syntax
  • Loading branch information
imaqtkatt authored Jul 10, 2024
2 parents 29f2098 + 6020fba commit 6bbc223
Show file tree
Hide file tree
Showing 16 changed files with 304 additions and 89 deletions.
12 changes: 8 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ and this project does not currently adhere to a particular versioning scheme.

- Fix variable binding in pattern matching when the irrefutable pattern optimization occurs. ([#618][gh-618])
- Don't warn on unused generated definitions. ([#514][gh-514])
- Fix local definitions not being desugared properly. ([#623][gh-623])

### Added

- Add import system ([#544][gh-544])
- Add import system. ([#544][gh-544])
- Add multi line comment `#{ ... #}` syntax. ([#595][gh-595])

## [0.2.36] - 2024-07-04

Expand Down Expand Up @@ -370,9 +372,11 @@ and this project does not currently adhere to a particular versioning scheme.
[gh-494]: https://github.com/HigherOrderCO/Bend/issues/494
[gh-502]: https://github.com/HigherOrderCO/Bend/issues/502
[gh-512]: https://github.com/HigherOrderCO/Bend/issues/512
[gh-514]: https://github.com/HigherOrderCO/Bend/issues/514
[gh-516]: https://github.com/HigherOrderCO/Bend/issues/516
[gh-526]: https://github.com/HigherOrderCO/Bend/issues/526
[gh-528]: https://github.com/HigherOrderCO/Bend/issues/528
[gh-544]: https://github.com/HigherOrderCO/Bend/pull/544
[gh-562]: https://github.com/HigherOrderCO/Bend/issues/562
[gh-570]: https://github.com/HigherOrderCO/Bend/issues/570
[gh-573]: https://github.com/HigherOrderCO/Bend/issues/573
Expand All @@ -383,9 +387,9 @@ and this project does not currently adhere to a particular versioning scheme.
[gh-582]: https://github.com/HigherOrderCO/Bend/issues/582
[gh-583]: https://github.com/HigherOrderCO/Bend/issues/583
[gh-586]: https://github.com/HigherOrderCO/Bend/issues/586
[gh-595]: https://github.com/HigherOrderCO/Bend/issues/595
[gh-596]: https://github.com/HigherOrderCO/Bend/issues/596
[gh-598]: https://github.com/HigherOrderCO/Bend/issues/598
[gh-618]: https://github.com/HigherOrderCO/Bend/issues/618
[gh-514]: https://github.com/HigherOrderCO/Bend/issues/514
[gh-544]: https://github.com/HigherOrderCO/Bend/pull/544
[gh-623]: https://github.com/HigherOrderCO/Bend/issues/623
[Unreleased]: https://github.com/HigherOrderCO/Bend/compare/0.2.36...HEAD
[gh-598]: https://github.com/HigherOrderCO/Bend/issues/598
7 changes: 7 additions & 0 deletions src/fun/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ impl Term {
Term::List { els } => *self = Term::encode_list(std::mem::take(els)),
Term::Str { val } => *self = Term::encode_str(val),
Term::Nat { val } => *self = Term::encode_nat(*val),
Term::Def { def, nxt } => {
for rule in def.rules.iter_mut() {
rule.pats.iter_mut().for_each(Pattern::encode_builtins);
rule.body.encode_builtins();
}
nxt.encode_builtins();
}
_ => {
for child in self.children_mut() {
child.encode_builtins();
Expand Down
14 changes: 7 additions & 7 deletions src/fun/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ impl fmt::Display for Term {
}
Term::List { els } => write!(f, "[{}]", DisplayJoin(|| els.iter(), ", "),),
Term::Open { typ, var, bod } => write!(f, "open {typ} {var}; {bod}"),
Term::Def { nam, rules, nxt } => {
Term::Def { def, nxt } => {
write!(f, "def ")?;
for rule in rules.iter() {
write!(f, "{}", rule.display(nam))?;
for rule in def.rules.iter() {
write!(f, "{}", rule.display(&def.name))?;
}
write!(f, "{nxt}")
}
Expand Down Expand Up @@ -500,13 +500,13 @@ impl Term {
Term::Num { val: Num::F24(val) } => write!(f, "{val:.3}"),
Term::Str { val } => write!(f, "{val:?}"),
Term::Ref { nam } => write!(f, "{nam}"),
Term::Def { nam, rules, nxt } => {
Term::Def { def, nxt } => {
write!(f, "def ")?;
for (i, rule) in rules.iter().enumerate() {
for (i, rule) in def.rules.iter().enumerate() {
if i == 0 {
writeln!(f, "{}", rule.display_def_aux(nam, tab + 4))?;
writeln!(f, "{}", rule.display_def_aux(&def.name, tab + 4))?;
} else {
writeln!(f, "{:tab$}{}", "", rule.display_def_aux(nam, tab + 4), tab = tab + 4)?;
writeln!(f, "{:tab$}{}", "", rule.display_def_aux(&def.name, tab + 4), tab = tab + 4)?;
}
}
write!(f, "{:tab$}{}", "", nxt.display_pretty(tab))
Expand Down
9 changes: 4 additions & 5 deletions src/fun/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ pub type Adts = IndexMap<Name, Adt>;
pub type Constructors = IndexMap<Name, Name>;

/// A pattern matching function definition.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Definition {
pub name: Name,
pub rules: Vec<Rule>,
pub source: Source,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Source {
Builtin,
/// Was generated by the compiler.
Expand Down Expand Up @@ -199,8 +199,7 @@ pub enum Term {
nam: Name,
},
Def {
nam: Name,
rules: Vec<Rule>,
def: Definition,
nxt: Box<Term>,
},
Era,
Expand Down Expand Up @@ -402,7 +401,7 @@ impl Clone for Term {
Self::Open { typ: typ.clone(), var: var.clone(), bod: nxt.clone() }
}
Self::Ref { nam } => Self::Ref { nam: nam.clone() },
Self::Def { nam, rules, nxt } => Self::Def { nam: nam.clone(), rules: rules.clone(), nxt: nxt.clone() },
Self::Def { def, nxt } => Self::Def { def: def.clone(), nxt: nxt.clone() },
Self::Era => Self::Era,
Self::Err => Self::Err,
})
Expand Down
60 changes: 51 additions & 9 deletions src/fun/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,8 @@ impl<'a> TermParser<'a> {
if name == "def" {
// parse the nxt def term.
self.index = nxt_def;
return Ok(Term::Def { nam: cur_name, rules, nxt: Box::new(self.parse_term()?) });
let def = FunDefinition::new(name, rules, Source::Local(nxt_def..*self.index()));
return Ok(Term::Def { def, nxt: Box::new(self.parse_term()?) });
}
if name == cur_name {
rules.push(rule);
Expand All @@ -648,7 +649,8 @@ impl<'a> TermParser<'a> {
}
}
let nxt = self.parse_term()?;
return Ok(Term::Def { nam: cur_name, rules, nxt: Box::new(nxt) });
let def = FunDefinition::new(cur_name, rules, Source::Local(nxt_term..*self.index()));
return Ok(Term::Def { def, nxt: Box::new(nxt) });
}

// If
Expand Down Expand Up @@ -1093,14 +1095,31 @@ impl<'a> Parser<'a> for TermParser<'a> {
continue;
}
if c == '#' {
while let Some(c) = self.peek_one() {
if c != '\n' {
self.advance_one();
if let Some(c) = self.peek_one() {
if c == '{' {
self.advance_one();
while let Some(c) = self.peek_one() {
self.advance_one();
if c == '#' {
if let Some('}') = self.peek_one() {
self.advance_one();
break;
} else {
self.advance_one();
}
}
}
} else {
break;
while let Some(c) = self.peek_one() {
if c != '\n' {
self.advance_one();
} else {
break;
}
}
}
}
self.advance_one(); // Skip the newline character as well
continue;
}
break;
Expand Down Expand Up @@ -1243,12 +1262,35 @@ pub trait ParserCommons<'a>: Parser<'a> {
continue;
}
if c == '#' {
while let Some(c) = self.peek_one() {
if c != '\n' {
self.advance_one();
char_count += 1;
if let Some(c) = self.peek_one() {
if c == '{' {
self.advance_one();
char_count += 1;
while let Some(c) = self.peek_one() {
self.advance_one();
char_count += 1;
if c == '#' {
if let Some('}') = self.peek_one() {
self.advance_one();
char_count += 1;
break;
} else {
self.advance_one();
char_count += 1;
}
}
}
} else {
break;
while let Some(c) = self.peek_one() {
if c != '\n' {
self.advance_one();
char_count += 1;
} else {
break;
}
}
}
}
continue;
Expand Down
23 changes: 22 additions & 1 deletion src/fun/transform/desugar_match_defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ impl Ctx<'_> {
impl Definition {
pub fn desugar_match_def(&mut self, ctrs: &Constructors, adts: &Adts) -> Vec<DesugarMatchDefErr> {
let mut errs = vec![];

for rule in self.rules.iter_mut() {
desugar_inner_match_defs(&mut rule.body, ctrs, adts, &mut errs);
}
let repeated_bind_errs = fix_repeated_binds(&mut self.rules);
errs.extend(repeated_bind_errs);

Expand All @@ -55,6 +57,25 @@ impl Definition {
}
}

fn desugar_inner_match_defs(
term: &mut Term,
ctrs: &Constructors,
adts: &Adts,
errs: &mut Vec<DesugarMatchDefErr>,
) {
maybe_grow(|| match term {
Term::Def { def, nxt } => {
errs.extend(def.desugar_match_def(ctrs, adts));
desugar_inner_match_defs(nxt, ctrs, adts, errs);
}
_ => {
for child in term.children_mut() {
desugar_inner_match_defs(child, ctrs, adts, errs);
}
}
})
}

/// When a rule has repeated bind, the only one that is actually useful is the last one.
///
/// Example: In `(Foo x x x x) = x`, the function should return the fourth argument.
Expand Down
43 changes: 27 additions & 16 deletions src/fun/transform/desugar_open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,37 @@ impl Ctx<'_> {
impl Term {
fn desugar_open(&mut self, adts: &Adts) -> Result<(), String> {
maybe_grow(|| {
if let Term::Open { typ, var, bod } = self {
if let Some(adt) = adts.get(&*typ) {
if adt.ctrs.len() == 1 {
let ctr = adt.ctrs.keys().next().unwrap();
*self = Term::Mat {
arg: Box::new(Term::Var { nam: var.clone() }),
bnd: Some(std::mem::take(var)),
with_bnd: vec![],
with_arg: vec![],
arms: vec![(Some(ctr.clone()), vec![], std::mem::take(bod))],
match self {
Term::Open { typ, var, bod } => {
bod.desugar_open(adts)?;
if let Some(adt) = adts.get(&*typ) {
if adt.ctrs.len() == 1 {
let ctr = adt.ctrs.keys().next().unwrap();
*self = Term::Mat {
arg: Box::new(Term::Var { nam: var.clone() }),
bnd: Some(std::mem::take(var)),
with_bnd: vec![],
with_arg: vec![],
arms: vec![(Some(ctr.clone()), vec![], std::mem::take(bod))],
}
} else {
return Err(format!("Type '{typ}' of an 'open' has more than one constructor"));
}
} else {
return Err(format!("Type '{typ}' of an 'open' has more than one constructor"));
return Err(format!("Type '{typ}' of an 'open' is not defined"));
}
}
Term::Def { def, nxt } => {
for rule in def.rules.iter_mut() {
rule.body.desugar_open(adts)?;
}
nxt.desugar_open(adts)?;
}
_ => {
for child in self.children_mut() {
child.desugar_open(adts)?;
}
} else {
return Err(format!("Type '{typ}' of an 'open' is not defined"));
}
}
for child in self.children_mut() {
child.desugar_open(adts)?;
}
Ok(())
})
Expand Down
53 changes: 40 additions & 13 deletions src/fun/transform/fix_match_defs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
diagnostics::Diagnostics,
fun::{Adts, Constructors, Ctx, Pattern},
fun::{Adts, Constructors, Ctx, Pattern, Rule, Term},
};

impl Ctx<'_> {
Expand All @@ -15,18 +15,7 @@ impl Ctx<'_> {

let def_arity = def.arity();
for rule in &mut def.rules {
if rule.arity() != def_arity {
errs.push(format!(
"Incorrect pattern matching rule arity. Expected {} args, found {}.",
def_arity,
rule.arity()
));
}

for pat in &mut rule.pats {
pat.resolve_pat(&self.book.ctrs);
pat.check_good_ctr(&self.book.ctrs, &self.book.adts, &mut errs);
}
rule.fix_match_defs(def_arity, &self.book.ctrs, &self.book.adts, &mut errs);
}

for err in errs {
Expand All @@ -38,6 +27,44 @@ impl Ctx<'_> {
}
}

impl Rule {
fn fix_match_defs(&mut self, def_arity: usize, ctrs: &Constructors, adts: &Adts, errs: &mut Vec<String>) {
if self.arity() != def_arity {
errs.push(format!(
"Incorrect pattern matching rule arity. Expected {} args, found {}.",
def_arity,
self.arity()
));
}

for pat in &mut self.pats {
pat.resolve_pat(ctrs);
pat.check_good_ctr(ctrs, adts, errs);
}

self.body.fix_match_defs(ctrs, adts, errs);
}
}

impl Term {
fn fix_match_defs(&mut self, ctrs: &Constructors, adts: &Adts, errs: &mut Vec<String>) {
match self {
Term::Def { def, nxt } => {
let def_arity = def.arity();
for rule in &mut def.rules {
rule.fix_match_defs(def_arity, ctrs, adts, errs);
}
nxt.fix_match_defs(ctrs, adts, errs);
}
_ => {
for children in self.children_mut() {
children.fix_match_defs(ctrs, adts, errs);
}
}
}
}
}

impl Pattern {
/// If a var pattern actually refers to an ADT constructor, convert it into a constructor pattern.
fn resolve_pat(&mut self, ctrs: &Constructors) {
Expand Down
8 changes: 7 additions & 1 deletion src/fun/transform/fix_match_terms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,14 @@ impl Term {
if matches!(self, Term::Mat { .. } | Term::Fold { .. }) {
self.fix_match(&mut errs, ctrs, adts);
}
// Add a use term to each arm rebuilding the matched variable
match self {
Term::Def { def, nxt } => {
for rule in def.rules.iter_mut() {
errs.extend(rule.body.fix_match_terms(ctrs, adts));
}
errs.extend(nxt.fix_match_terms(ctrs, adts));
}
// Add a use term to each arm rebuilding the matched variable
Term::Mat { arg: _, bnd, with_bnd: _, with_arg: _, arms }
| Term::Fold { bnd, arg: _, with_bnd: _, with_arg: _, arms } => {
for (ctr, fields, body) in arms {
Expand Down
Loading

0 comments on commit 6bbc223

Please sign in to comment.