mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
Impl ShortenedRecord
desugaring
This commit is contained in:
parent
4557690347
commit
d2ed277685
6 changed files with 281 additions and 29 deletions
|
@ -264,7 +264,14 @@ impl Evaluator {
|
|||
Some(ValueObj::Array(RcArray::from(elems)))
|
||||
}
|
||||
|
||||
fn eval_const_record(&self, record: &NormalRecord, ctx: &Context) -> Option<ValueObj> {
|
||||
fn eval_const_record(&self, record: &Record, ctx: &Context) -> Option<ValueObj> {
|
||||
match record {
|
||||
Record::Normal(rec) => self.eval_const_normal_record(rec, ctx),
|
||||
Record::Shortened(_rec) => unreachable!(), // should be desugared
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_const_normal_record(&self, record: &NormalRecord, ctx: &Context) -> Option<ValueObj> {
|
||||
let mut attrs = vec![];
|
||||
for attr in record.attrs.iter() {
|
||||
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
|
||||
|
|
|
@ -217,7 +217,15 @@ impl ASTLowerer {
|
|||
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
|
||||
}
|
||||
|
||||
fn lower_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
|
||||
fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_normal_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
|
||||
log!(info "entered {}({record})", fn_name!());
|
||||
let mut hir_record =
|
||||
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
|
||||
|
|
|
@ -6,8 +6,6 @@ use erg_common::error::Location;
|
|||
use erg_common::set::Set as HashSet;
|
||||
use erg_common::traits::{Locational, NestedDisplay, Stream};
|
||||
use erg_common::vis::{Field, Visibility};
|
||||
// use erg_common::ty::SubrKind;
|
||||
// use erg_common::value::{Field, ValueObj, Visibility};
|
||||
use erg_common::Str;
|
||||
use erg_common::{
|
||||
fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct,
|
||||
|
@ -675,6 +673,10 @@ impl From<Vec<Def>> for RecordAttrs {
|
|||
}
|
||||
|
||||
impl RecordAttrs {
|
||||
pub const fn new(attrs: Vec<Def>) -> Self {
|
||||
Self(attrs)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Def> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
@ -714,12 +716,45 @@ impl NormalRecord {
|
|||
|
||||
/// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z})
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct SimpleRecord {
|
||||
pub struct ShortenedRecord {
|
||||
pub l_brace: Token,
|
||||
pub r_brace: Token,
|
||||
idents: Vec<Identifier>,
|
||||
pub idents: Vec<Identifier>,
|
||||
}
|
||||
|
||||
impl NestedDisplay for ShortenedRecord {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
write!(f, "{{")?;
|
||||
for ident in self.idents.iter() {
|
||||
write!(f, "{}; ", ident)?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(ShortenedRecord);
|
||||
impl_locational!(ShortenedRecord, l_brace, r_brace);
|
||||
|
||||
impl ShortenedRecord {
|
||||
pub const fn new(l_brace: Token, r_brace: Token, idents: Vec<Identifier>) -> Self {
|
||||
Self {
|
||||
l_brace,
|
||||
r_brace,
|
||||
idents,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Record {
|
||||
Normal(NormalRecord),
|
||||
Shortened(ShortenedRecord),
|
||||
}
|
||||
|
||||
impl_nested_display_for_enum!(Record; Normal, Shortened);
|
||||
impl_display_for_enum!(Record; Normal, Shortened);
|
||||
impl_locational_for_enum!(Record; Normal, Shortened);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NormalSet {
|
||||
l_brace: Token,
|
||||
|
@ -2610,7 +2645,8 @@ pub struct Def {
|
|||
|
||||
impl NestedDisplay for Def {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
writeln!(f, "{} {}", self.sig, self.body.op.content)?;
|
||||
self.sig.fmt_nest(f, level)?;
|
||||
writeln!(f, " {}", self.body.op.content)?;
|
||||
self.body.block.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
@ -2671,7 +2707,7 @@ pub enum Expr {
|
|||
Tuple(Tuple),
|
||||
Dict(Dict),
|
||||
Set(Set),
|
||||
Record(NormalRecord),
|
||||
Record(Record),
|
||||
BinOp(BinOp),
|
||||
UnaryOp(UnaryOp),
|
||||
Call(Call),
|
||||
|
|
|
@ -11,9 +11,11 @@ use erg_common::Str;
|
|||
use erg_common::{enum_unwrap, get_hash, set};
|
||||
|
||||
use crate::ast::{
|
||||
Accessor, Args, Block, Call, Def, DefBody, DefId, Expr, Identifier, Lambda, LambdaSignature,
|
||||
Literal, Local, Module, ParamPattern, ParamSignature, Params, PosArg, Signature, SubrSignature,
|
||||
TypeBoundSpecs, TypeSpec, VarName, VarPattern, VarSignature,
|
||||
Accessor, Args, Array, BinOp, Block, Call, Def, DefBody, DefId, Expr, Identifier, KwArg,
|
||||
Lambda, LambdaSignature, Literal, Local, MethodDefs, Module, NormalArray, NormalRecord,
|
||||
NormalTuple, ParamPattern, ParamSignature, Params, PosArg, Record, RecordAttrs,
|
||||
ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
|
||||
UnaryOp, VarName, VarPattern, VarSignature,
|
||||
};
|
||||
use crate::token::{Token, TokenKind};
|
||||
|
||||
|
@ -46,7 +48,9 @@ impl Desugarer {
|
|||
|
||||
pub fn desugar(&mut self, module: Module) -> Module {
|
||||
let module = self.desugar_multiple_pattern_def(module);
|
||||
self.desugar_pattern(module)
|
||||
let module = self.desugar_pattern(module);
|
||||
let module = self.desugar_shortened_record(module);
|
||||
module
|
||||
}
|
||||
|
||||
fn desugar_ubar_lambda(&self, _module: Module) -> Module {
|
||||
|
@ -306,6 +310,149 @@ impl Desugarer {
|
|||
}
|
||||
}
|
||||
|
||||
/// `{x; y}` -> `{x = x; y = y}`
|
||||
fn desugar_shortened_record(&self, mut module: Module) -> Module {
|
||||
let mut new = Module::with_capacity(module.len());
|
||||
while let Some(chunk) = module.lpop() {
|
||||
new.push(self.rec_desugar_shortened_record(chunk));
|
||||
}
|
||||
new
|
||||
}
|
||||
|
||||
fn rec_desugar_shortened_record(&self, expr: Expr) -> Expr {
|
||||
match expr {
|
||||
Expr::Record(Record::Shortened(rec)) => {
|
||||
let rec = self.desugar_shortened_record_inner(rec);
|
||||
Expr::Record(Record::Normal(rec))
|
||||
}
|
||||
Expr::Array(array) => match array {
|
||||
Array::Normal(arr) => {
|
||||
let (elems, _, _) = arr.elems.deconstruct();
|
||||
let elems = elems
|
||||
.into_iter()
|
||||
.map(|elem| PosArg::new(self.rec_desugar_shortened_record(elem.expr)))
|
||||
.collect();
|
||||
let elems = Args::new(elems, vec![], None);
|
||||
let arr = NormalArray::new(arr.l_sqbr, arr.r_sqbr, elems);
|
||||
Expr::Array(Array::Normal(arr))
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
Expr::Tuple(tuple) => match tuple {
|
||||
Tuple::Normal(tup) => {
|
||||
let (elems, _, paren) = tup.elems.deconstruct();
|
||||
let elems = elems
|
||||
.into_iter()
|
||||
.map(|elem| PosArg::new(self.rec_desugar_shortened_record(elem.expr)))
|
||||
.collect();
|
||||
let new_tup = Args::new(elems, vec![], paren);
|
||||
let tup = NormalTuple::new(new_tup);
|
||||
Expr::Tuple(Tuple::Normal(tup))
|
||||
}
|
||||
},
|
||||
Expr::Set(set) => {
|
||||
todo!("{set}")
|
||||
}
|
||||
Expr::Dict(dict) => {
|
||||
todo!("{dict}")
|
||||
}
|
||||
Expr::BinOp(binop) => {
|
||||
let mut args = vec![];
|
||||
for arg in binop.args.into_iter() {
|
||||
args.push(self.rec_desugar_shortened_record(*arg));
|
||||
}
|
||||
let lhs = args.remove(0);
|
||||
let rhs = args.remove(0);
|
||||
Expr::BinOp(BinOp::new(binop.op, lhs, rhs))
|
||||
}
|
||||
Expr::UnaryOp(unaryop) => {
|
||||
let mut args = vec![];
|
||||
for arg in unaryop.args.into_iter() {
|
||||
args.push(self.rec_desugar_shortened_record(*arg));
|
||||
}
|
||||
let expr = args.remove(0);
|
||||
Expr::UnaryOp(UnaryOp::new(unaryop.op, expr))
|
||||
}
|
||||
Expr::Call(call) => {
|
||||
let obj = self.rec_desugar_shortened_record(*call.obj);
|
||||
let (pos_args, kw_args, paren) = call.args.deconstruct();
|
||||
let pos_args = pos_args
|
||||
.into_iter()
|
||||
.map(|arg| PosArg::new(self.rec_desugar_shortened_record(arg.expr)))
|
||||
.collect();
|
||||
let kw_args = kw_args
|
||||
.into_iter()
|
||||
.map(|arg| {
|
||||
let expr = self.rec_desugar_shortened_record(arg.expr);
|
||||
KwArg::new(arg.keyword, arg.t_spec, expr) // TODO: t_spec
|
||||
})
|
||||
.collect();
|
||||
let args = Args::new(pos_args, kw_args, paren);
|
||||
Expr::Call(Call::new(obj, call.method_name, args))
|
||||
}
|
||||
Expr::Def(def) => {
|
||||
let mut chunks = vec![];
|
||||
for chunk in def.body.block.into_iter() {
|
||||
chunks.push(self.rec_desugar_shortened_record(chunk));
|
||||
}
|
||||
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
|
||||
Expr::Def(Def::new(def.sig, body))
|
||||
}
|
||||
Expr::Lambda(lambda) => {
|
||||
let mut chunks = vec![];
|
||||
for chunk in lambda.body.into_iter() {
|
||||
chunks.push(self.rec_desugar_shortened_record(chunk));
|
||||
}
|
||||
let body = Block::new(chunks);
|
||||
Expr::Lambda(Lambda::new(lambda.sig, lambda.op, body, lambda.id))
|
||||
}
|
||||
Expr::TypeAsc(tasc) => {
|
||||
let expr = self.rec_desugar_shortened_record(*tasc.expr);
|
||||
Expr::TypeAsc(TypeAscription::new(expr, tasc.t_spec))
|
||||
}
|
||||
Expr::MethodDefs(method_defs) => {
|
||||
let mut new_defs = vec![];
|
||||
for def in method_defs.defs.into_iter() {
|
||||
let mut chunks = vec![];
|
||||
for chunk in def.body.block.into_iter() {
|
||||
chunks.push(self.rec_desugar_shortened_record(chunk));
|
||||
}
|
||||
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
|
||||
new_defs.push(Def::new(def.sig, body));
|
||||
}
|
||||
let new_defs = RecordAttrs::from(new_defs);
|
||||
Expr::MethodDefs(MethodDefs::new(
|
||||
method_defs.class,
|
||||
method_defs.vis,
|
||||
new_defs,
|
||||
))
|
||||
}
|
||||
// TODO: Accessorにも一応レコードを入れられる
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
fn desugar_shortened_record_inner(&self, 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);
|
||||
}
|
||||
let attrs = RecordAttrs::new(attrs);
|
||||
NormalRecord::new(rec.l_brace, rec.r_brace, attrs)
|
||||
}
|
||||
|
||||
/// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})`
|
||||
fn desugar_refinement_pattern(&self, _mod: Module) -> Module {
|
||||
todo!()
|
||||
|
|
|
@ -64,7 +64,7 @@ pub enum ArrayInner {
|
|||
pub enum BraceContainer {
|
||||
Set(Set),
|
||||
Dict(Dict),
|
||||
Record(NormalRecord),
|
||||
Record(Record),
|
||||
}
|
||||
|
||||
/// Perform recursive descent parsing.
|
||||
|
@ -1410,12 +1410,20 @@ impl Parser {
|
|||
match first {
|
||||
Expr::Def(def) => {
|
||||
let record = self
|
||||
.try_reduce_record(l_brace, def)
|
||||
.try_reduce_normal_record(l_brace, def)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(BraceContainer::Record(record))
|
||||
Ok(BraceContainer::Record(Record::Normal(record)))
|
||||
}
|
||||
// Dict
|
||||
Expr::TypeAsc(_) => todo!(),
|
||||
Expr::Accessor(acc) if self.cur_is(Semi) => {
|
||||
let record = self
|
||||
.try_reduce_shortened_record(l_brace, acc)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(BraceContainer::Record(Record::Shortened(record)))
|
||||
}
|
||||
Expr::TypeAsc(_) => todo!(), // invalid syntax
|
||||
other => {
|
||||
let set = self
|
||||
.try_reduce_set(l_brace, other)
|
||||
|
@ -1426,7 +1434,11 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_reduce_record(&mut self, l_brace: Token, first: Def) -> ParseResult<NormalRecord> {
|
||||
fn try_reduce_normal_record(
|
||||
&mut self,
|
||||
l_brace: Token,
|
||||
first: Def,
|
||||
) -> ParseResult<NormalRecord> {
|
||||
debug_call_info!(self);
|
||||
let mut attrs = vec![first];
|
||||
loop {
|
||||
|
@ -1459,6 +1471,54 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_reduce_shortened_record(
|
||||
&mut self,
|
||||
l_brace: Token,
|
||||
first: Accessor,
|
||||
) -> ParseResult<ShortenedRecord> {
|
||||
debug_call_info!(self);
|
||||
let first = match first {
|
||||
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)),
|
||||
Accessor::Public(public) => {
|
||||
Identifier::new(Some(public.dot), VarName::new(public.symbol))
|
||||
}
|
||||
other => todo!("{other}"), // syntax error
|
||||
};
|
||||
let mut idents = vec![first];
|
||||
loop {
|
||||
match self.peek() {
|
||||
Some(t) if t.category_is(TC::Separator) => {
|
||||
self.skip();
|
||||
if self.cur_is(Dedent) {
|
||||
self.skip();
|
||||
if self.cur_is(RBrace) {
|
||||
let r_brace = self.lpop();
|
||||
self.level -= 1;
|
||||
return Ok(ShortenedRecord::new(l_brace, r_brace, idents));
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
|
||||
let acc = match acc {
|
||||
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)),
|
||||
Accessor::Public(public) => {
|
||||
Identifier::new(Some(public.dot), VarName::new(public.symbol))
|
||||
}
|
||||
other => todo!("{other}"), // syntax error
|
||||
};
|
||||
idents.push(acc);
|
||||
}
|
||||
Some(term) if term.is(RBrace) => {
|
||||
let r_brace = self.lpop();
|
||||
self.level -= 1;
|
||||
return Ok(ShortenedRecord::new(l_brace, r_brace, idents));
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _try_reduce_dict() -> ParseResult<Dict> {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1594,10 +1654,7 @@ impl Parser {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn convert_record_to_record_pat(
|
||||
&mut self,
|
||||
_record: NormalRecord,
|
||||
) -> ParseResult<VarRecordPattern> {
|
||||
fn convert_record_to_record_pat(&mut self, _record: Record) -> ParseResult<VarRecordPattern> {
|
||||
debug_call_info!(self);
|
||||
todo!()
|
||||
}
|
||||
|
@ -1809,7 +1866,7 @@ impl Parser {
|
|||
|
||||
fn convert_record_to_param_record_pat(
|
||||
&mut self,
|
||||
_record: NormalRecord,
|
||||
_record: Record,
|
||||
) -> ParseResult<ParamRecordPattern> {
|
||||
debug_call_info!(self);
|
||||
todo!()
|
||||
|
@ -1920,10 +1977,7 @@ impl Parser {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn convert_record_to_param_pat(
|
||||
&mut self,
|
||||
_record: NormalRecord,
|
||||
) -> ParseResult<ParamRecordPattern> {
|
||||
fn convert_record_to_param_pat(&mut self, _record: Record) -> ParseResult<ParamRecordPattern> {
|
||||
debug_call_info!(self);
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
@Inheritable
|
||||
Point2D = Class {x = Int; y = Int}
|
||||
Point2D.
|
||||
new x, y = Self::__new__ {x = x; y = y}
|
||||
new x, y = Self::__new__ {x; y}
|
||||
norm ref self = self::x**2 + self::y**2
|
||||
|
||||
Point3D = Inherit Point2D, Additional := {z = Int}
|
||||
Point3D.
|
||||
@Override
|
||||
new x, y, z = Self::__new__ {x = x; y = y; z = z}
|
||||
new x, y, z = Self::__new__ {x; y; z}
|
||||
@Override
|
||||
norm ref self = self::x**2 + self::y**2 + self::z**2
|
||||
|
||||
UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack
|
||||
|
||||
p = UnpackPoint2D::{x = 1; y = 2}
|
||||
UnpackPoint2D::{x = x; y = x} = p
|
||||
UnpackPoint2D::{x; y} = p
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue