Skip to content

Commit

Permalink
Allow constructors share names with data types
Browse files Browse the repository at this point in the history
  • Loading branch information
imaqtkatt committed Mar 4, 2024
1 parent 3d7c4e8 commit a179e10
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 19 deletions.
63 changes: 55 additions & 8 deletions src/term/check/shared_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::fmt::Display;

use indexmap::IndexMap;

use crate::term::{Ctx, Name};
use crate::{
diagnostics,
term::{Ctx, Name},
};

#[derive(Debug, Clone)]
pub struct TopLevelErr(Name);
Expand All @@ -14,26 +17,70 @@ impl Display for TopLevelErr {
}

impl Ctx<'_> {
/// Checks if exists shared names from definitions, adts and constructors.
pub fn check_shared_names(&mut self) {
let mut checked = IndexMap::<&Name, usize>::new();
let mut checked = IndexMap::<&Name, NameInfo>::new();

for adt_name in self.book.adts.keys() {
*checked.entry(adt_name).or_default() += 1;
checked.entry(adt_name).or_insert(NameInfo::new(NameKind::Adt)).with_adt(adt_name, &mut self.info);
}

for ctr_name in self.book.ctrs.keys() {
*checked.entry(ctr_name).or_default() += 1;
checked.entry(ctr_name).or_insert(NameInfo::new(NameKind::Ctr)).with_ctr(ctr_name, &mut self.info);
}

for def_name in self.book.defs.keys() {
*checked.entry(def_name).or_default() += 1;
checked.entry(def_name).or_insert(NameInfo::new(NameKind::Def)).with_def(def_name, &mut self.info);
}

for (name, n) in checked.into_iter() {
if n > 1 {
for (name, name_info) in checked.into_iter() {
if name_info.count > 1 {
self.info.error(TopLevelErr(name.clone()));
}
}
}
}

#[derive(Debug)]
enum NameKind {
Adt,
Def,
Ctr,
}

#[derive(Debug)]
struct NameInfo {
kind: NameKind,
count: usize,
}

impl NameInfo {
fn new(kind: NameKind) -> Self {
Self { kind, count: 0 }
}
}

impl NameInfo {
fn with_ctr(&mut self, current_name: &Name, info: &mut diagnostics::Info) {
match self.kind {
NameKind::Adt => {} // Catch by the parser
NameKind::Def => info.error(TopLevelErr(current_name.clone())),
NameKind::Ctr => {} // Catch by the parser
}
}

fn with_def(&mut self, current_name: &Name, info: &mut diagnostics::Info) {
match self.kind {
NameKind::Adt => self.count += 1,
NameKind::Def => {}
NameKind::Ctr => info.error(TopLevelErr(current_name.clone())),
}
}

fn with_adt(&mut self, current_name: &Name, info: &mut diagnostics::Info) {
match self.kind {
NameKind::Adt => self.count += 1,
NameKind::Def => info.error(TopLevelErr(current_name.clone())),
NameKind::Ctr => self.count += 1,
}
}
}
8 changes: 4 additions & 4 deletions src/term/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use chumsky::{
util::MaybeRef,
IterParser, Parser,
};
use indexmap::{map::Entry, IndexMap};
use indexmap::map::Entry;
use logos::{Logos, SpannedIter};
use std::{iter::Map, ops::Range, path::Path};

Expand Down Expand Up @@ -521,14 +521,14 @@ fn collect_book(
}
TopLevel::Adt((nam, nam_span), adt) => match book.adts.get(&nam) {
None => {
let (ctrs, spans): (IndexMap<_, _>, Vec<_>) = adt.into_iter().unzip();
let (ctrs, spans): (Vec<(_, _)>, Vec<_>) = adt.into_iter().unzip();

for ((ctr, _), span) in ctrs.iter().zip(spans.into_iter()) {
match book.ctrs.entry(ctr.clone()) {
Entry::Vacant(e) => _ = e.insert(nam.clone()),
Entry::Occupied(e) => emit.emit(Rich::custom(
span,
if book.adts[e.get()].builtin {
if book.adts.get(e.get()).is_some_and(|adt| adt.builtin) {
format!("{} is a built-in constructor and should not be overridden.", e.key())
} else {
format!("Repeated constructor '{}'", e.key())
Expand All @@ -537,7 +537,7 @@ fn collect_book(
}
}

let adt = Adt { ctrs, builtin };
let adt = Adt { ctrs: ctrs.into_iter().collect(), builtin };
book.adts.insert(nam.clone(), adt);
}
Some(adt) => emit.emit(Rich::custom(
Expand Down
1 change: 1 addition & 0 deletions tests/golden_tests/compile_file/error_messages.hvm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
data A = (A)
data B = (B)
data C = (B)

Foo (C) = *
Foo (D) = *
Expand Down
9 changes: 2 additions & 7 deletions tests/snapshots/compile_file__error_messages.hvm.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,5 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file/error_messages.hvm
---
Duplicated top-level name 'A'.
Duplicated top-level name 'B'.
In definition 'Foo':
Unbound constructor 'C'.
Unbound constructor 'D'.
In definition 'Foo2':
Unbound constructor 'E'.
At tests/golden_tests/compile_file/error_messages.hvm:3:10: Repeated constructor 'B'
 3 | data C = (B)

0 comments on commit a179e10

Please sign in to comment.