mirror of
https://github.com/uutils/awk.git
synced 2026-06-10 16:15:04 -07:00
parser: refactor lvalues & ast ownership; add getline pipes
This commit is contained in:
+120
-66
@@ -5,14 +5,14 @@
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use bumpalo::{Bump, collections::Vec};
|
||||
use bumpalo::{Bump, boxed::Box, collections::Vec};
|
||||
use either::Either;
|
||||
use hashbrown::{DefaultHashBuilder, HashMap};
|
||||
use lexer::{Slice, Span, Token};
|
||||
|
||||
use crate::{ParsingError, Result, lex::TokenExt};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Ast<'a> {
|
||||
pub loads: Vec<'a, Slice<'a>>,
|
||||
pub begin: Vec<'a, Body<'a>>,
|
||||
@@ -24,7 +24,7 @@ pub struct Ast<'a> {
|
||||
pub functions: HashMap<Identifier<'a>, Function<'a>, DefaultHashBuilder, &'a Bump>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Rule<'a> {
|
||||
pub pattern: Option<RulePattern<'a>>,
|
||||
pub actions: Option<Body<'a>>,
|
||||
@@ -40,7 +40,7 @@ pub enum Atom<'a> {
|
||||
Regex(Slice<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum RulePattern<'a> {
|
||||
Expression(Expr<'a>),
|
||||
Range(Expr<'a>, Expr<'a>),
|
||||
@@ -81,22 +81,21 @@ pub enum Variable<'a> {
|
||||
Environ,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Expr<'a> {
|
||||
Leaf(Atom<'a>),
|
||||
Node(&'a ExprNode<'a>),
|
||||
Node(Box<'a, ExprNode<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Body<'a>(pub Vec<'a, Statement<'a>>);
|
||||
pub type Pattern<'a> = Either<RulePattern<'a>, SpecialPattern>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum ExprNode<'a> {
|
||||
FunctionCall(Identifier<'a>, Vec<'a, Expr<'a>>),
|
||||
UnaryOperation(UnaryOperator, Expr<'a>),
|
||||
BinaryOperation(BinaryOperator, Expr<'a>, Expr<'a>),
|
||||
PlaceOperation(PlaceOperator, Variable<'a>, Expr<'a>),
|
||||
UnaryPlaceOperation(UnaryPlaceOperator, Place<'a>),
|
||||
BinaryPlaceOperation(BinaryPlaceOperator, Place<'a>, Expr<'a>),
|
||||
Ternary(Expr<'a>, Expr<'a>, Expr<'a>),
|
||||
Getline(Getline<'a>),
|
||||
}
|
||||
@@ -131,12 +130,32 @@ pub enum BinaryOperator {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum PlaceOperator {
|
||||
pub enum UnaryPlaceOperator {
|
||||
IncrementL,
|
||||
DecrementL,
|
||||
IncrementR,
|
||||
DecrementR,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BinaryPlaceOperator {
|
||||
Assignment,
|
||||
AddAssign,
|
||||
SubAssign,
|
||||
MulAssign,
|
||||
DivAssign,
|
||||
PowAssign,
|
||||
ModAssign,
|
||||
ArrayAccess,
|
||||
InArray,
|
||||
}
|
||||
|
||||
pub enum Place<'a> {
|
||||
Record(Expr<'a>),
|
||||
Variable(Variable<'a>),
|
||||
ArrayElement(Variable<'a>, Expr<'a>),
|
||||
}
|
||||
|
||||
/// GNU docs: https://www.gnu.org/software/gawk/manual/html_node/Redirection.html
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Redirection<'a> {
|
||||
@@ -152,19 +171,18 @@ pub enum WriteKind {
|
||||
Coprocess,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum Getline<'a> {
|
||||
// getline (var)?
|
||||
FromInput(Option<Variable<'a>>),
|
||||
FromInput(Option<Place<'a>>),
|
||||
// getline (var)? < (file)
|
||||
FromFile(Option<Variable<'a>>, Expr<'a>),
|
||||
FromFile(Option<Place<'a>>, Expr<'a>),
|
||||
// (expr) | getline (var)?
|
||||
PipeOut(Option<Variable<'a>>, Expr<'a>),
|
||||
PipeOut(Option<Place<'a>>, Expr<'a>),
|
||||
// (expr) |& getline (var)?
|
||||
CoprocessOut(Option<Variable<'a>>, Expr<'a>),
|
||||
CoprocessOut(Option<Place<'a>>, Expr<'a>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Statement<'a> {
|
||||
Expression(Expr<'a>),
|
||||
Command {
|
||||
@@ -194,7 +212,7 @@ pub enum Statement<'a> {
|
||||
body: Body<'a>,
|
||||
},
|
||||
ForEach {
|
||||
place: Variable<'a>,
|
||||
variable: Variable<'a>,
|
||||
array: Variable<'a>,
|
||||
body: Body<'a>,
|
||||
},
|
||||
@@ -211,13 +229,13 @@ pub enum Statement<'a> {
|
||||
Exit(Option<Expr<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct Function<'a> {
|
||||
pub args: Vec<'a, Identifier<'a>>,
|
||||
pub body: Body<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Command {
|
||||
Print,
|
||||
Printf,
|
||||
@@ -229,7 +247,7 @@ impl<'a> Expr<'a> {
|
||||
}
|
||||
|
||||
pub fn node(op: impl Into<ExprNode<'a>>, arena: &'a Bump) -> Self {
|
||||
Self::Node(arena.alloc(op.into()))
|
||||
Self::Node(Box::new_in(op.into(), arena))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,9 +263,15 @@ impl BinaryOperator {
|
||||
}
|
||||
}
|
||||
|
||||
impl PlaceOperator {
|
||||
pub fn expr<'a>(self, a: Variable<'a>, b: Expr<'a>) -> ExprNode<'a> {
|
||||
ExprNode::PlaceOperation(self, a, b)
|
||||
impl UnaryPlaceOperator {
|
||||
pub fn expr(self, a: Place<'_>) -> ExprNode<'_> {
|
||||
ExprNode::UnaryPlaceOperation(self, a)
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryPlaceOperator {
|
||||
pub fn expr<'a>(self, a: Place<'a>, b: Expr<'a>) -> ExprNode<'a> {
|
||||
ExprNode::BinaryPlaceOperation(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,6 +299,12 @@ impl<'a> From<Variable<'a>> for Atom<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Variable<'a>> for Place<'a> {
|
||||
fn from(value: Variable<'a>) -> Self {
|
||||
Self::Variable(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Atom<'_> {
|
||||
fn from(value: f64) -> Self {
|
||||
Self::Number(value)
|
||||
@@ -323,16 +353,34 @@ impl<'a> BinaryOperator {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PlaceOperator {
|
||||
impl UnaryPlaceOperator {
|
||||
pub fn parse_prefix(value: &Token<'_>, span: &Span) -> Result<Self> {
|
||||
match value {
|
||||
Token::Increment => Ok(Self::IncrementL),
|
||||
Token::Decrement => Ok(Self::DecrementL),
|
||||
_ => Err(ParsingError::OperatorExpectsVariable(span.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_suffix(value: &Token<'_>, span: &Span) -> Result<Self> {
|
||||
match value {
|
||||
Token::Increment => Ok(Self::IncrementR),
|
||||
Token::Decrement => Ok(Self::DecrementR),
|
||||
_ => Err(ParsingError::OperatorExpectsVariable(span.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BinaryPlaceOperator {
|
||||
pub fn parse(value: &Token<'a>, span: &Span) -> Result<Self> {
|
||||
match value {
|
||||
Token::Assignment
|
||||
| Token::PlusAssign
|
||||
| Token::MinusAssign
|
||||
| Token::StarAssign
|
||||
| Token::SlashAssign
|
||||
| Token::CaretAssign
|
||||
| Token::PercentAssign => Ok(Self::Assignment),
|
||||
Token::Assignment => Ok(Self::Assignment),
|
||||
Token::PlusAssign => Ok(Self::AddAssign),
|
||||
Token::MinusAssign => Ok(Self::SubAssign),
|
||||
Token::StarAssign => Ok(Self::MulAssign),
|
||||
Token::SlashAssign => Ok(Self::DivAssign),
|
||||
Token::CaretAssign => Ok(Self::PowAssign),
|
||||
Token::PercentAssign => Ok(Self::ModAssign),
|
||||
Token::OpenBracket => Ok(Self::ArrayAccess),
|
||||
Token::In => Ok(Self::InArray),
|
||||
_ => Err(ParsingError::UnexpectedToken(
|
||||
@@ -343,6 +391,34 @@ impl<'a> PlaceOperator {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Place<'a> {
|
||||
pub fn promote_from(expr: Expr<'a>, span: Span) -> Result<Self, (Expr<'a>, ParsingError)> {
|
||||
match expr {
|
||||
Expr::Leaf(Atom::Variable(var)) => Ok(Self::Variable(var)),
|
||||
Expr::Node(node)
|
||||
if matches!(
|
||||
&*node,
|
||||
&ExprNode::UnaryOperation(UnaryOperator::Record, _)
|
||||
| &ExprNode::BinaryPlaceOperation(
|
||||
BinaryPlaceOperator::ArrayAccess,
|
||||
Place::Variable(_),
|
||||
_
|
||||
)
|
||||
) =>
|
||||
{
|
||||
match Box::into_inner(node) {
|
||||
ExprNode::UnaryOperation(_, index) => Ok(Self::Record(index)),
|
||||
ExprNode::BinaryPlaceOperation(_, Place::Variable(var), index) => {
|
||||
Ok(Self::ArrayElement(var, index))
|
||||
}
|
||||
_ => unreachable!("Box is magic; handled awkwardly in the match guard."),
|
||||
}
|
||||
}
|
||||
_ => Err((expr, ParsingError::OperatorExpectsVariable(span))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteKind {
|
||||
pub fn parse(value: &Token) -> Option<Self> {
|
||||
match value {
|
||||
@@ -352,7 +428,7 @@ impl WriteKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr_getline<'a>(self, var: Option<Variable<'a>>, expr: Expr<'a>) -> Getline<'a> {
|
||||
pub fn expr_getline<'a>(self, var: Option<Place<'a>>, expr: Expr<'a>) -> Getline<'a> {
|
||||
match self {
|
||||
Self::Pipe => Getline::PipeOut(var, expr),
|
||||
Self::Coprocess => Getline::CoprocessOut(var, expr),
|
||||
@@ -360,35 +436,6 @@ impl WriteKind {
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryOperator {
|
||||
pub fn unfold(token: &Token) -> Option<Self> {
|
||||
match token {
|
||||
Token::PlusAssign => Some(Self::Add),
|
||||
Token::MinusAssign => Some(Self::Subtract),
|
||||
Token::StarAssign => Some(Self::Multiply),
|
||||
Token::SlashAssign => Some(Self::Divide),
|
||||
Token::PercentAssign => Some(Self::Modulo),
|
||||
Token::CaretAssign => Some(Self::Raise),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unfold_prefix(token: &Token<'_>) -> Option<(Self, u8)> {
|
||||
match token {
|
||||
Token::Increment => Some((Self::Add, binding_powers::BP_INC_DEC)),
|
||||
Token::Decrement => Some((Self::Subtract, binding_powers::BP_INC_DEC)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn unfold_suffix(token: &Token<'_>) -> Option<(Self, Self, u8)> {
|
||||
match token {
|
||||
Token::Increment => Some((Self::Add, Self::Subtract, binding_powers::BP_INC_DEC)),
|
||||
Token::Decrement => Some((Self::Subtract, Self::Add, binding_powers::BP_INC_DEC)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Ternary;
|
||||
|
||||
mod binding_powers {
|
||||
@@ -435,13 +482,20 @@ impl BindingPower for BinaryOperator {
|
||||
}
|
||||
}
|
||||
|
||||
impl BindingPower for PlaceOperator {
|
||||
impl BindingPower for UnaryPlaceOperator {
|
||||
type Bp = u8;
|
||||
fn binding_power(&self) -> Self::Bp {
|
||||
binding_powers::BP_INC_DEC
|
||||
}
|
||||
}
|
||||
|
||||
impl BindingPower for BinaryPlaceOperator {
|
||||
type Bp = (u8, u8);
|
||||
fn binding_power(&self) -> Self::Bp {
|
||||
match self {
|
||||
Self::Assignment => binding_powers::BP_ASSIGN,
|
||||
Self::ArrayAccess => (binding_powers::BP_GROUPING, 0),
|
||||
Self::InArray => binding_powers::BP_IN,
|
||||
_ => binding_powers::BP_ASSIGN,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,7 +514,6 @@ impl BindingPower for UnaryOperator {
|
||||
|
||||
impl BindingPower for Ternary {
|
||||
type Bp = (u8, u8);
|
||||
|
||||
fn binding_power(&self) -> Self::Bp {
|
||||
binding_powers::BP_TERNARY
|
||||
}
|
||||
@@ -476,7 +529,7 @@ impl Debug for Expr<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Leaf(atom) => write!(f, "{atom:?}"),
|
||||
Self::Node(expr) => match expr {
|
||||
Self::Node(expr) => match expr.as_ref() {
|
||||
ExprNode::FunctionCall(ident, args) => {
|
||||
write!(f, "({ident:?}")?;
|
||||
for arg in args {
|
||||
@@ -486,7 +539,8 @@ impl Debug for Expr<'_> {
|
||||
}
|
||||
ExprNode::UnaryOperation(op, a) => write!(f, "({op:?} {a:?})"),
|
||||
ExprNode::BinaryOperation(op, a, b) => write!(f, "({op:?} {a:?} {b:?})"),
|
||||
ExprNode::PlaceOperation(op, a, b) => write!(f, "({op:?} {a:?} {b:?})"),
|
||||
ExprNode::BinaryPlaceOperation(op, a, b) => write!(f, "({op:?} {a:?} {b:?})"),
|
||||
ExprNode::UnaryPlaceOperation(op, a) => write!(f, "({op:?} {a:?})"),
|
||||
ExprNode::Ternary(a, b, c) => write!(f, "(?: {a:?} {b:?} {c:?})"),
|
||||
ExprNode::Getline(getline) => match getline {
|
||||
Getline::FromInput(Some(a)) => write!(f, "(getline {a:?})"),
|
||||
|
||||
@@ -150,3 +150,9 @@ pub fn report_error<'a>(
|
||||
}
|
||||
(Box::new(report.finish()), Source::from(source))
|
||||
}
|
||||
|
||||
impl<T> From<(T, Self)> for ParsingError {
|
||||
fn from(value: (T, Self)) -> Self {
|
||||
value.1
|
||||
}
|
||||
}
|
||||
|
||||
+51
-14
@@ -3,8 +3,9 @@ use std::fmt::{Debug, Display, Formatter, Result, Write};
|
||||
use crate::{
|
||||
Ast, Function,
|
||||
ast::{
|
||||
Atom, BinaryOperator, BindingPower, Body, Command, Expr, ExprNode, Getline, PlaceOperator,
|
||||
Rule, RulePattern, Statement, Ternary, UnaryOperator,
|
||||
Atom, BinaryOperator, BinaryPlaceOperator, BindingPower, Body, Command, Expr, ExprNode,
|
||||
Getline, Place, Rule, RulePattern, Statement, Ternary, UnaryOperator, UnaryPlaceOperator,
|
||||
Variable,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -138,8 +139,12 @@ impl Display for Statement<'_> {
|
||||
write!(f, ") ")?;
|
||||
write_body(f, body, indent)
|
||||
}
|
||||
Self::ForEach { place, array, body } => {
|
||||
write!(f, "for ({place:?} in {array:?}) ")?;
|
||||
Self::ForEach {
|
||||
variable,
|
||||
array,
|
||||
body,
|
||||
} => {
|
||||
write!(f, "for ({variable} in {array}) ")?;
|
||||
write_body(f, body, indent)
|
||||
}
|
||||
Self::Switch {
|
||||
@@ -220,6 +225,23 @@ impl Display for Atom<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Variable<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
<Self as Debug>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Place<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
match self {
|
||||
Self::Variable(var) => <_ as Display>::fmt(var, f),
|
||||
Self::Record(Expr::Leaf(leaf)) => write!(f, "${leaf}"),
|
||||
Self::Record(Expr::Node(node)) => write!(f, "$({node})"),
|
||||
Self::ArrayElement(var, expr) => write!(f, "{var}[{expr}]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ExprNode<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
let (indent, parent_bp) = decode(f);
|
||||
@@ -249,21 +271,27 @@ impl Display for ExprNode<'_> {
|
||||
write!(f, "{a:left_w$}{op}{b:right_w$}")
|
||||
}
|
||||
}
|
||||
Self::PlaceOperation(op, place, idx) => {
|
||||
Self::UnaryPlaceOperation(op, place) => match op {
|
||||
UnaryPlaceOperator::IncrementL => write!(f, "++{place}"),
|
||||
UnaryPlaceOperator::DecrementL => write!(f, "--{place}"),
|
||||
UnaryPlaceOperator::DecrementR => write!(f, "{place}--"),
|
||||
UnaryPlaceOperator::IncrementR => write!(f, "{place}++"),
|
||||
},
|
||||
Self::BinaryPlaceOperation(op, place, idx) => {
|
||||
let (left_bp, right_bp) = op.binding_power();
|
||||
if op == &PlaceOperator::ArrayAccess {
|
||||
if op == &BinaryPlaceOperator::ArrayAccess {
|
||||
let idx_w = encode(indent, 0);
|
||||
if left_bp < parent_bp {
|
||||
write!(f, "({place:?}[{idx:idx_w$}])")
|
||||
write!(f, "({place}[{idx:idx_w$}])")
|
||||
} else {
|
||||
write!(f, "{place:?}[{idx:idx_w$}]")
|
||||
write!(f, "{place}[{idx:idx_w$}]")
|
||||
}
|
||||
} else {
|
||||
let right_w = encode(indent, right_bp);
|
||||
if left_bp < parent_bp {
|
||||
write!(f, "({place:?}{op}{idx:right_w$})")
|
||||
write!(f, "({place}{op}{idx:right_w$})")
|
||||
} else {
|
||||
write!(f, "{place:?}{op}{idx:right_w$}")
|
||||
write!(f, "{place}{op}{idx:right_w$}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,11 +311,14 @@ impl Display for ExprNode<'_> {
|
||||
}
|
||||
}
|
||||
Self::Getline(getline) => match getline {
|
||||
Getline::FromInput(Some(var)) => write!(f, "getline {var:?}"),
|
||||
Getline::FromInput(Some(var)) => write!(f, "getline {var}"),
|
||||
Getline::FromInput(None) => write!(f, "getline"),
|
||||
Getline::FromFile(Some(var), file) => write!(f, "getline {var:?} < {file}"),
|
||||
Getline::FromFile(Some(var), file) => write!(f, "getline {var} < {file}"),
|
||||
Getline::FromFile(None, file) => write!(f, "getline < {file}"),
|
||||
_ => todo!(),
|
||||
Getline::PipeOut(Some(place), e) => write!(f, "{e} | getline {place}"),
|
||||
Getline::PipeOut(None, e) => write!(f, "{e} | getline"),
|
||||
Getline::CoprocessOut(Some(place), e) => write!(f, "{e} |& getline {place}"),
|
||||
Getline::CoprocessOut(None, e) => write!(f, "{e} |& getline"),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -328,10 +359,16 @@ impl Display for BinaryOperator {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PlaceOperator {
|
||||
impl Display for BinaryPlaceOperator {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
match self {
|
||||
Self::Assignment => write!(f, " = "),
|
||||
Self::AddAssign => write!(f, " += "),
|
||||
Self::SubAssign => write!(f, " -= "),
|
||||
Self::MulAssign => write!(f, " *= "),
|
||||
Self::DivAssign => write!(f, " /= "),
|
||||
Self::PowAssign => write!(f, " ^= "),
|
||||
Self::ModAssign => write!(f, " %= "),
|
||||
Self::InArray => write!(f, " in "),
|
||||
Self::ArrayAccess => unreachable!("Array access needs special handling."),
|
||||
}
|
||||
|
||||
+3
-1
@@ -189,7 +189,8 @@ impl TokenExt for Token<'_> {
|
||||
)
|
||||
}
|
||||
fn is_atom(&self) -> bool {
|
||||
matches!(self, Token::Number(_) | Token::String(_) | Token::Regex(_)) || self.is_place()
|
||||
matches!(self, Token::Number(_) | Token::String(_) | Token::Regex(_))
|
||||
|| self.is_place() && self != &Token::Record
|
||||
}
|
||||
fn is_expr_start(&self) -> bool {
|
||||
self.is_atom()
|
||||
@@ -216,6 +217,7 @@ impl TokenExt for Token<'_> {
|
||||
| Token::RlengthVariable
|
||||
| Token::EnvironVariable
|
||||
| Token::Identifier(_)
|
||||
| Token::Record
|
||||
)
|
||||
}
|
||||
fn is_pattern_start(&self) -> bool {
|
||||
|
||||
+14
-11
@@ -15,7 +15,7 @@ mod tests;
|
||||
|
||||
use std::{fmt::Debug, mem::replace};
|
||||
|
||||
use bumpalo::{Bump, collections::Vec, vec};
|
||||
use bumpalo::{Bump, boxed::Box, collections::Vec, vec};
|
||||
use either::Either::{Left, Right};
|
||||
use hashbrown::HashMap;
|
||||
use lexer::{LexingError, Span, Token};
|
||||
@@ -24,8 +24,8 @@ pub use crate::ast::Ast;
|
||||
pub use crate::lex::Lexer;
|
||||
use crate::{
|
||||
ast::{
|
||||
Atom, Body, Command, Expr, ExprNode, Function, Identifier, Pattern, PlaceOperator, Rule,
|
||||
RulePattern, SpecialPattern, Statement, Variable,
|
||||
Atom, BinaryPlaceOperator, Body, Command, Expr, ExprNode, Function, Identifier, Pattern,
|
||||
Rule, RulePattern, SpecialPattern, Statement, Variable,
|
||||
},
|
||||
diagnostics::{ParsingError, report_error},
|
||||
lex::TokenExt,
|
||||
@@ -50,7 +50,7 @@ impl From<LexingError> for ParsingError {
|
||||
}
|
||||
|
||||
type AriadneErr<'a> = (
|
||||
Box<ariadne::Report<'a, (&'a str, Span)>>,
|
||||
std::boxed::Box<ariadne::Report<'a, (&'a str, Span)>>,
|
||||
ariadne::Source<&'a str>,
|
||||
);
|
||||
|
||||
@@ -242,7 +242,7 @@ impl<'a> Parser<'a> {
|
||||
let init = (!lex.consume(&Token::Semicolon))
|
||||
.then(|| self.parse_expression(lex))
|
||||
.transpose()?;
|
||||
if lex.consume(&Token::Semicolon) || init.is_none() {
|
||||
if init.is_none() || lex.consume(&Token::Semicolon) {
|
||||
let condition = self.parse_for_fragment::<false>(lex)?;
|
||||
let update = self.parse_for_fragment::<true>(lex)?;
|
||||
let body = self.parse_statement_body(lex)?;
|
||||
@@ -253,11 +253,14 @@ impl<'a> Parser<'a> {
|
||||
body,
|
||||
}
|
||||
} else {
|
||||
let Some(Expr::Node(ExprNode::PlaceOperation(
|
||||
PlaceOperator::InArray,
|
||||
place,
|
||||
let Some(Expr::Node(node)) = init else {
|
||||
return Err(ParsingError::InvalidForLoop(lex.span()));
|
||||
};
|
||||
let ExprNode::BinaryPlaceOperation(
|
||||
BinaryPlaceOperator::InArray,
|
||||
ast::Place::Variable(variable),
|
||||
Expr::Leaf(Atom::Variable(array)),
|
||||
))) = init
|
||||
) = Box::into_inner(node)
|
||||
else {
|
||||
return Err(ParsingError::InvalidForLoop(lex.span()));
|
||||
};
|
||||
@@ -267,8 +270,8 @@ impl<'a> Parser<'a> {
|
||||
)?;
|
||||
let body = self.parse_statement_body(lex)?;
|
||||
Statement::ForEach {
|
||||
place: *place,
|
||||
array: *array,
|
||||
variable,
|
||||
array,
|
||||
body,
|
||||
}
|
||||
}
|
||||
|
||||
+67
-72
@@ -3,8 +3,8 @@ use lexer::Token;
|
||||
use crate::{
|
||||
IdentifierExt, Lexer, Parser, Result,
|
||||
ast::{
|
||||
Atom, BinaryOperator, BindingPower, Expr, ExprNode, Getline, PlaceOperator, Ternary,
|
||||
UnaryOperator, Variable, WriteKind,
|
||||
BinaryOperator, BinaryPlaceOperator, BindingPower, Expr, ExprNode, Getline, Place, Ternary,
|
||||
UnaryOperator, UnaryPlaceOperator, Variable, WriteKind,
|
||||
},
|
||||
diagnostics::ParsingError,
|
||||
lex::TokenExt,
|
||||
@@ -39,35 +39,35 @@ impl<'a, 'b> Pratt<'a, 'b> {
|
||||
fn fold_rhs(&mut self, lex: &mut Lexer<'a>, mut lhs: Expr<'a>, min_bp: u8) -> Result<Expr<'a>> {
|
||||
while let Some((next, span)) = lex.peek_with_span() {
|
||||
let next = next?;
|
||||
lhs = if let Ok(op) = BinaryOperator::parse(next, &span)
|
||||
lhs = if let Ok(op) = UnaryPlaceOperator::parse_suffix(next, &span) {
|
||||
if op.binding_power() < min_bp {
|
||||
break;
|
||||
}
|
||||
lex.next();
|
||||
let place = Place::promote_from(lhs.take(), lex.span())?;
|
||||
Expr::node(op.expr(place), self.parser.arena)
|
||||
} else if let Ok(op) = BinaryPlaceOperator::parse(next, &span) {
|
||||
if op.binding_power().0 < min_bp {
|
||||
break;
|
||||
}
|
||||
let place = Place::promote_from(lhs.take(), lex.span())?;
|
||||
self.parse_place_op(lex, op, place)?
|
||||
} else if let Ok(op) = BinaryOperator::parse(next, &span)
|
||||
&& !matches!(next, Token::Increment | Token::Decrement)
|
||||
{
|
||||
if op.binding_power().0 < min_bp {
|
||||
break;
|
||||
}
|
||||
self.parse_infix_op(lex, op, lhs)?
|
||||
} else if let Ok(op) = PlaceOperator::parse(next, &span) {
|
||||
let Expr::Leaf(Atom::Variable(var)) = lhs.take() else {
|
||||
return Err(ParsingError::OperatorExpectsVariable(lex.span()));
|
||||
};
|
||||
if op.binding_power().0 < min_bp {
|
||||
break;
|
||||
}
|
||||
self.parse_place_op(lex, op, var)?
|
||||
} else if next == &Token::QuestionMark {
|
||||
if Ternary.binding_power().0 < min_bp {
|
||||
break;
|
||||
}
|
||||
self.parse_ternary(lex, lhs)?
|
||||
} else if let Some((op, reciprocal, bp)) = BinaryOperator::unfold_suffix(next) {
|
||||
let Expr::Leaf(Atom::Variable(rhs)) = lhs else {
|
||||
return Err(ParsingError::OperatorExpectsVariable(lex.span()));
|
||||
};
|
||||
if bp < min_bp {
|
||||
} else if let Some(op) = WriteKind::parse(next) {
|
||||
if BinaryOperator::Concat.binding_power().0 < min_bp {
|
||||
break;
|
||||
}
|
||||
self.unfolded_suffix_op(lex, op, reciprocal, rhs)
|
||||
} else if let Some(op) = WriteKind::parse(next) {
|
||||
self.parse_getline_pipe(lex, op, lhs)?
|
||||
} else {
|
||||
break;
|
||||
@@ -87,15 +87,10 @@ impl<'a, 'b> Pratt<'a, 'b> {
|
||||
|
||||
fn parse_prefix(&mut self, lex: &mut Lexer<'a>) -> Result<Expr<'a>> {
|
||||
let next = lex.expect_next()?;
|
||||
if let Some((op, bp)) = BinaryOperator::unfold_prefix(&next) {
|
||||
let Expr::Leaf(Atom::Variable(rhs)) = self.parse_expression(lex, bp)? else {
|
||||
return Err(ParsingError::OperatorExpectsVariable(lex.span()));
|
||||
};
|
||||
if let Ok(op) = UnaryPlaceOperator::parse_prefix(&next, &lex.span()) {
|
||||
let rhs = self.parse_expression(lex, op.binding_power())?;
|
||||
Ok(Expr::node(
|
||||
PlaceOperator::Assignment.expr(
|
||||
rhs,
|
||||
Expr::node(op.expr(Expr::leaf(rhs), Expr::leaf(1.)), self.parser.arena),
|
||||
),
|
||||
op.expr(Place::promote_from(rhs, lex.span())?),
|
||||
self.parser.arena,
|
||||
))
|
||||
} else if let Ok(op) = UnaryOperator::parse(&next, &lex.peeked_span()?) {
|
||||
@@ -107,22 +102,32 @@ impl<'a, 'b> Pratt<'a, 'b> {
|
||||
}
|
||||
|
||||
fn parse_prefix_getline(&mut self, lex: &mut Lexer<'a>) -> Result<Expr<'a>> {
|
||||
// Consumes with maximum precedence the following ident and/or
|
||||
// Consumes with maximum precedence the following place and/or
|
||||
// redirection reading from file.
|
||||
// TODO: move to specialized rhs loop to disambiguate call/variable.
|
||||
let var = if lex.peek_with(Token::is_place) {
|
||||
let next = lex.expect_next()?;
|
||||
self.parser.get_place(lex, next)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if lex.consume(&Token::LesserThan) {
|
||||
Ok(Expr::node(
|
||||
Getline::FromFile(var, self.parse_expression(lex, 0)?),
|
||||
self.parser.arena,
|
||||
let place = if lex.peek_with(Token::is_place) {
|
||||
Some(Place::promote_from(
|
||||
self.parse_expression(lex, BinaryOperator::Concat.binding_power().1)?,
|
||||
lex.span(),
|
||||
))
|
||||
} else {
|
||||
Ok(Expr::node(Getline::FromInput(var), self.parser.arena))
|
||||
None
|
||||
}
|
||||
.transpose();
|
||||
|
||||
let getline = |gl| Expr::node(ExprNode::Getline(gl), self.parser.arena);
|
||||
match place {
|
||||
Err((expr, _)) => Ok(Expr::node(
|
||||
BinaryOperator::Concat.expr(getline(Getline::FromInput(None)), expr),
|
||||
self.parser.arena,
|
||||
)),
|
||||
Ok(place) => {
|
||||
if lex.consume(&Token::LesserThan) {
|
||||
let file = self.parse_expression(lex, BinaryOperator::Lt.binding_power().1)?;
|
||||
Ok(getline(Getline::FromFile(place, file)))
|
||||
} else {
|
||||
Ok(getline(Getline::FromInput(place)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,15 +159,15 @@ impl<'a, 'b> Pratt<'a, 'b> {
|
||||
fn parse_place_op(
|
||||
&mut self,
|
||||
lex: &mut Lexer<'a>,
|
||||
op: PlaceOperator,
|
||||
var: Variable<'a>,
|
||||
op: BinaryPlaceOperator,
|
||||
place: Place<'a>,
|
||||
) -> Result<Expr<'a>> {
|
||||
let token_op = lex.expect_next()?;
|
||||
|
||||
lex.next();
|
||||
let mut rhs = self.parse_expression(lex, op.binding_power().1)?;
|
||||
if let Some(op) = BinaryOperator::unfold(&token_op) {
|
||||
rhs = Expr::node(op.expr(Expr::leaf(var), rhs), self.parser.arena);
|
||||
} else if op == PlaceOperator::ArrayAccess {
|
||||
if op == BinaryPlaceOperator::ArrayAccess {
|
||||
if !matches!(place, Place::Variable(_)) {
|
||||
return Err(ParsingError::OperatorExpectsVariable(lex.span()));
|
||||
}
|
||||
while lex.consume(&Token::Comma) {
|
||||
rhs = Expr::node(
|
||||
BinaryOperator::Concat.expr(
|
||||
@@ -178,7 +183,7 @@ impl<'a, 'b> Pratt<'a, 'b> {
|
||||
}
|
||||
lex.expect(&Token::ClosedBracket, ParsingError::UnclosedArrayAccess)?;
|
||||
}
|
||||
Ok(Expr::node(op.expr(var, rhs), self.parser.arena))
|
||||
Ok(Expr::node(op.expr(place, rhs), self.parser.arena))
|
||||
}
|
||||
|
||||
fn parse_ternary(&mut self, lex: &mut Lexer<'a>, lhs: Expr<'a>) -> Result<Expr<'a>> {
|
||||
@@ -193,42 +198,32 @@ impl<'a, 'b> Pratt<'a, 'b> {
|
||||
))
|
||||
}
|
||||
|
||||
fn unfolded_suffix_op(
|
||||
&mut self,
|
||||
lex: &mut Lexer<'a>,
|
||||
op: BinaryOperator,
|
||||
reciprocal: BinaryOperator,
|
||||
rhs: Variable<'a>,
|
||||
) -> Expr<'a> {
|
||||
lex.next();
|
||||
Expr::node(
|
||||
reciprocal.expr(
|
||||
Expr::node(
|
||||
PlaceOperator::Assignment.expr(
|
||||
rhs,
|
||||
Expr::node(op.expr(Expr::leaf(rhs), Expr::leaf(1.)), self.parser.arena),
|
||||
),
|
||||
self.parser.arena,
|
||||
),
|
||||
Expr::leaf(1.),
|
||||
),
|
||||
self.parser.arena,
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_getline_pipe(
|
||||
&mut self,
|
||||
lex: &mut Lexer<'a>,
|
||||
op: WriteKind,
|
||||
lhs: Expr<'a>,
|
||||
) -> Result<Expr<'a>> {
|
||||
lex.next();
|
||||
lex.expect(&Token::Getline, |span| {
|
||||
ParsingError::UnexpectedToken(
|
||||
span,
|
||||
"operand must precede `getline` in an expression.".into(),
|
||||
)
|
||||
})?;
|
||||
// TODO: move to specialized rhs loop to disambiguate call/variable.
|
||||
Ok(Expr::node(op.expr_getline(None, lhs), self.parser.arena))
|
||||
|
||||
let pipe = |place| Expr::node(op.expr_getline(place, lhs), self.parser.arena);
|
||||
if lex.peek_with(Token::is_place) {
|
||||
let expr = self.parse_expression(lex, BinaryOperator::Concat.binding_power().1)?;
|
||||
match Place::promote_from(expr, lex.span()) {
|
||||
Ok(place) => Ok(pipe(Some(place))),
|
||||
Err((expr, _)) => Ok(Expr::node(
|
||||
BinaryOperator::Concat.expr(pipe(None), expr),
|
||||
self.parser.arena,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(pipe(None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-4
@@ -5,7 +5,7 @@
|
||||
|
||||
use std::fmt::{Debug, Display, Formatter, Result};
|
||||
|
||||
use crate::ast::{Atom, Body, Expr, Identifier, Statement, Variable};
|
||||
use crate::ast::{Atom, Body, Expr, Identifier, Place, Statement, Variable};
|
||||
|
||||
const PRETTY_PRINT_INDENT: usize = 2;
|
||||
|
||||
@@ -111,11 +111,15 @@ impl Debug for Statement<'_> {
|
||||
write!(f, "(for {init:?} {condition:?} {update:?} {body:?})")
|
||||
}
|
||||
}
|
||||
Self::ForEach { place, array, body } => {
|
||||
Self::ForEach {
|
||||
variable,
|
||||
array,
|
||||
body,
|
||||
} => {
|
||||
if alt {
|
||||
write!(f, "(for-each {place:?} {array:?}\n{pad}{body:#ni$?})")
|
||||
write!(f, "(for-each {variable:?} {array:?}\n{pad}{body:#ni$?})")
|
||||
} else {
|
||||
write!(f, "(for-each {place:?} {array:?} {body:?})")
|
||||
write!(f, "(for-each {variable:?} {array:?} {body:?})")
|
||||
}
|
||||
}
|
||||
Self::Switch {
|
||||
@@ -237,6 +241,16 @@ impl Debug for Atom<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Place<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
match self {
|
||||
Self::Record(expr) => write!(f, "($ {expr:?})"),
|
||||
Self::Variable(var) => <_ as Debug>::fmt(var, f),
|
||||
Self::ArrayElement(var, index) => write!(f, "(index {var:?} {index:?})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Variable<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
match self {
|
||||
|
||||
Reference in New Issue
Block a user