Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add postfix operator #394

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/els/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use erg_common::traits::{Locational, Runnable};
use erg_compiler::artifact::BuildRunnable;
use erg_compiler::erg_parser::ast::{
Accessor, Args, BinOp, Block, Call, ClassAttr, Def, DefKind, Expr, Methods, Params,
PreDeclTypeSpec, SimpleTypeSpec, TypeSpec, UnaryOp, AST,
PreDeclTypeSpec, PrefixOp, SimpleTypeSpec, TypeSpec, AST,
};
use erg_compiler::erg_parser::token::TokenKind;
use erg_compiler::ASTBuilder;
Expand Down Expand Up @@ -156,7 +156,7 @@ impl ASTSemanticState {
Expr::Accessor(acc) => self.gen_from_acc(acc),
Expr::Call(call) => self.gen_from_call(call),
Expr::BinOp(bin) => self.gen_from_bin(bin),
Expr::UnaryOp(unary) => self.gen_from_unary(unary),
Expr::PrefixOp(unary) => self.gen_from_unary(unary),
_ => vec![],
}
}
Expand Down Expand Up @@ -249,7 +249,7 @@ impl ASTSemanticState {
tokens
}

fn gen_from_unary(&mut self, unary: UnaryOp) -> Vec<SemanticToken> {
fn gen_from_unary(&mut self, unary: PrefixOp) -> Vec<SemanticToken> {
let mut tokens = vec![self.gen_token(unary.op.loc(), SemanticTokenType::OPERATOR)];
let mut args = unary.args.into_iter();
tokens.extend(self.gen_from_expr(*args.next().unwrap()));
Expand Down
6 changes: 3 additions & 3 deletions crates/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl Context {
self.eval_bin(op, lhs, rhs)
}

fn eval_const_unary(&self, unary: &UnaryOp) -> EvalResult<ValueObj> {
fn eval_const_unary(&self, unary: &PrefixOp) -> EvalResult<ValueObj> {
let val = self.eval_const_expr(&unary.args[0])?;
let op = self.try_get_op_kind_from_token(&unary.op)?;
self.eval_unary_val(op, val)
Expand Down Expand Up @@ -526,7 +526,7 @@ impl Context {
Expr::Literal(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
Expr::PrefixOp(unary) => self.eval_const_unary(unary),
Expr::Call(call) => self.eval_const_call(call),
Expr::Array(arr) => self.eval_const_array(arr),
Expr::Set(set) => self.eval_const_set(set),
Expand Down Expand Up @@ -556,7 +556,7 @@ impl Context {
Expr::Literal(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
Expr::PrefixOp(unary) => self.eval_const_unary(unary),
Expr::Call(call) => self.eval_const_call(call),
Expr::Array(arr) => self.eval_const_array(arr),
Expr::Set(set) => self.eval_const_set(set),
Expand Down
4 changes: 2 additions & 2 deletions crates/erg_compiler/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ impl ASTLowerer {
Ok(hir::BinOp::new(bin.op, lhs, rhs, t))
}

fn lower_unary(&mut self, unary: ast::UnaryOp) -> LowerResult<hir::UnaryOp> {
fn lower_unary(&mut self, unary: ast::PrefixOp) -> LowerResult<hir::UnaryOp> {
log!(info "entered {}({unary})", fn_name!());
let mut args = unary.args.into_iter();
let arg = hir::PosArg::new(self.lower_expr(*args.next().unwrap())?);
Expand Down Expand Up @@ -2021,7 +2021,7 @@ impl ASTLowerer {
ast::Expr::Dict(dict) => Ok(hir::Expr::Dict(self.lower_dict(dict)?)),
ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.lower_acc(acc)?)),
ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)),
ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
ast::Expr::PrefixOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)),
ast::Expr::DataPack(pack) => Ok(hir::Expr::Call(self.lower_pack(pack)?)),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
Expand Down
66 changes: 53 additions & 13 deletions crates/erg_parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,27 +1037,27 @@ impl BinOp {
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct UnaryOp {
pub struct PrefixOp {
pub op: Token,
pub args: [Box<Expr>; 1],
}

impl NestedDisplay for UnaryOp {
impl NestedDisplay for PrefixOp {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "`{}`:", self.op.content)?;
self.args[0].fmt_nest(f, level + 1)
}
}

impl_display_from_nested!(UnaryOp);
impl_display_from_nested!(PrefixOp);

impl Locational for UnaryOp {
impl Locational for PrefixOp {
fn loc(&self) -> Location {
Location::concat(&self.op, self.args[0].as_ref())
}
}

impl UnaryOp {
impl PrefixOp {
pub fn new(op: Token, expr: Expr) -> Self {
Self {
op,
Expand All @@ -1071,6 +1071,41 @@ impl UnaryOp {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PostfixOp {
pub op: Token,
pub args: [Box<Expr>; 1],
}

impl NestedDisplay for PostfixOp {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
self.args[0].fmt_nest(f, level + 1)?;
writeln!(f, "{}", self.op.content)
}
}

impl_display_from_nested!(PostfixOp);

impl Locational for PostfixOp {
fn loc(&self) -> Location {
Location::concat(self.args[0].as_ref(), &self.op)
}
}

impl PostfixOp {
pub fn new(expr: Expr, op: Token) -> Self {
Self {
op,
args: [Box::new(expr)],
}
}

pub fn deconstruct(self) -> (Expr, Token) {
let mut exprs = self.args.into_iter();
(*exprs.next().unwrap(), self.op)
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Call {
pub obj: Box<Expr>,
Expand Down Expand Up @@ -1562,8 +1597,8 @@ impl ConstUnaryOp {
}
}

pub fn downcast(self) -> UnaryOp {
UnaryOp::new(self.op, self.expr.downcast())
pub fn downcast(self) -> PrefixOp {
PrefixOp::new(self.op, self.expr.downcast())
}
}

Expand Down Expand Up @@ -1636,7 +1671,7 @@ impl ConstExpr {
// Self::Set(set) => Expr::Set(set.downcast()),
// Self::Dict(dict) => Expr::Dict(dict.downcast()),
Self::BinOp(binop) => Expr::BinOp(binop.downcast()),
Self::UnaryOp(unop) => Expr::UnaryOp(unop.downcast()),
Self::UnaryOp(unop) => Expr::PrefixOp(unop.downcast()),
_ => todo!(),
}
}
Expand Down Expand Up @@ -3717,7 +3752,8 @@ pub enum Expr {
Set(Set),
Record(Record),
BinOp(BinOp),
UnaryOp(UnaryOp),
PrefixOp(PrefixOp),
PostfixOp(PostfixOp),
Call(Call),
DataPack(DataPack),
Lambda(Lambda),
Expand All @@ -3731,10 +3767,10 @@ pub enum Expr {
Dummy(Dummy),
}

impl_nested_display_for_chunk_enum!(Expr; Literal, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAscription, Def, Methods, ClassDef, PatchDef, ReDef, Dummy);
impl_from_trait_for_enum!(Expr; Literal, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAscription, Def, Methods, ClassDef, PatchDef, ReDef, Dummy);
impl_nested_display_for_chunk_enum!(Expr; Literal, Accessor, Array, Tuple, Dict, Set, Record, BinOp, PrefixOp, PostfixOp, Call, DataPack, Lambda, TypeAscription, Def, Methods, ClassDef, PatchDef, ReDef, Dummy);
impl_from_trait_for_enum!(Expr; Literal, Accessor, Array, Tuple, Dict, Set, Record, BinOp, PrefixOp, PostfixOp, Call, DataPack, Lambda, TypeAscription, Def, Methods, ClassDef, PatchDef, ReDef, Dummy);
impl_display_from_nested!(Expr);
impl_locational_for_enum!(Expr; Literal, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAscription, Def, Methods, ClassDef, PatchDef, ReDef, Dummy);
impl_locational_for_enum!(Expr; Literal, Accessor, Array, Tuple, Dict, Set, Record, BinOp, PrefixOp, PostfixOp, Call, DataPack, Lambda, TypeAscription, Def, Methods, ClassDef, PatchDef, ReDef, Dummy);

impl Expr {
pub fn is_match_call(&self) -> bool {
Expand All @@ -3759,7 +3795,7 @@ impl Expr {
pub fn need_to_be_closed(&self) -> bool {
matches!(
self,
Expr::BinOp(_) | Expr::UnaryOp(_) | Expr::Lambda(_) | Expr::TypeAscription(_)
Expr::BinOp(_) | Expr::PrefixOp(_) | Expr::Lambda(_) | Expr::TypeAscription(_)
)
}

Expand Down Expand Up @@ -3826,6 +3862,10 @@ impl Expr {
Self::Call(self.call(args))
}

pub fn postfix_expr(self, op: Token) -> Self {
Self::PostfixOp(PostfixOp::new(self, op))
}

pub fn type_asc(self, op: Token, t_spec: TypeSpec) -> TypeAscription {
TypeAscription::new(self, op, t_spec)
}
Expand Down
14 changes: 7 additions & 7 deletions crates/erg_parser/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,9 @@ impl Parser {
debug_exit_info!(self);
Ok(param)
}
Expr::UnaryOp(unary) => match unary.op.kind {
Expr::PrefixOp(prefix) => match prefix.op.kind {
TokenKind::RefOp => {
let var = unary.args.into_iter().next().unwrap();
let var = prefix.args.into_iter().next().unwrap();
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::Ref(var.name);
Expand All @@ -457,7 +457,7 @@ impl Parser {
Ok(param)
}
TokenKind::RefMutOp => {
let var = unary.args.into_iter().next().unwrap();
let var = prefix.args.into_iter().next().unwrap();
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::RefMut(var.name);
Expand All @@ -467,7 +467,7 @@ impl Parser {
}
// TODO: Spread
_other => {
let err = ParseError::simple_syntax_error(line!() as usize, unary.loc());
let err = ParseError::simple_syntax_error(line!() as usize, prefix.loc());
self.errs.push(err);
debug_exit_info!(self);
Err(())
Expand Down Expand Up @@ -652,9 +652,9 @@ impl Parser {
debug_exit_info!(self);
Ok(sig)
}
Expr::UnaryOp(unary) => match unary.op.kind {
Expr::PrefixOp(prefix) => match prefix.op.kind {
TokenKind::PreStar => {
let mut exprs = unary.args.into_iter();
let mut exprs = prefix.args.into_iter();
let param = self
.convert_rhs_to_param(*exprs.next().unwrap(), false)
.map_err(|_| self.stack_dec(fn_name!()))?;
Expand All @@ -663,7 +663,7 @@ impl Parser {
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
_ => {
let err = ParseError::simple_syntax_error(line!() as usize, unary.op.loc());
let err = ParseError::simple_syntax_error(line!() as usize, prefix.op.loc());
self.errs.push(err);
debug_exit_info!(self);
Err(())
Expand Down
17 changes: 11 additions & 6 deletions crates/erg_parser/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use crate::ast::{
ClassAttr, ClassAttrs, ClassDef, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Dummy, Expr,
Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, MixedRecord, Module,
NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple,
ParamPattern, ParamRecordAttr, Params, PatchDef, PosArg, ReDef, Record, RecordAttrOrIdent,
RecordAttrs, Set as astSet, SetWithLength, Signature, SubrSignature, Tuple, TupleTypeSpec,
TypeAppArgs, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern,
ParamPattern, ParamRecordAttr, Params, PatchDef, PosArg, PostfixOp, PrefixOp, ReDef, Record,
RecordAttrOrIdent, RecordAttrs, Set as astSet, SetWithLength, Signature, SubrSignature, Tuple,
TupleTypeSpec, TypeAppArgs, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, VarName, VarPattern,
VarRecordAttr, VarSignature,
};
use crate::token::{Token, TokenKind, COLON, DOT};
Expand Down Expand Up @@ -219,10 +219,15 @@ impl Desugarer {
let rhs = desugar(*args.next().unwrap());
Expr::BinOp(BinOp::new(binop.op, lhs, rhs))
}
Expr::UnaryOp(unaryop) => {
let mut args = unaryop.args.into_iter();
Expr::PrefixOp(prefixop) => {
let mut args = prefixop.args.into_iter();
let expr = desugar(*args.next().unwrap());
Expr::UnaryOp(UnaryOp::new(unaryop.op, expr))
Expr::PrefixOp(PrefixOp::new(prefixop.op, expr))
}
Expr::PostfixOp(postfixop) => {
let mut args = postfixop.args.into_iter();
let expr = desugar(*args.next().unwrap());
Expr::PostfixOp(PostfixOp::new(expr, postfixop.op))
}
Expr::Call(call) => {
let obj = desugar(*call.obj);
Expand Down
43 changes: 24 additions & 19 deletions crates/erg_parser/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use erg_common::traits::{Locational, Runnable, Stream};
use erg_common::{debug_power_assert, fn_name_full, normalize_newline, switch_lang};

use crate::error::{LexError, LexErrors, LexResult, LexerRunnerError, LexerRunnerErrors};
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
use crate::token::{Token, TokenKind, TokenStream};
use TokenKind::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -292,32 +292,29 @@ impl Lexer /*<'a>*/ {
)
}

fn is_right_disconnective(s: char) -> bool {
matches!(s, ')' | ']' | '}' | ',' | ':' | ';' | '\n' | '>' | '=')
}

// +, -, * etc. may be pre/bin
// and, or, is!, isnot!, in, notin, as, dot, cross may be bin/function
// None means invalid syntax
fn op_fix(&self) -> Option<OpFix> {
match self.prev_token.category() {
// unary: `[ +`, `= +`, `+ +`, `, +`, `:: +`
TokenCategory::LEnclosure
| TokenCategory::BinOp
| TokenCategory::UnaryOp
| TokenCategory::Separator
| TokenCategory::SpecialBinOp
| TokenCategory::DefOp
| TokenCategory::LambdaOp
| TokenCategory::StrInterpLeft
| TokenCategory::StrInterpMid
| TokenCategory::BOF => Some(OpFix::Prefix),
TokenCategory::REnclosure
| TokenCategory::Literal
| TokenCategory::StrInterpRight
| TokenCategory::Symbol => match (self.peek_prev_prev_ch(), self.peek_cur_ch()) {
let left_disconnective = self.prev_token.category().is_left_disconnective();
let right_disconnective = self
.peek_cur_ch()
.map_or(false, Self::is_right_disconnective);
match (left_disconnective, right_disconnective) {
(true, true) => None,
(true, false) => Some(OpFix::Prefix),
(false, true) => Some(OpFix::Postfix),
(false, false) => match (self.peek_prev_prev_ch(), self.peek_cur_ch()) {
(Some(' '), Some(' ')) => Some(OpFix::Infix), // x + 1: bin
(Some(' '), Some(_)) => Some(OpFix::Prefix), // x +1: unary
(Some(_), Some(' ')) => Some(OpFix::Infix), // x+ 1 : bin
(Some(_), Some(_)) => Some(OpFix::Infix), // x+1: bin
_ => None,
},
_ => None,
}
}

Expand Down Expand Up @@ -1207,7 +1204,15 @@ impl Iterator for Lexer /*<'a>*/ {
self.consume();
self.accept(EllipsisLit, "...")
}
_ => self.accept(Closed, ".."),
_ => match self.op_fix() {
Some(OpFix::Prefix) => self.accept(PreRange, ".."),
Some(OpFix::Infix) => self.accept(Closed, ".."),
Some(OpFix::Postfix) => self.accept(PostRange, ".."),
_ => {
let token = self.emit_token(Illegal, "..");
Some(Err(LexError::simple_syntax_error(0, token.loc())))
}
},
}
}
// prev_token is Symbol => TupleAttribute
Expand Down
Loading