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

Enable shortened/normal mixed record definition #239

Merged
merged 3 commits into from
Nov 21, 2022
Merged
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
2 changes: 1 addition & 1 deletion compiler/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ impl Context {
fn eval_const_record(&self, record: &Record) -> EvalResult<ValueObj> {
match record {
Record::Normal(rec) => self.eval_const_normal_record(rec),
Record::Shortened(_rec) => unreachable!(), // should be desugared
Record::Mixed(_rec) => unreachable!(), // should be desugared
}
}

Expand Down
5 changes: 2 additions & 3 deletions compiler/erg_compiler/context/inquire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use erg_common::error::{ErrorCore, ErrorKind, Location};
use erg_common::levenshtein::get_similar_name;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::{Field, Visibility};
use erg_common::vis::Visibility;
use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set};
use erg_common::{option_enum_unwrap, Str};
use Type::*;
Expand Down Expand Up @@ -530,8 +530,7 @@ impl Context {
self.get_attr_info_from_attributive(&refine.t, ident, namespace)
}
Type::Record(record) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why?
if let Some(attr_t) = record.get(&Field::new(Public, ident.inspect().clone())) {
if let Some(attr_t) = record.get(ident.inspect()) {
let muty = Mutability::from(&ident.inspect()[..]);
let vi = VarInfo::new(
attr_t.clone(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/erg_compiler/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl ASTLowerer {
log!(info "entered {}({record})", fn_name!());
match record {
ast::Record::Normal(rec) => self.lower_normal_record(rec),
ast::Record::Shortened(_rec) => unreachable!(), // should be desugared
ast::Record::Mixed(_rec) => unreachable!(), // should be desugared
}
}

Expand Down
78 changes: 57 additions & 21 deletions compiler/erg_parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,9 @@ impl Subscript {

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TypeAppArgs {
l_vbar: Token,
pub l_vbar: Token,
pub args: Args,
r_vbar: Token,
pub r_vbar: Token,
}

impl NestedDisplay for TypeAppArgs {
Expand Down Expand Up @@ -447,6 +447,10 @@ impl Accessor {
Self::Subscr(Subscript::new(obj, index, r_sqbr))
}

pub fn type_app(obj: Expr, type_args: TypeAppArgs) -> Self {
Self::TypeApp(TypeApp::new(obj, type_args))
}

pub const fn name(&self) -> Option<&Str> {
match self {
Self::Ident(ident) => Some(ident.inspect()),
Expand Down Expand Up @@ -830,46 +834,74 @@ impl NormalRecord {
}
}

/// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z})
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ShortenedRecord {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Record {
Normal(NormalRecord),
Mixed(MixedRecord),
}

impl_nested_display_for_enum!(Record; Normal, Mixed);
impl_display_for_enum!(Record; Normal, Mixed);
impl_locational_for_enum!(Record; Normal, Mixed);

impl Record {
pub const fn new_mixed(l_brace: Token, r_brace: Token, attrs: Vec<RecordAttrOrIdent>) -> Self {
Self::Mixed(MixedRecord {
l_brace,
r_brace,
attrs,
})
}

pub fn empty(l_brace: Token, r_brace: Token) -> Self {
Self::Normal(NormalRecord {
l_brace,
r_brace,
attrs: RecordAttrs::new(Vec::with_capacity(0)),
})
}
}

/// Record can be defined with shorthend/normal mixed style, i.e. {x; y=expr; z; ...}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MixedRecord {
pub l_brace: Token,
pub r_brace: Token,
pub idents: Vec<Identifier>,
pub attrs: Vec<RecordAttrOrIdent>,
}

impl NestedDisplay for ShortenedRecord {
impl NestedDisplay for MixedRecord {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{{")?;
for ident in self.idents.iter() {
write!(f, "{}; ", ident)?;
for attr in self.attrs.iter() {
write!(f, "{}; ", attr)?;
}
write!(f, "}}")
}
}

impl_display_from_nested!(ShortenedRecord);
impl_locational!(ShortenedRecord, l_brace, r_brace);
impl_display_from_nested!(MixedRecord);
impl_locational!(MixedRecord, l_brace, r_brace);

impl ShortenedRecord {
pub const fn new(l_brace: Token, r_brace: Token, idents: Vec<Identifier>) -> Self {
impl MixedRecord {
pub fn new(l_brace: Token, r_brace: Token, attrs: Vec<RecordAttrOrIdent>) -> Self {
Self {
l_brace,
r_brace,
idents,
attrs,
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Record {
Normal(NormalRecord),
Shortened(ShortenedRecord),
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum RecordAttrOrIdent {
Attr(Def),
Ident(Identifier),
}

impl_nested_display_for_enum!(Record; Normal, Shortened);
impl_display_for_enum!(Record; Normal, Shortened);
impl_locational_for_enum!(Record; Normal, Shortened);
impl_nested_display_for_enum!(RecordAttrOrIdent; Attr, Ident);
impl_display_for_enum!(RecordAttrOrIdent; Attr, Ident);
impl_locational_for_enum!(RecordAttrOrIdent; Attr, Ident);

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NormalSet {
Expand Down Expand Up @@ -3479,6 +3511,10 @@ impl Expr {
Self::Accessor(self.tuple_attr(index))
}

pub fn type_app(self, type_args: TypeAppArgs) -> Accessor {
Accessor::type_app(self, type_args)
}

pub fn call(self, args: Args) -> Call {
match self {
Self::Accessor(Accessor::Attr(attr)) => Call::new(*attr.obj, Some(attr.ident), args),
Expand Down
147 changes: 104 additions & 43 deletions compiler/erg_parser/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ use erg_common::{enum_unwrap, get_hash, log, set};

use crate::ast::{
Accessor, Args, Array, ArrayComprehension, ArrayTypeSpec, ArrayWithLength, BinOp, Block, Call,
ClassAttr, ClassAttrs, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr, Identifier,
KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, Module, NonDefaultParamSignature,
NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple, ParamPattern, ParamRecordAttr,
Params, PosArg, Record, RecordAttrs, Set as astSet, SetWithLength, ShortenedRecord, Signature,
SubrSignature, Tuple, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern,
VarRecordAttr, VarSignature,
ClassAttr, ClassAttrs, ClassDef, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr,
Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, MixedRecord, Module,
NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple,
ParamPattern, ParamRecordAttr, Params, PosArg, Record, RecordAttrOrIdent, RecordAttrs,
Set as astSet, SetWithLength, Signature, SubrSignature, Tuple, TypeAppArgs, TypeBoundSpecs,
TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
};
use crate::token::{Token, TokenKind, COLON, DOT};

Expand Down Expand Up @@ -63,8 +63,25 @@ impl Desugarer {
module.into_iter().map(desugar).collect()
}

fn desugar_args(mut desugar: impl FnMut(Expr) -> Expr, args: Args) -> Args {
let (pos_args, kw_args, paren) = args.deconstruct();
let pos_args = pos_args
.into_iter()
.map(|arg| PosArg::new(desugar(arg.expr)))
.collect();
let kw_args = kw_args
.into_iter()
.map(|arg| {
let expr = desugar(arg.expr);
KwArg::new(arg.keyword, arg.t_spec, expr) // TODO: t_spec
})
.collect();
Args::new(pos_args, kw_args, paren)
}

fn perform_desugar(mut desugar: impl FnMut(Expr) -> Expr, expr: Expr) -> Expr {
match expr {
Expr::Lit(_) => expr,
Expr::Record(record) => match record {
Record::Normal(rec) => {
let mut new_attrs = vec![];
Expand All @@ -77,7 +94,28 @@ impl Desugarer {
RecordAttrs::new(new_attrs),
)))
}
shorten => Expr::Record(shorten),
Record::Mixed(mixed) => {
let mut new_attrs = vec![];
for attr in mixed.attrs {
match attr {
RecordAttrOrIdent::Attr(attr) => {
let attr = RecordAttrOrIdent::Attr(enum_unwrap!(
desugar(Expr::Def(attr)),
Expr::Def
));
new_attrs.push(attr);
}
RecordAttrOrIdent::Ident(ident) => {
new_attrs.push(RecordAttrOrIdent::Ident(ident));
}
}
}
Expr::Record(Record::Mixed(MixedRecord::new(
mixed.l_brace,
mixed.r_brace,
new_attrs,
)))
}
},
Expr::DataPack(pack) => {
let class = desugar(*pack.class);
Expand Down Expand Up @@ -173,19 +211,7 @@ impl Desugarer {
}
Expr::Call(call) => {
let obj = desugar(*call.obj);
let (pos_args, kw_args, paren) = call.args.deconstruct();
let pos_args = pos_args
.into_iter()
.map(|arg| PosArg::new(desugar(arg.expr)))
.collect();
let kw_args = kw_args
.into_iter()
.map(|arg| {
let expr = desugar(arg.expr);
KwArg::new(arg.keyword, arg.t_spec, expr) // TODO: t_spec
})
.collect();
let args = Args::new(pos_args, kw_args, paren);
let args = Self::desugar_args(desugar, call.args);
Expr::Call(Call::new(obj, call.attr_name, args))
}
Expr::Def(def) => {
Expand All @@ -196,6 +222,15 @@ impl Desugarer {
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
Expr::Def(Def::new(def.sig, body))
}
Expr::ClassDef(class_def) => {
let def = enum_unwrap!(desugar(Expr::Def(class_def.def)), Expr::Def);
let methods = class_def
.methods_list
.into_iter()
.map(|method| enum_unwrap!(desugar(Expr::Methods(method)), Expr::Methods))
.collect();
Expr::ClassDef(ClassDef::new(def, methods))
}
Expr::Lambda(lambda) => {
let mut chunks = vec![];
for chunk in lambda.body.into_iter() {
Expand Down Expand Up @@ -229,8 +264,29 @@ impl Desugarer {
let new_attrs = ClassAttrs::from(new_attrs);
Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_attrs))
}
// TODO: Accessor
other => other,
Expr::Accessor(acc) => {
let acc = match acc {
Accessor::Ident(ident) => Accessor::Ident(ident),
Accessor::Attr(attr) => desugar(*attr.obj).attr(attr.ident),
Accessor::TupleAttr(tup) => {
let obj = desugar(*tup.obj);
obj.tuple_attr(tup.index)
}
Accessor::Subscr(sub) => {
let obj = desugar(*sub.obj);
let index = desugar(*sub.index);
obj.subscr(index, sub.r_sqbr)
}
Accessor::TypeApp(tapp) => {
let obj = desugar(*tapp.obj);
let args = Self::desugar_args(desugar, tapp.type_args.args);
let type_args =
TypeAppArgs::new(tapp.type_args.l_vbar, args, tapp.type_args.r_vbar);
obj.type_app(type_args)
}
};
Expr::Accessor(acc)
}
}
}

Expand Down Expand Up @@ -595,12 +651,12 @@ impl Desugarer {

fn rec_desugar_shortened_record(expr: Expr) -> Expr {
match expr {
Expr::Record(Record::Shortened(rec)) => {
let rec = Self::desugar_shortened_record_inner(rec);
Expr::Record(Record::Mixed(record)) => {
let rec = Self::desugar_shortened_record_inner(record);
Expr::Record(Record::Normal(rec))
}
Expr::DataPack(pack) => {
if let Record::Shortened(rec) = pack.args {
if let Record::Mixed(rec) = pack.args {
let class = Self::rec_desugar_shortened_record(*pack.class);
let rec = Self::desugar_shortened_record_inner(rec);
let args = Record::Normal(rec);
Expand All @@ -613,25 +669,30 @@ impl Desugarer {
}
}

fn desugar_shortened_record_inner(rec: ShortenedRecord) -> NormalRecord {
let mut attrs = vec![];
for attr in rec.idents.into_iter() {
let var = VarSignature::new(VarPattern::Ident(attr.clone()), None);
let sig = Signature::Var(var);
let body = DefBody::new(
Token::from_str(TokenKind::Equal, "="),
Block::new(vec![Expr::local(
attr.inspect(),
attr.ln_begin().unwrap(),
attr.col_begin().unwrap(),
)]),
DefId(get_hash(&(&sig, attr.inspect()))),
);
let def = Def::new(sig, body);
attrs.push(def);
}
fn desugar_shortened_record_inner(record: MixedRecord) -> NormalRecord {
let attrs = record
.attrs
.into_iter()
.map(|attr_or_ident| match attr_or_ident {
RecordAttrOrIdent::Attr(def) => def,
RecordAttrOrIdent::Ident(ident) => {
let var = VarSignature::new(VarPattern::Ident(ident.clone()), None);
let sig = Signature::Var(var);
let body = DefBody::new(
Token::from_str(TokenKind::Equal, "="),
Block::new(vec![Expr::local(
ident.inspect(),
ident.ln_begin().unwrap(),
ident.col_begin().unwrap(),
)]),
DefId(get_hash(&(&sig, ident.inspect()))),
);
Def::new(sig, body)
}
})
.collect();
let attrs = RecordAttrs::new(attrs);
NormalRecord::new(rec.l_brace, rec.r_brace, attrs)
NormalRecord::new(record.l_brace, record.r_brace, attrs)
}

/// ```erg
Expand Down
Loading