mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 11:56:54 +03:00
Make rules necessarily be in a single block
This commit is contained in:
parent
a58d5aae89
commit
e81f990208
@ -62,8 +62,10 @@ impl<'a> TermParser<'a> {
|
||||
pub fn parse_book(&mut self, default_book: Book, builtin: bool) -> ParseResult<Book> {
|
||||
let mut book = default_book;
|
||||
let mut indent = self.advance_newlines();
|
||||
let mut last_rule = None;
|
||||
while !self.is_eof() {
|
||||
let ini_idx = *self.index();
|
||||
|
||||
// Imp type definition
|
||||
if self.try_parse_keyword("type") {
|
||||
let mut prs = PyParser { input: self.input, index: *self.index() };
|
||||
@ -72,6 +74,7 @@ impl<'a> TermParser<'a> {
|
||||
let end_idx = *self.index();
|
||||
prs.add_type(enum_, &mut book, ini_idx, end_idx, builtin)?;
|
||||
indent = nxt_indent;
|
||||
last_rule = None;
|
||||
continue;
|
||||
}
|
||||
// Imp record type definition
|
||||
@ -82,8 +85,10 @@ impl<'a> TermParser<'a> {
|
||||
let end_idx = *self.index();
|
||||
prs.add_object(obj, &mut book, ini_idx, end_idx, builtin)?;
|
||||
indent = nxt_indent;
|
||||
last_rule = None;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Imp function definition
|
||||
if self.try_parse_keyword("def") {
|
||||
let mut prs = PyParser { input: self.input, index: *self.index() };
|
||||
@ -92,20 +97,46 @@ impl<'a> TermParser<'a> {
|
||||
let end_idx = *self.index();
|
||||
prs.add_def(def, &mut book, ini_idx, end_idx)?;
|
||||
indent = nxt_indent;
|
||||
last_rule = None;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fun type definition
|
||||
if self.try_parse_keyword("data") {
|
||||
let (nam, adt) = self.parse_datatype(builtin)?;
|
||||
let end_idx = *self.index();
|
||||
self.with_ctx(book.add_adt(nam, adt), ini_idx, end_idx)?;
|
||||
indent = self.advance_newlines();
|
||||
last_rule = None;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fun function definition
|
||||
let ini_idx = *self.index();
|
||||
let (name, rule) = self.parse_rule()?;
|
||||
book.add_rule(name, rule, builtin);
|
||||
let end_idx = *self.index();
|
||||
// Add to book
|
||||
if let Some(def) = book.defs.get_mut(&name) {
|
||||
if let Some(last_rule) = last_rule {
|
||||
if last_rule == name {
|
||||
// Continuing with a new rule to the current definition
|
||||
def.rules.push(rule);
|
||||
} else {
|
||||
// Trying to add a new rule to a previous definition, coming from a different rule.
|
||||
let msg = format!("Redefinition of function '{name}'");
|
||||
return self.with_ctx(Err(msg), ini_idx, end_idx);
|
||||
}
|
||||
} else {
|
||||
// Trying to add a new rule to a previous definition, coming from another kind of top-level.
|
||||
let msg = format!("Redefinition of function '{name}'");
|
||||
return self.with_ctx(Err(msg), ini_idx, end_idx);
|
||||
}
|
||||
} else {
|
||||
// Adding the first rule of a new definition
|
||||
book.defs.insert(name.clone(), Definition { name: name.clone(), rules: vec![rule], builtin });
|
||||
}
|
||||
indent = self.advance_newlines();
|
||||
last_rule = Some(name);
|
||||
}
|
||||
|
||||
Ok(book)
|
||||
@ -756,14 +787,6 @@ impl Book {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_rule(&mut self, name: Name, rule: Rule, builtin: bool) {
|
||||
if let Some(def) = self.defs.get_mut(&name) {
|
||||
def.rules.push(rule);
|
||||
} else {
|
||||
self.defs.insert(name.clone(), Definition { name, rules: vec![rule], builtin });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ParserCommons<'a> for TermParser<'a> {}
|
||||
@ -789,13 +812,8 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
}
|
||||
|
||||
fn parse_bend_name(&mut self) -> ParseResult<Name> {
|
||||
let nam = self.parse_exactly_name()?;
|
||||
Ok(Name::new(nam))
|
||||
}
|
||||
|
||||
fn parse_exactly_name(&mut self) -> ParseResult<String> {
|
||||
let name = self.take_while(|c| c.is_ascii_alphanumeric() || c == '_' || c == '.' || c == '-' || c == '/');
|
||||
if name.is_empty() { self.expected("name") } else { Ok(name.to_owned()) }
|
||||
if name.is_empty() { self.expected("name") } else { Ok(Name::new(name.to_owned())) }
|
||||
}
|
||||
|
||||
/// Consumes exactly the text without skipping.
|
||||
@ -862,14 +880,6 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
self.advance_trivia_inline();
|
||||
}
|
||||
|
||||
fn skip_trivia_maybe_inline(&mut self, inline: bool) {
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_spanned<T>(&mut self, exp: &str, ini_idx: usize, end_idx: usize) -> ParseResult<T> {
|
||||
let is_eof = self.is_eof();
|
||||
let detected = DisplayFn(|f| if is_eof { write!(f, " end of input") } else { Ok(()) });
|
||||
|
@ -90,7 +90,11 @@ impl<'a> PyParser<'a> {
|
||||
/// <var> <postfix>?
|
||||
///
|
||||
fn parse_simple_expr(&mut self, inline: bool) -> ParseResult<Expr> {
|
||||
self.skip_trivia_maybe_inline(inline);
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
let Some(head) = self.peek_one() else { return self.expected("expression")? };
|
||||
|
||||
let ini_idx = *self.index();
|
||||
@ -133,7 +137,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
}
|
||||
// List or Comprehension
|
||||
'[' => self.list_or_comprehension()?,
|
||||
'[' => self.parse_list_or_comprehension()?,
|
||||
// Symbol
|
||||
'`' => Expr::Num { val: Num::U24(self.parse_quoted_symbol()?) },
|
||||
// String
|
||||
@ -173,7 +177,11 @@ impl<'a> PyParser<'a> {
|
||||
let end_idx = *self.index();
|
||||
|
||||
// postfixes
|
||||
self.skip_trivia_maybe_inline(inline);
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
// call
|
||||
if self.starts_with("(") {
|
||||
self.advance_one();
|
||||
@ -265,7 +273,7 @@ impl<'a> PyParser<'a> {
|
||||
Ok((key, val))
|
||||
}
|
||||
|
||||
fn list_or_comprehension(&mut self) -> ParseResult<Expr> {
|
||||
fn parse_list_or_comprehension(&mut self) -> ParseResult<Expr> {
|
||||
self.consume_exactly("[")?;
|
||||
|
||||
// Empty list
|
||||
@ -316,7 +324,11 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
self.skip_trivia_maybe_inline(inline);
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
|
||||
// lambda
|
||||
if self.try_parse_keyword("lambda") | self.try_consume_exactly("λ") {
|
||||
@ -350,18 +362,26 @@ impl<'a> PyParser<'a> {
|
||||
/// <simple> (<infix_op> <infix>)?
|
||||
fn parse_infix_expr(&mut self, prec: usize, inline: bool) -> ParseResult<Expr> {
|
||||
maybe_grow(|| {
|
||||
self.skip_trivia_maybe_inline(inline);
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
if prec > PREC.len() - 1 {
|
||||
return self.parse_simple_expr(inline);
|
||||
}
|
||||
let mut lhs = self.parse_infix_expr(prec + 1, inline)?;
|
||||
self.skip_trivia_maybe_inline(inline);
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
while let Some(op) = self.peek_oper() {
|
||||
if PREC[prec].iter().any(|r| *r == op) {
|
||||
self.parse_oper()?;
|
||||
let rhs = self.parse_infix_expr(prec + 1, inline)?;
|
||||
lhs = Expr::Bin { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
|
||||
self.advance_trivia_inline();
|
||||
self.skip_trivia_inline();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -423,7 +443,7 @@ impl<'a> PyParser<'a> {
|
||||
let ini_idx = *self.index();
|
||||
let pat = self.parse_assign_pattern()?;
|
||||
let end_idx = *self.index();
|
||||
self.advance_trivia_inline();
|
||||
self.skip_trivia_inline();
|
||||
|
||||
// Assignment
|
||||
if self.starts_with("=") {
|
||||
@ -472,7 +492,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_in_place_op(&mut self) -> ParseResult<Option<InPlaceOp>> {
|
||||
self.advance_trivia_inline();
|
||||
self.skip_trivia_inline();
|
||||
let op = if self.starts_with("+=") {
|
||||
self.consume("+=")?;
|
||||
Some(InPlaceOp::Add)
|
||||
@ -579,7 +599,7 @@ impl<'a> PyParser<'a> {
|
||||
let arg = self.parse_expr(true)?;
|
||||
let end_idx = *self.index();
|
||||
|
||||
self.advance_trivia_inline();
|
||||
self.skip_trivia_inline();
|
||||
match (arg, self.starts_with("=")) {
|
||||
(Expr::Var { nam }, true) => {
|
||||
self.advance_one();
|
||||
@ -591,24 +611,15 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn name_or_wildcard(&mut self) -> ParseResult<Option<Name>> {
|
||||
self.labelled(
|
||||
|p| {
|
||||
if p.try_consume_exactly("_") {
|
||||
Ok(None)
|
||||
} else {
|
||||
let nam = p.parse_bend_name()?;
|
||||
Ok(Some(nam))
|
||||
}
|
||||
},
|
||||
"name or '_'",
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_match_case(&mut self, indent: &mut Indent) -> ParseResult<(MatchArm, Indent)> {
|
||||
self.parse_keyword("case")?;
|
||||
self.skip_trivia_inline();
|
||||
let pat = self.name_or_wildcard()?;
|
||||
let pat = if self.try_consume_exactly("_") {
|
||||
None
|
||||
} else {
|
||||
let nam = self.labelled(|p| p.parse_bend_name(), "name or '_'")?;
|
||||
Some(nam)
|
||||
};
|
||||
self.skip_trivia_inline();
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
@ -683,7 +694,7 @@ impl<'a> PyParser<'a> {
|
||||
return self.expected("number or '_'")?;
|
||||
};
|
||||
|
||||
self.advance_trivia_inline();
|
||||
self.skip_trivia_inline();
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -853,7 +864,7 @@ impl<'a> PyParser<'a> {
|
||||
// Chn pattern
|
||||
if self.starts_with("$") {
|
||||
self.advance_one();
|
||||
self.advance_trivia_inline();
|
||||
self.skip_trivia_inline();
|
||||
let nam = self.parse_bend_name()?;
|
||||
return Ok(AssignPattern::Chn(nam));
|
||||
}
|
||||
|
4
tests/golden_tests/parse_file/redefinition_fun_imp.bend
Normal file
4
tests/golden_tests/parse_file/redefinition_fun_imp.bend
Normal file
@ -0,0 +1,4 @@
|
||||
# We shouldn't allow a fun rule to be extended by an imp function
|
||||
(A) = @x x
|
||||
def A:
|
||||
return 0
|
5
tests/golden_tests/parse_file/redefinition_imp_fun.bend
Normal file
5
tests/golden_tests/parse_file/redefinition_imp_fun.bend
Normal file
@ -0,0 +1,5 @@
|
||||
# We shouldn't allow an imp function to have a fun rule
|
||||
def A:
|
||||
return 0
|
||||
|
||||
(A) = 1
|
@ -0,0 +1,4 @@
|
||||
# We shouldn't allow rules of other functions in the middle of a definition
|
||||
(A) = @x x
|
||||
(B) = @x x
|
||||
(A) = @x x
|
@ -0,0 +1,3 @@
|
||||
A = 0
|
||||
object B
|
||||
A = 1
|
@ -0,0 +1,3 @@
|
||||
A = 0
|
||||
data B = B
|
||||
A = 1
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/redefinition_fun_imp.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/redefinition_fun_imp.bend :
|
||||
Redefinition of function 'A'.
|
||||
[0m 3 | [4m[31mdef A:
|
||||
[0m 4 | [4m[31m return 0[0m
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/redefinition_imp_fun.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/redefinition_imp_fun.bend :
|
||||
Redefinition of function 'A'
|
||||
[0m 5 | [4m[31m(A) = 1[0m
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/redefinition_with_def_between.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/redefinition_with_def_between.bend :
|
||||
Redefinition of function 'A'
|
||||
[0m 4 | [4m[31m(A) = @x x[0m
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/redefinition_with_object_between.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/redefinition_with_object_between.bend :
|
||||
Redefinition of function 'A'
|
||||
[0m 3 | [4m[31mA = 1[0m
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/redefinition_with_type_between.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/redefinition_with_type_between.bend :
|
||||
Redefinition of function 'A'
|
||||
[0m 3 | [4m[31mA = 1[0m
|
Loading…
Reference in New Issue
Block a user