Impl Dict parsing

This commit is contained in:
Shunsuke Shibayama 2022-10-08 12:44:11 +09:00
parent 7d659da6a5
commit ec196d0695
3 changed files with 174 additions and 49 deletions

View file

@ -590,16 +590,40 @@ impl Tuple {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyValue {
pub key: Box<Expr>,
pub value: Box<Expr>,
}
impl NestedDisplay for KeyValue {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{}: {}", self.key, self.value)
}
}
impl_display_from_nested!(KeyValue);
impl_locational!(KeyValue, key, value);
impl KeyValue {
pub fn new(key: Expr, value: Expr) -> Self {
Self {
key: Box::new(key),
value: Box::new(value),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NormalDict {
l_brace: Token,
r_brace: Token,
pub attrs: Args, // TODO: Impl K: V Pair
pub(crate) l_brace: Token,
pub(crate) r_brace: Token,
pub kvs: Vec<KeyValue>,
}
impl NestedDisplay for NormalDict {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{{{}}}", self.attrs)
write!(f, "{{{}}}", fmt_vec(&self.kvs))
}
}
@ -607,11 +631,11 @@ impl_display_from_nested!(NormalDict);
impl_locational!(NormalDict, l_brace, r_brace);
impl NormalDict {
pub fn new(l_brace: Token, r_brace: Token, attrs: Args) -> Self {
pub fn new(l_brace: Token, r_brace: Token, kvs: Vec<KeyValue>) -> Self {
Self {
l_brace,
r_brace,
attrs,
kvs,
}
}
}

View file

@ -12,11 +12,11 @@ use erg_common::{enum_unwrap, get_hash, log, set};
use crate::ast::{
Accessor, Args, Array, ArrayComprehension, ArrayWithLength, BinOp, Block, Call, DataPack, Def,
DefBody, DefId, Expr, Identifier, KwArg, Lambda, LambdaSignature, Literal, Methods, Module,
NormalArray, NormalRecord, NormalSet, NormalTuple, ParamPattern, ParamSignature, Params,
PosArg, Record, RecordAttrs, Set as astSet, SetWithLength, ShortenedRecord, Signature,
SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec, UnaryOp, VarName, VarPattern,
VarRecordAttr, VarSignature,
DefBody, DefId, Dict, Expr, Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal,
Methods, Module, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple, ParamPattern,
ParamSignature, Params, PosArg, Record, RecordAttrs, Set as astSet, SetWithLength,
ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
};
use crate::token::{Token, TokenKind};
@ -439,9 +439,22 @@ impl Desugarer {
Expr::Set(astSet::WithLength(set))
}
},
Expr::Dict(dict) => {
todo!("{dict}")
Expr::Dict(dict) => match dict {
Dict::Normal(dic) => {
let new_kvs = dic
.kvs
.into_iter()
.map(|elem| {
let key = self.rec_desugar_shortened_record(*elem.key);
let value = self.rec_desugar_shortened_record(*elem.value);
KeyValue::new(key, value)
})
.collect();
let tup = NormalDict::new(dic.l_brace, dic.r_brace, new_kvs);
Expr::Dict(Dict::Normal(tup))
}
_ => todo!("dict comprehension"),
},
Expr::BinOp(binop) => {
let mut args = binop.args.into_iter();
let lhs = self.rec_desugar_shortened_record(*args.next().unwrap());

View file

@ -264,7 +264,7 @@ impl Parser {
switch_unreachable!()
}
Some(_) => {
if let Ok(expr) = self.try_reduce_chunk(true) {
if let Ok(expr) = self.try_reduce_chunk(true, false) {
chunks.push(expr);
}
}
@ -280,7 +280,9 @@ impl Parser {
let mut block = Block::with_capacity(2);
// single line block
if !self.cur_is(Newline) {
let chunk = self.try_reduce_chunk(true).map_err(|_| self.stack_dec())?;
let chunk = self
.try_reduce_chunk(true, false)
.map_err(|_| self.stack_dec())?;
block.push(chunk);
self.level -= 1;
return Ok(block);
@ -304,7 +306,7 @@ impl Parser {
break;
}
Some(_) => {
if let Ok(expr) = self.try_reduce_chunk(true) {
if let Ok(expr) = self.try_reduce_chunk(true, false) {
block.push(expr);
}
}
@ -343,7 +345,7 @@ impl Parser {
if self.cur_is(TokenKind::AtSign) {
self.lpop();
let expr = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(Some(Decorator::new(expr)))
@ -472,7 +474,7 @@ impl Parser {
Some(t) if t.is(LSqBr) => {
self.skip();
let index = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
if self.cur_is(RSqBr) {
self.skip();
@ -568,7 +570,7 @@ impl Parser {
Some(semi) if semi.is(Semi) => {
self.lpop();
let len = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
return Ok(ArrayInner::WithLength(elems.remove_pos(0), len));
@ -625,7 +627,7 @@ impl Parser {
match self.peek() {
Some(_) => {
let expr = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(PosArg::new(expr))
@ -814,13 +816,13 @@ impl Parser {
return Err(());
};
let expr = self
.try_reduce_expr(false, in_type_args)
.try_reduce_expr(false, in_type_args, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(PosOrKwArg::Kw(KwArg::new(kw, None, expr)))
} else {
let expr = self
.try_reduce_expr(false, in_type_args)
.try_reduce_expr(false, in_type_args, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(PosOrKwArg::Pos(PosArg::new(expr)))
@ -828,7 +830,7 @@ impl Parser {
}
Some(_) => {
let expr = self
.try_reduce_expr(false, in_type_args)
.try_reduce_expr(false, in_type_args, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(PosOrKwArg::Pos(PosArg::new(expr)))
@ -867,7 +869,7 @@ impl Parser {
None
};*/
let expr = self
.try_reduce_expr(false, in_type_args)
.try_reduce_expr(false, in_type_args, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(KwArg::new(keyword, None, expr))
@ -901,7 +903,9 @@ impl Parser {
while self.cur_is(Newline) {
self.skip();
}
let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let first = self
.try_reduce_chunk(false, false)
.map_err(|_| self.stack_dec())?;
let first = if let Some(fst) = option_enum_unwrap!(first, Expr::Def) {
fst
} else {
@ -924,7 +928,9 @@ impl Parser {
self.skip();
}
Some(_) => {
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let def = self
.try_reduce_chunk(false, false)
.map_err(|_| self.stack_dec())?;
match def {
Expr::Def(def) => {
defs.push(def);
@ -968,7 +974,7 @@ impl Parser {
Ok(Lambda::new(sig, op, body, self.counter))
} else {
let expr = self
.try_reduce_expr(true, false)
.try_reduce_expr(true, false, false)
.map_err(|_| self.stack_dec())?;
let block = Block::new(vec![expr]);
self.level -= 1;
@ -977,11 +983,11 @@ impl Parser {
}
/// chunk = normal expr + def
fn try_reduce_chunk(&mut self, winding: bool) -> ParseResult<Expr> {
fn try_reduce_chunk(&mut self, winding: bool, in_brace: bool) -> ParseResult<Expr> {
debug_call_info!(self);
let mut stack = Vec::<ExprOrOp>::new();
stack.push(ExprOrOp::Expr(
self.try_reduce_bin_lhs(false)
self.try_reduce_bin_lhs(false, in_brace)
.map_err(|_| self.stack_dec())?,
));
loop {
@ -1016,14 +1022,19 @@ impl Parser {
self.counter,
))));
}
// type ascription
Some(op)
if (op.is(Colon) && !self.nth_is(1, Newline))
|| (op.is(SubtypeOf) || op.is(SupertypeOf)) =>
{
// "a": 1 (key-value pair)
if in_brace {
break;
}
let op = self.lpop();
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
let t_spec = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
let t_spec = self
.convert_rhs_to_type_spec(t_spec)
@ -1053,7 +1064,7 @@ impl Parser {
}
stack.push(ExprOrOp::Op(self.lpop()));
stack.push(ExprOrOp::Expr(
self.try_reduce_bin_lhs(false)
self.try_reduce_bin_lhs(false, in_brace)
.map_err(|_| self.stack_dec())?,
));
}
@ -1225,11 +1236,17 @@ impl Parser {
/// chunk = expr + def
/// winding: true => parse paren-less tuple
fn try_reduce_expr(&mut self, winding: bool, in_type_args: bool) -> ParseResult<Expr> {
/// in_brace: true => (1: 1) will not be a syntax error (key-value pair)
fn try_reduce_expr(
&mut self,
winding: bool,
in_type_args: bool,
in_brace: bool,
) -> ParseResult<Expr> {
debug_call_info!(self);
let mut stack = Vec::<ExprOrOp>::new();
stack.push(ExprOrOp::Expr(
self.try_reduce_bin_lhs(in_type_args)
self.try_reduce_bin_lhs(in_type_args, in_brace)
.map_err(|_| self.stack_dec())?,
));
loop {
@ -1249,14 +1266,19 @@ impl Parser {
self.counter,
))));
}
// type ascription
Some(op)
if (op.is(Colon) && !self.nth_is(1, Newline))
|| (op.is(SubtypeOf) || op.is(SupertypeOf)) =>
{
// "a": 1 (key-value pair)
if in_brace {
break;
}
let op = self.lpop();
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
let t_spec = self
.try_reduce_expr(false, in_type_args)
.try_reduce_expr(false, in_type_args, in_brace)
.map_err(|_| self.stack_dec())?;
let t_spec = self
.convert_rhs_to_type_spec(t_spec)
@ -1286,7 +1308,7 @@ impl Parser {
}
stack.push(ExprOrOp::Op(self.lpop()));
stack.push(ExprOrOp::Expr(
self.try_reduce_bin_lhs(in_type_args)
self.try_reduce_bin_lhs(in_type_args, in_brace)
.map_err(|_| self.stack_dec())?,
));
}
@ -1383,7 +1405,7 @@ impl Parser {
/// "LHS" is the smallest unit that can be the left-hand side of an BinOp.
/// e.g. Call, Name, UnaryOp, Lambda
fn try_reduce_bin_lhs(&mut self, in_type_args: bool) -> ParseResult<Expr> {
fn try_reduce_bin_lhs(&mut self, in_type_args: bool, in_brace: bool) -> ParseResult<Expr> {
debug_call_info!(self);
match self.peek() {
Some(t) if t.category_is(TC::Literal) => {
@ -1394,7 +1416,7 @@ impl Parser {
}
Some(t) if t.is(AtSign) => {
let decos = self.opt_reduce_decorators()?;
let expr = self.try_reduce_chunk(false)?;
let expr = self.try_reduce_chunk(false, in_brace)?;
let mut def = if let Some(def) = option_enum_unwrap!(expr, Expr::Def) {
def
} else {
@ -1447,7 +1469,7 @@ impl Parser {
return Ok(Expr::Tuple(unit));
}
let mut expr = self
.try_reduce_expr(true, false)
.try_reduce_expr(true, false, false)
.map_err(|_| self.stack_dec())?;
let rparen = self.lpop();
if let Expr::Tuple(Tuple::Normal(tup)) = &mut expr {
@ -1533,7 +1555,7 @@ impl Parser {
debug_call_info!(self);
let op = self.lpop();
let expr = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(UnaryOp::new(op, expr))
@ -1620,6 +1642,9 @@ impl Parser {
return Ok(BraceContainer::Record(Record::Normal(rec)));
}
}
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
if first.is(Colon) {
@ -1627,16 +1652,20 @@ impl Parser {
if let Some(t) = self.peek() {
if t.is(RBrace) {
let r_brace = self.lpop();
let arg = Args::empty();
let dict = NormalDict::new(l_brace, r_brace, arg);
let dict = NormalDict::new(l_brace, r_brace, vec![]);
return Ok(BraceContainer::Dict(Dict::Normal(dict)));
}
}
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
}
let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let first = self
.try_reduce_chunk(false, true)
.map_err(|_| self.stack_dec())?;
match first {
Expr::Def(def) => {
let record = self
@ -1645,8 +1674,6 @@ impl Parser {
self.level -= 1;
Ok(BraceContainer::Record(Record::Normal(record)))
}
// Dict
Expr::TypeAsc(_) => todo!(),
// TODO: {X; Y} will conflict with Set
Expr::Accessor(acc)
if self.cur_is(Semi)
@ -1659,6 +1686,14 @@ impl Parser {
self.level -= 1;
Ok(BraceContainer::Record(Record::Shortened(record)))
}
// Dict
other if self.cur_is(Colon) => {
let dict = self
.try_reduce_normal_dict(l_brace, other)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(BraceContainer::Dict(Dict::Normal(dict)))
}
other => {
let set = self
.try_reduce_set(l_brace, other)
@ -1704,7 +1739,9 @@ impl Parser {
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
}
Some(_) => {
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let def = self
.try_reduce_chunk(false, false)
.map_err(|_| self.stack_dec())?;
let def = if let Some(def) = option_enum_unwrap!(def, Expr::Def) {
def
} else {
@ -1791,8 +1828,59 @@ impl Parser {
}
}
fn _try_reduce_dict() -> ParseResult<Dict> {
todo!()
fn try_reduce_normal_dict(
&mut self,
l_brace: Token,
first_key: Expr,
) -> ParseResult<NormalDict> {
debug_call_info!(self);
assert!(self.cur_is(Colon));
self.skip();
let value = self
.try_reduce_chunk(false, false)
.map_err(|_| self.stack_dec())?;
let mut kvs = vec![KeyValue::new(first_key, value)];
loop {
match self.peek() {
Some(t) if t.is(Comma) => {
self.skip();
if self.cur_is(Comma) {
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
} else if self.cur_is(RBrace) {
let dict = NormalDict::new(l_brace, self.lpop(), kvs);
self.level -= 1;
return Ok(dict);
}
let key = self
.try_reduce_expr(false, false, true)
.map_err(|_| self.stack_dec())?;
if self.cur_is(Colon) {
self.skip();
let value = self
.try_reduce_chunk(false, false)
.map_err(|_| self.stack_dec())?;
kvs.push(KeyValue::new(key, value));
} else {
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
}
Some(t) if t.is(RBrace) => {
let dict = NormalDict::new(l_brace, self.lpop(), kvs);
self.level -= 1;
return Ok(dict);
}
_ => {
break;
}
}
}
Err(())
}
fn try_reduce_set(&mut self, l_brace: Token, first_elem: Expr) -> ParseResult<Set> {
@ -1800,7 +1888,7 @@ impl Parser {
if self.cur_is(Semi) {
self.skip();
let len = self
.try_reduce_expr(false, false)
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
let r_brace = self.lpop();
return Ok(Set::WithLength(SetWithLength::new(