mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
cleanup
This commit is contained in:
parent
6122b0650b
commit
ad40609d44
1 changed files with 0 additions and 282 deletions
|
@ -10,26 +10,6 @@ use roc_region::all::{Located, Region};
|
||||||
// BinOp precedence logic adapted from Gluon by Markus Westerlind, MIT licensed
|
// BinOp precedence logic adapted from Gluon by Markus Westerlind, MIT licensed
|
||||||
// https://github.com/gluon-lang/gluon
|
// https://github.com/gluon-lang/gluon
|
||||||
// Thank you, Markus!
|
// Thank you, Markus!
|
||||||
fn new_op_expr<'a>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
left: Located<Expr<'a>>,
|
|
||||||
op: Located<BinOp>,
|
|
||||||
right: Located<Expr<'a>>,
|
|
||||||
) -> Located<Expr<'a>> {
|
|
||||||
let new_region = Region {
|
|
||||||
start_line: left.region.start_line,
|
|
||||||
start_col: left.region.start_col,
|
|
||||||
|
|
||||||
end_line: right.region.end_line,
|
|
||||||
end_col: right.region.end_col,
|
|
||||||
};
|
|
||||||
let new_expr = Expr::BinOp(arena.alloc((left, op, right)));
|
|
||||||
|
|
||||||
Located {
|
|
||||||
value: new_expr,
|
|
||||||
region: new_region,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_op_call_expr<'a>(
|
fn new_op_call_expr<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -724,265 +704,3 @@ fn binop_step<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugar_bin_op<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'_>>) -> &'a Located<Expr<'a>> {
|
|
||||||
use roc_module::operator::Associativity::*;
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
let mut infixes = Infixes::new(loc_expr);
|
|
||||||
let mut arg_stack: Vec<&'a Located<Expr>> = Vec::new_in(arena);
|
|
||||||
let mut op_stack: Vec<Located<BinOp>> = Vec::new_in(arena);
|
|
||||||
|
|
||||||
while let Some(token) = infixes.next() {
|
|
||||||
match token {
|
|
||||||
InfixToken::Arg(next_expr) => arg_stack.push(next_expr),
|
|
||||||
InfixToken::Op(next_op) => {
|
|
||||||
match op_stack.pop() {
|
|
||||||
Some(stack_op) => {
|
|
||||||
match next_op.value.cmp(&stack_op.value) {
|
|
||||||
Ordering::Less => {
|
|
||||||
// Inline
|
|
||||||
let right = arg_stack.pop().unwrap();
|
|
||||||
let left = arg_stack.pop().unwrap();
|
|
||||||
|
|
||||||
infixes.next_op = Some(next_op);
|
|
||||||
arg_stack.push(arena.alloc(new_op_expr(
|
|
||||||
arena,
|
|
||||||
Located {
|
|
||||||
value: Nested(&left.value),
|
|
||||||
region: left.region,
|
|
||||||
},
|
|
||||||
stack_op,
|
|
||||||
Located {
|
|
||||||
value: Nested(&right.value),
|
|
||||||
region: right.region,
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ordering::Greater => {
|
|
||||||
// Swap
|
|
||||||
op_stack.push(stack_op);
|
|
||||||
op_stack.push(next_op);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ordering::Equal => {
|
|
||||||
match (
|
|
||||||
next_op.value.associativity(),
|
|
||||||
stack_op.value.associativity(),
|
|
||||||
) {
|
|
||||||
(LeftAssociative, LeftAssociative) => {
|
|
||||||
// Inline
|
|
||||||
let right = arg_stack.pop().unwrap();
|
|
||||||
let left = arg_stack.pop().unwrap();
|
|
||||||
|
|
||||||
infixes.next_op = Some(next_op);
|
|
||||||
arg_stack.push(arena.alloc(new_op_expr(
|
|
||||||
arena,
|
|
||||||
Located {
|
|
||||||
value: Nested(&left.value),
|
|
||||||
region: left.region,
|
|
||||||
},
|
|
||||||
stack_op,
|
|
||||||
Located {
|
|
||||||
value: Nested(&right.value),
|
|
||||||
region: right.region,
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
(RightAssociative, RightAssociative) => {
|
|
||||||
// Swap
|
|
||||||
op_stack.push(stack_op);
|
|
||||||
op_stack.push(next_op);
|
|
||||||
}
|
|
||||||
|
|
||||||
(NonAssociative, NonAssociative) => {
|
|
||||||
// Both operators were non-associative, e.g. (True == False == False).
|
|
||||||
// We should tell the author to disambiguate by grouping them with parens.
|
|
||||||
let bad_op = next_op;
|
|
||||||
let right = arg_stack.pop().unwrap();
|
|
||||||
let left = arg_stack.pop().unwrap();
|
|
||||||
let broken_expr = new_op_expr(
|
|
||||||
arena,
|
|
||||||
Located {
|
|
||||||
value: Nested(&left.value),
|
|
||||||
region: left.region,
|
|
||||||
},
|
|
||||||
next_op,
|
|
||||||
Located {
|
|
||||||
value: Nested(&right.value),
|
|
||||||
region: right.region,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let region = broken_expr.region;
|
|
||||||
let data = roc_parse::ast::PrecedenceConflict {
|
|
||||||
whole_region: loc_expr.region,
|
|
||||||
binop1_position: stack_op.region.start(),
|
|
||||||
binop1: stack_op.value,
|
|
||||||
binop2_position: bad_op.region.start(),
|
|
||||||
binop2: bad_op.value,
|
|
||||||
expr: arena.alloc(broken_expr),
|
|
||||||
};
|
|
||||||
let value = Expr::PrecedenceConflict(arena.alloc(data));
|
|
||||||
|
|
||||||
return arena.alloc(Located { region, value });
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
// The operators had the same precedence but different associativity.
|
|
||||||
//
|
|
||||||
// In many languages, this case can happen due to (for example) <| and |> having the same
|
|
||||||
// precedence but different associativity. Languages which support custom operators with
|
|
||||||
// (e.g. Haskell) can potentially have arbitrarily many of these cases.
|
|
||||||
//
|
|
||||||
// By design, Roc neither allows custom operators nor has any built-in operators with
|
|
||||||
// the same precedence and different associativity, so this should never happen!
|
|
||||||
panic!("BinOps had the same associativity, but different precedence. This should never happen!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => op_stack.push(next_op),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for loc_op in op_stack.into_iter().rev() {
|
|
||||||
let right = desugar_expr(arena, arg_stack.pop().unwrap());
|
|
||||||
let left = desugar_expr(arena, arg_stack.pop().unwrap());
|
|
||||||
|
|
||||||
let region = Region::span_across(&left.region, &right.region);
|
|
||||||
let value = match loc_op.value {
|
|
||||||
Pizza => {
|
|
||||||
// Rewrite the Pizza operator into an Apply
|
|
||||||
|
|
||||||
match &right.value {
|
|
||||||
Apply(function, arguments, _called_via) => {
|
|
||||||
let mut args = Vec::with_capacity_in(1 + arguments.len(), arena);
|
|
||||||
|
|
||||||
args.push(left);
|
|
||||||
|
|
||||||
for arg in arguments.iter() {
|
|
||||||
args.push(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let args = args.into_bump_slice();
|
|
||||||
|
|
||||||
Apply(function, args, CalledVia::BinOp(Pizza))
|
|
||||||
}
|
|
||||||
expr => {
|
|
||||||
// e.g. `1 |> (if b then (\a -> a) else (\c -> c))`
|
|
||||||
let mut args = Vec::with_capacity_in(1, arena);
|
|
||||||
|
|
||||||
args.push(left);
|
|
||||||
|
|
||||||
let function = arena.alloc(Located {
|
|
||||||
value: Nested(expr),
|
|
||||||
region: right.region,
|
|
||||||
});
|
|
||||||
|
|
||||||
let args = args.into_bump_slice();
|
|
||||||
|
|
||||||
Apply(function, args, CalledVia::BinOp(Pizza))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binop => {
|
|
||||||
// This is a normal binary operator like (+), so desugar it
|
|
||||||
// into the appropriate function call.
|
|
||||||
let (module_name, ident) = binop_to_function(binop);
|
|
||||||
let mut args = Vec::with_capacity_in(2, arena);
|
|
||||||
|
|
||||||
args.push(left);
|
|
||||||
args.push(right);
|
|
||||||
|
|
||||||
let loc_expr = arena.alloc(Located {
|
|
||||||
value: Expr::Var { module_name, ident },
|
|
||||||
region: loc_op.region,
|
|
||||||
});
|
|
||||||
|
|
||||||
let args = args.into_bump_slice();
|
|
||||||
|
|
||||||
Apply(loc_expr, args, CalledVia::BinOp(binop))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
arg_stack.push(arena.alloc(Located { region, value }));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(arg_stack.len(), 1);
|
|
||||||
|
|
||||||
arg_stack.pop().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
enum InfixToken<'a> {
|
|
||||||
Arg(&'a Located<Expr<'a>>),
|
|
||||||
Op(Located<BinOp>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator that takes an expression that has had its operators grouped
|
|
||||||
/// with _right associativity_, and yeilds a sequence of `InfixToken`s. This
|
|
||||||
/// is useful for reparsing the operators with their correct associativies
|
|
||||||
/// and precedences.
|
|
||||||
///
|
|
||||||
/// For example, the expression:
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// (1 + (2 ^ (4 * (6 - 8))))
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Will result in the following iterations:
|
|
||||||
///
|
|
||||||
/// ```text
|
|
||||||
/// Arg: 1
|
|
||||||
/// Op: +
|
|
||||||
/// Arg: 2
|
|
||||||
/// Op: ^
|
|
||||||
/// Arg: 4
|
|
||||||
/// Op: *
|
|
||||||
/// Arg: 6
|
|
||||||
/// Op: -
|
|
||||||
/// Arg: 8
|
|
||||||
/// ```
|
|
||||||
struct Infixes<'a> {
|
|
||||||
/// The next part of the expression that we need to flatten
|
|
||||||
remaining_expr: Option<&'a Located<Expr<'a>>>,
|
|
||||||
/// Cached operator from a previous iteration
|
|
||||||
next_op: Option<Located<BinOp>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Infixes<'a> {
|
|
||||||
fn new(expr: &'a Located<Expr<'a>>) -> Infixes<'a> {
|
|
||||||
Infixes {
|
|
||||||
remaining_expr: Some(expr),
|
|
||||||
next_op: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for Infixes<'a> {
|
|
||||||
type Item = InfixToken<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<InfixToken<'a>> {
|
|
||||||
match self.next_op.take() {
|
|
||||||
Some(op) => Some(InfixToken::Op(op)),
|
|
||||||
None => self
|
|
||||||
.remaining_expr
|
|
||||||
.take()
|
|
||||||
.map(|loc_expr| match loc_expr.value {
|
|
||||||
Expr::BinOp((left, loc_op, right))
|
|
||||||
| Expr::Nested(Expr::BinOp((left, loc_op, right))) => {
|
|
||||||
self.remaining_expr = Some(right);
|
|
||||||
self.next_op = Some(*loc_op);
|
|
||||||
|
|
||||||
InfixToken::Arg(left)
|
|
||||||
}
|
|
||||||
_ => InfixToken::Arg(loc_expr),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue