feat: support symbolized operators

This commit is contained in:
Shunsuke Shibayama 2023-09-09 16:45:24 +09:00
parent 64874f4169
commit 21cb0bb4c1
5 changed files with 187 additions and 147 deletions

View file

@ -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)]

View file

@ -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)

View file

@ -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,
)));

View file

@ -5,5 +5,5 @@ private = "this is a private variable"
.C.
x = 1
.C|<: Eq|.
__eq__ self, other =
`==` self, other =
self.x == other.x

View file

@ -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