mirror of
https://github.com/erg-lang/erg.git
synced 2025-07-07 21:25:31 +00:00
feat: support symbolized operators
This commit is contained in:
parent
64874f4169
commit
21cb0bb4c1
5 changed files with 187 additions and 147 deletions
|
@ -837,6 +837,8 @@ impl_locational_for_enum!(ClassAttr; Def, Decl, Doc);
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ClassAttrs(Vec<ClassAttr>);
|
||||
|
||||
impl_stream!(ClassAttrs, ClassAttr);
|
||||
|
||||
impl NestedDisplay for ClassAttrs {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
fmt_lines(self.0.iter(), f, level)?;
|
||||
|
@ -856,28 +858,6 @@ impl From<Vec<ClassAttr>> for ClassAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
impl ClassAttrs {
|
||||
pub const fn new(attrs: Vec<ClassAttr>) -> Self {
|
||||
Self(attrs)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &ClassAttr> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ClassAttr> {
|
||||
self.0.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for ClassAttrs {
|
||||
type Item = ClassAttr;
|
||||
type IntoIter = <Vec<ClassAttr> as IntoIterator>::IntoIter;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct RecordAttrs(Vec<Def>);
|
||||
|
||||
|
@ -3135,6 +3115,10 @@ impl VarName {
|
|||
pub fn trim_end_proc_mark(&mut self) {
|
||||
self.0.content = Str::rc(self.0.content.trim_end_matches('!'));
|
||||
}
|
||||
|
||||
pub fn rename(&mut self, new: Str) {
|
||||
self.0.content = new;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -23,6 +23,36 @@ use crate::ast::{
|
|||
};
|
||||
use crate::token::{Token, TokenKind, COLON, DOT};
|
||||
|
||||
pub fn symop_to_dname(op: &str) -> Option<&'static str> {
|
||||
match op {
|
||||
"`_+_`" => Some("__add__"),
|
||||
"`_-_`" => Some("__sub__"),
|
||||
"`*`" | "`cross`" => Some("__mul__"),
|
||||
"`/`" => Some("__div__"),
|
||||
"`//`" => Some("__floordiv__"),
|
||||
"`**`" => Some("__pow__"),
|
||||
"`%`" => Some("__mod__"),
|
||||
"`@`" | "`dot`" => Some("__matmul__"),
|
||||
"`&&`" => Some("__and__"),
|
||||
"`||`" => Some("__or__"),
|
||||
"`^`" => Some("__xor__"),
|
||||
"`==`" => Some("__eq__"),
|
||||
"`!=`" => Some("__ne__"),
|
||||
"`<`" => Some("__lt__"),
|
||||
"`<=`" => Some("__le__"),
|
||||
"`>`" => Some("__gt__"),
|
||||
"`>=`" => Some("__ge__"),
|
||||
"`<<`" => Some("__lshift__"),
|
||||
"`>>`" => Some("__rshift__"),
|
||||
"`+_`" => Some("__pos__"),
|
||||
"`-_`" => Some("__neg__"),
|
||||
"`~`" => Some("__invert__"),
|
||||
"`!`" => Some("__mutate__"),
|
||||
"`...`" => Some("__spread__"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum BufIndex<'i> {
|
||||
Array(usize),
|
||||
|
@ -623,6 +653,107 @@ impl Desugarer {
|
|||
Block::new(self.desugar_pattern(block.into_iter()))
|
||||
}
|
||||
|
||||
fn desugar_def_pattern(&mut self, def: Def, new: &mut Vec<Expr>) {
|
||||
match def {
|
||||
Def {
|
||||
sig: Signature::Var(mut v),
|
||||
body,
|
||||
} => match &v.pat {
|
||||
VarPattern::Tuple(tup) => {
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(v.loc(), v.t_spec);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for (n, elem) in tup.elems.iter().enumerate() {
|
||||
self.desugar_nested_var_pattern(new, elem, &buf_name, BufIndex::Tuple(n));
|
||||
}
|
||||
}
|
||||
VarPattern::Array(arr) => {
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(v.loc(), v.t_spec);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for (n, elem) in arr.elems.iter().enumerate() {
|
||||
self.desugar_nested_var_pattern(new, elem, &buf_name, BufIndex::Array(n));
|
||||
}
|
||||
}
|
||||
VarPattern::Record(rec) => {
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(v.loc(), v.t_spec);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for VarRecordAttr { lhs, rhs } in rec.attrs.iter() {
|
||||
self.desugar_nested_var_pattern(new, rhs, &buf_name, BufIndex::Record(lhs));
|
||||
}
|
||||
}
|
||||
VarPattern::DataPack(pack) => {
|
||||
let t_spec =
|
||||
TypeSpecWithOp::new(COLON, pack.class.clone(), *pack.class_as_expr.clone());
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(
|
||||
v.loc(),
|
||||
Some(t_spec), // TODO: これだとvの型指定の意味がなくなる
|
||||
);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() {
|
||||
self.desugar_nested_var_pattern(new, rhs, &buf_name, BufIndex::Record(lhs));
|
||||
}
|
||||
}
|
||||
VarPattern::Ident(_) | VarPattern::Discard(_) => {
|
||||
if let VarPattern::Ident(ident) = v.pat {
|
||||
v.pat = VarPattern::Ident(Self::desugar_ident(ident));
|
||||
}
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let body = DefBody::new(body.op, block, body.id);
|
||||
let def = Def::new(Signature::Var(v), body);
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
},
|
||||
Def {
|
||||
sig: Signature::Subr(mut subr),
|
||||
mut body,
|
||||
} => {
|
||||
subr.ident = Self::desugar_ident(subr.ident);
|
||||
self.desugar_params_patterns(&mut subr.params, &mut body.block);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let body = DefBody::new(body.op, block, body.id);
|
||||
let def = Def::new(Signature::Subr(subr), body);
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: nested function pattern
|
||||
/// `[i, j] = [1, 2]` -> `i = 1; j = 2`
|
||||
/// `[i, j] = l` -> `i = l[0]; j = l[1]`
|
||||
|
@ -636,120 +767,33 @@ impl Desugarer {
|
|||
let mut new = Vec::with_capacity(chunks.len());
|
||||
for chunk in chunks.into_iter() {
|
||||
match chunk {
|
||||
Expr::Def(Def {
|
||||
sig: Signature::Var(v),
|
||||
body,
|
||||
}) => match &v.pat {
|
||||
VarPattern::Tuple(tup) => {
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(v.loc(), v.t_spec);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for (n, elem) in tup.elems.iter().enumerate() {
|
||||
self.desugar_nested_var_pattern(
|
||||
&mut new,
|
||||
elem,
|
||||
&buf_name,
|
||||
BufIndex::Tuple(n),
|
||||
);
|
||||
Expr::Def(def) => {
|
||||
self.desugar_def_pattern(def, &mut new);
|
||||
}
|
||||
Expr::Methods(methods) => {
|
||||
let mut new_attrs = Vec::with_capacity(methods.attrs.len());
|
||||
for attr in methods.attrs.into_iter() {
|
||||
match attr {
|
||||
ClassAttr::Def(def) => {
|
||||
let mut new = vec![];
|
||||
self.desugar_def_pattern(def, &mut new);
|
||||
let Expr::Def(def) = new.remove(0) else {
|
||||
todo!("{new:?}")
|
||||
};
|
||||
new_attrs.push(ClassAttr::Def(def));
|
||||
}
|
||||
_ => {
|
||||
new_attrs.push(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
VarPattern::Array(arr) => {
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(v.loc(), v.t_spec);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for (n, elem) in arr.elems.iter().enumerate() {
|
||||
self.desugar_nested_var_pattern(
|
||||
&mut new,
|
||||
elem,
|
||||
&buf_name,
|
||||
BufIndex::Array(n),
|
||||
);
|
||||
}
|
||||
}
|
||||
VarPattern::Record(rec) => {
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(v.loc(), v.t_spec);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for VarRecordAttr { lhs, rhs } in rec.attrs.iter() {
|
||||
self.desugar_nested_var_pattern(
|
||||
&mut new,
|
||||
rhs,
|
||||
&buf_name,
|
||||
BufIndex::Record(lhs),
|
||||
);
|
||||
}
|
||||
}
|
||||
VarPattern::DataPack(pack) => {
|
||||
let t_spec = TypeSpecWithOp::new(
|
||||
COLON,
|
||||
pack.class.clone(),
|
||||
*pack.class_as_expr.clone(),
|
||||
);
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(
|
||||
v.loc(),
|
||||
Some(t_spec), // TODO: これだとvの型指定の意味がなくなる
|
||||
);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let buf_def = Def::new(buf_sig, DefBody::new(body.op, block, body.id));
|
||||
new.push(Expr::Def(buf_def));
|
||||
for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() {
|
||||
self.desugar_nested_var_pattern(
|
||||
&mut new,
|
||||
rhs,
|
||||
&buf_name,
|
||||
BufIndex::Record(lhs),
|
||||
);
|
||||
}
|
||||
}
|
||||
VarPattern::Ident(_) | VarPattern::Discard(_) => {
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let body = DefBody::new(body.op, block, body.id);
|
||||
let def = Def::new(Signature::Var(v), body);
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
},
|
||||
Expr::Def(Def {
|
||||
sig: Signature::Subr(mut subr),
|
||||
mut body,
|
||||
}) => {
|
||||
self.desugar_params_patterns(&mut subr.params, &mut body.block);
|
||||
let block = body
|
||||
.block
|
||||
.into_iter()
|
||||
.map(|ex| self.rec_desugar_lambda_pattern(ex))
|
||||
.collect();
|
||||
let block = self.desugar_pattern_in_block(block);
|
||||
let body = DefBody::new(body.op, block, body.id);
|
||||
let def = Def::new(Signature::Subr(subr), body);
|
||||
new.push(Expr::Def(def));
|
||||
let methods = Methods::new(
|
||||
methods.class,
|
||||
*methods.class_as_expr,
|
||||
methods.vis,
|
||||
ClassAttrs::from(new_attrs),
|
||||
);
|
||||
new.push(Expr::Methods(methods));
|
||||
}
|
||||
Expr::Dummy(dummy) => {
|
||||
let loc = dummy.loc;
|
||||
|
@ -1450,6 +1494,8 @@ impl Desugarer {
|
|||
|
||||
/// x[y] => x.__getitem__(y)
|
||||
/// x.0 => x.__Tuple_getitem__(0)
|
||||
/// `==`(x, y) => __eq__(x, y)
|
||||
/// x.`==` y => x.__eq__ y
|
||||
fn desugar_acc(module: Module) -> Module {
|
||||
Self::desugar_all_chunks(module, Self::rec_desugar_acc)
|
||||
}
|
||||
|
@ -1500,12 +1546,20 @@ impl Desugarer {
|
|||
}
|
||||
Accessor::Attr(mut attr) => {
|
||||
attr.obj = Box::new(Self::rec_desugar_acc(*attr.obj));
|
||||
attr.ident = Self::desugar_ident(attr.ident);
|
||||
Expr::Accessor(Accessor::Attr(attr))
|
||||
}
|
||||
other => Expr::Accessor(other),
|
||||
Accessor::Ident(ident) => Expr::Accessor(Accessor::Ident(Self::desugar_ident(ident))),
|
||||
}
|
||||
}
|
||||
|
||||
fn desugar_ident(mut ident: Identifier) -> Identifier {
|
||||
if let Some(name) = symop_to_dname(ident.inspect()) {
|
||||
ident.name.rename(name.into());
|
||||
}
|
||||
ident
|
||||
}
|
||||
|
||||
// TODO: pipeline desugaring (move from `Parser`)
|
||||
fn desugar_operator(module: Module) -> Module {
|
||||
Self::desugar_all_chunks(module, Self::rec_desugar_operator)
|
||||
|
|
|
@ -277,18 +277,17 @@ impl Lexer /*<'a>*/ {
|
|||
matches!(
|
||||
s,
|
||||
"+_" | "_+_"
|
||||
| "-_"
|
||||
| "-"
|
||||
| "*"
|
||||
| "/"
|
||||
| "//"
|
||||
| "**"
|
||||
| "%"
|
||||
| ".."
|
||||
| "..="
|
||||
| "~"
|
||||
| "&&"
|
||||
| "||"
|
||||
| "^^"
|
||||
| "^"
|
||||
| ">>"
|
||||
| "<<"
|
||||
| "=="
|
||||
|
@ -1544,12 +1543,14 @@ impl Iterator for Lexer /*<'a>*/ {
|
|||
}
|
||||
}
|
||||
// Symbolized operators (シンボル化された演算子)
|
||||
// e.g. `-`(l, r) = l + (-r)
|
||||
// e.g. `-`(l, r) == __sub__(1, r) == l - r
|
||||
Some('`') => {
|
||||
let mut op = "".to_string();
|
||||
while let Some(c) = self.consume() {
|
||||
if c == '`' {
|
||||
if Self::is_definable_operator(&op[..]) {
|
||||
op.insert(0, '`');
|
||||
op.push('`');
|
||||
return self.accept(Symbol, &op);
|
||||
} else {
|
||||
let token = self.emit_token(Illegal, &op);
|
||||
|
@ -1569,10 +1570,10 @@ impl Iterator for Lexer /*<'a>*/ {
|
|||
line!() as usize,
|
||||
token.loc(),
|
||||
switch_lang!(
|
||||
"japanese" => format!("`{}`はユーザー定義できません", &token.content),
|
||||
"simplified_chinese" => format!("`{}`不能由用户定义", &token.content),
|
||||
"traditional_chinese" => format!("`{}`不能由用戶定義", &token.content),
|
||||
"english" => format!("`{}` cannot be defined by user", &token.content),
|
||||
"japanese" => format!("`{}`は存在しないか、ユーザー定義できません", &token.content),
|
||||
"simplified_chinese" => format!("`{}`不存在或不能由用户定义", &token.content),
|
||||
"traditional_chinese" => format!("`{}`不存在或不能由用戶定義", &token.content),
|
||||
"english" => format!("`{}` does not exist or cannot be defined by user", &token.content),
|
||||
),
|
||||
hint,
|
||||
)));
|
||||
|
|
|
@ -5,5 +5,5 @@ private = "this is a private variable"
|
|||
.C.
|
||||
x = 1
|
||||
.C|<: Eq|.
|
||||
__eq__ self, other =
|
||||
`==` self, other =
|
||||
self.x == other.x
|
||||
|
|
|
@ -4,14 +4,15 @@ Point.
|
|||
norm self = self::x**2 + self::y**2
|
||||
Point|<: Add(Point)|.
|
||||
Output = Point
|
||||
__add__ self, other: Point =
|
||||
# This is same as `__add__ self, other: Point = ...`
|
||||
`_+_` self, other: Point =
|
||||
Point.new(self::x + other::x, self::y + other::y)
|
||||
Point|<: Mul(Point)|.
|
||||
Output = Int
|
||||
__mul__ self, other: Point =
|
||||
`*` self, other: Point =
|
||||
self::x * other::x + self::y * other::y
|
||||
Point|<: Eq|.
|
||||
__eq__ self, other: Point =
|
||||
`==` self, other: Point =
|
||||
self::x == other::x and self::y == other::y
|
||||
|
||||
p = Point.new 1, 2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue