mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-11-05 04:51:40 +03:00
Merge pull request #133 from HigherOrderCO/feature/sc-359/don-t-allow-main-to-be-called-by-any-functions
[sc-359] Don't allow main to be called by any functions
This commit is contained in:
commit
542383df16
@ -42,7 +42,7 @@ pub fn desugar_book(book: &mut Book, opt_level: OptimizationLevel) -> Result<Def
|
||||
book.encode_strs()?;
|
||||
book.encode_lists()?;
|
||||
book.generate_scott_adts();
|
||||
book.resolve_refs();
|
||||
book.resolve_refs()?;
|
||||
encode_pattern_matching(book)?;
|
||||
book.normalize_native_matches()?;
|
||||
book.check_unbound_vars()?;
|
||||
|
@ -6,52 +6,57 @@ impl Book {
|
||||
/// Decides if names inside a term belong to a Var or to a Ref.
|
||||
/// Precondition: Refs are encoded as vars.
|
||||
/// Postcondition: Refs are encoded as refs, with the correct def id.
|
||||
pub fn resolve_refs(&mut self) {
|
||||
pub fn resolve_refs(&mut self) -> Result<(), String> {
|
||||
for def in self.defs.values_mut() {
|
||||
for rule in def.rules.iter_mut() {
|
||||
rule.body.resolve_refs(&self.def_names);
|
||||
rule.body.resolve_refs(&self.def_names)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Term {
|
||||
pub fn resolve_refs(&mut self, def_names: &DefNames) {
|
||||
pub fn resolve_refs(&mut self, def_names: &DefNames) -> Result<(), String> {
|
||||
resolve_refs(self, def_names, &mut HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_refs(term: &mut Term, def_names: &DefNames, scope: &mut HashMap<Name, usize>) {
|
||||
fn resolve_refs(
|
||||
term: &mut Term,
|
||||
def_names: &DefNames,
|
||||
scope: &mut HashMap<Name, usize>,
|
||||
) -> Result<(), String> {
|
||||
match term {
|
||||
Term::Lam { nam, bod, .. } => {
|
||||
push_scope(nam.clone(), scope);
|
||||
resolve_refs(bod, def_names, scope);
|
||||
resolve_refs(bod, def_names, scope)?;
|
||||
pop_scope(nam.clone(), scope);
|
||||
}
|
||||
Term::Let { pat: Pattern::Var(nam), val, nxt } => {
|
||||
resolve_refs(val, def_names, scope);
|
||||
resolve_refs(val, def_names, scope)?;
|
||||
push_scope(nam.clone(), scope);
|
||||
resolve_refs(nxt, def_names, scope);
|
||||
resolve_refs(nxt, def_names, scope)?;
|
||||
pop_scope(nam.clone(), scope);
|
||||
}
|
||||
Term::Let { pat, val, nxt } => {
|
||||
resolve_refs(val, def_names, scope);
|
||||
resolve_refs(val, def_names, scope)?;
|
||||
|
||||
for nam in pat.names() {
|
||||
push_scope(Some(nam.clone()), scope)
|
||||
}
|
||||
|
||||
resolve_refs(nxt, def_names, scope);
|
||||
resolve_refs(nxt, def_names, scope)?;
|
||||
|
||||
for nam in pat.names() {
|
||||
pop_scope(Some(nam.clone()), scope)
|
||||
}
|
||||
}
|
||||
Term::Dup { tag: _, fst, snd, val, nxt } => {
|
||||
resolve_refs(val, def_names, scope);
|
||||
resolve_refs(val, def_names, scope)?;
|
||||
push_scope(fst.clone(), scope);
|
||||
push_scope(snd.clone(), scope);
|
||||
resolve_refs(nxt, def_names, scope);
|
||||
resolve_refs(nxt, def_names, scope)?;
|
||||
pop_scope(fst.clone(), scope);
|
||||
pop_scope(snd.clone(), scope);
|
||||
}
|
||||
@ -59,27 +64,31 @@ fn resolve_refs(term: &mut Term, def_names: &DefNames, scope: &mut HashMap<Name,
|
||||
// If variable not defined, we check if it's a ref and swap if it is.
|
||||
Term::Var { nam } => {
|
||||
if is_var_in_scope(nam.clone(), scope) {
|
||||
if matches!(nam.0.as_ref(), DefNames::ENTRY_POINT | DefNames::HVM1_ENTRY_POINT) {
|
||||
return Err("Main definition can't be referenced inside the program".to_string());
|
||||
}
|
||||
|
||||
if let Some(def_id) = def_names.def_id(nam) {
|
||||
*term = Term::Ref { def_id };
|
||||
}
|
||||
}
|
||||
}
|
||||
Term::Chn { bod, .. } => resolve_refs(bod, def_names, scope),
|
||||
Term::Chn { bod, .. } => resolve_refs(bod, def_names, scope)?,
|
||||
Term::App { fun: fst, arg: snd, .. }
|
||||
| Term::Sup { fst, snd, .. }
|
||||
| Term::Tup { fst, snd }
|
||||
| Term::Opx { fst, snd, .. } => {
|
||||
resolve_refs(fst, def_names, scope);
|
||||
resolve_refs(snd, def_names, scope);
|
||||
resolve_refs(fst, def_names, scope)?;
|
||||
resolve_refs(snd, def_names, scope)?;
|
||||
}
|
||||
Term::Match { scrutinee, arms } => {
|
||||
resolve_refs(scrutinee, def_names, scope);
|
||||
resolve_refs(scrutinee, def_names, scope)?;
|
||||
for (pat, term) in arms {
|
||||
if let Pattern::Num(MatchNum::Succ(Some(nam))) = pat {
|
||||
push_scope(nam.clone(), scope)
|
||||
}
|
||||
|
||||
resolve_refs(term, def_names, scope);
|
||||
resolve_refs(term, def_names, scope)?;
|
||||
|
||||
if let Pattern::Num(MatchNum::Succ(Some(nam))) = pat {
|
||||
pop_scope(nam.clone(), scope)
|
||||
@ -89,6 +98,8 @@ fn resolve_refs(term: &mut Term, def_names: &DefNames, scope: &mut HashMap<Name,
|
||||
Term::List { .. } => unreachable!("Should have been desugared already"),
|
||||
Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push_scope(name: Option<Name>, scope: &mut HashMap<Name, usize>) {
|
||||
|
@ -15,10 +15,10 @@ impl Book {
|
||||
let mut ref_id = def_id;
|
||||
let mut is_ref_to_ref = false;
|
||||
while let Term::Ref { def_id: next_ref_id } = &self.defs.get(ref_id).unwrap().rules[0].body {
|
||||
if next_ref_id == def_id {
|
||||
if next_ref_id == ref_id {
|
||||
return Err(format!(
|
||||
"Definition {} is a reference to itself",
|
||||
self.def_names.name(def_id).unwrap()
|
||||
self.def_names.name(ref_id).unwrap()
|
||||
));
|
||||
}
|
||||
ref_id = next_ref_id;
|
||||
|
@ -170,7 +170,7 @@ fn encode_pattern_match() {
|
||||
book.encode_strs()?;
|
||||
book.encode_lists()?;
|
||||
book.generate_scott_adts();
|
||||
book.resolve_refs();
|
||||
book.resolve_refs()?;
|
||||
encode_pattern_matching(&mut book)?;
|
||||
Ok(book.to_string())
|
||||
})
|
||||
|
2
tests/golden_tests/compile_file/ref_to_main.hvm
Normal file
2
tests/golden_tests/compile_file/ref_to_main.hvm
Normal file
@ -0,0 +1,2 @@
|
||||
Foo = Main
|
||||
main = Foo
|
@ -1 +1,2 @@
|
||||
main = main
|
||||
Foo = Foo
|
||||
main = Foo
|
@ -1 +0,0 @@
|
||||
Main = λa Main
|
@ -1 +0,0 @@
|
||||
main = λa main
|
5
tests/snapshots/compile_file__ref_to_main.hvm.snap
Normal file
5
tests/snapshots/compile_file__ref_to_main.hvm.snap
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/compile_file/ref_to_main.hvm
|
||||
---
|
||||
Main definition can't be referenced inside the program
|
@ -2,4 +2,4 @@
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/compile_file/self_ref.hvm
|
||||
---
|
||||
Definition main is a reference to itself
|
||||
Definition Foo is a reference to itself
|
||||
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/run_file/readback_hvm1_main.hvm
|
||||
---
|
||||
λ* Main
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/run_file/readback_hvm2_main.hvm
|
||||
---
|
||||
λ* main
|
Loading…
Reference in New Issue
Block a user