mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +00:00
Update parser
This commit is contained in:
parent
6d09b8a4df
commit
fc5ad07660
12 changed files with 242 additions and 113 deletions
|
@ -212,7 +212,7 @@ macro_rules! impl_stream_for_wrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl erg_common::traits::Stream<$Inner> for $Strc {
|
impl $crate::traits::Stream<$Inner> for $Strc {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn payload(self) -> Vec<$Inner> {
|
fn payload(self) -> Vec<$Inner> {
|
||||||
self.0
|
self.0
|
||||||
|
@ -232,7 +232,7 @@ macro_rules! impl_stream_for_wrapper {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_stream {
|
macro_rules! impl_stream {
|
||||||
($Strc: ident, $Inner: ident, $field: ident) => {
|
($Strc: ident, $Inner: ident, $field: ident) => {
|
||||||
impl erg_common::traits::Stream<$Inner> for $Strc {
|
impl $crate::traits::Stream<$Inner> for $Strc {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn payload(self) -> Vec<$Inner> {
|
fn payload(self) -> Vec<$Inner> {
|
||||||
self.$field
|
self.$field
|
||||||
|
|
|
@ -701,6 +701,9 @@ impl CodeGenerator {
|
||||||
self.emit_store_instr(sig.ident, Name);
|
self.emit_store_instr(sig.ident, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
||||||
|
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
||||||
|
|
||||||
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
|
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
|
||||||
if body.is_type() {
|
if body.is_type() {
|
||||||
return self.emit_mono_type_def(sig, body);
|
return self.emit_mono_type_def(sig, body);
|
||||||
|
|
|
@ -264,7 +264,7 @@ impl Evaluator {
|
||||||
Some(ValueObj::Array(RcArray::from(elems)))
|
Some(ValueObj::Array(RcArray::from(elems)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_record(&self, record: &Record, ctx: &Context) -> Option<ValueObj> {
|
fn eval_const_record(&self, record: &NormalRecord, ctx: &Context) -> Option<ValueObj> {
|
||||||
let mut attrs = vec![];
|
let mut attrs = vec![];
|
||||||
for attr in record.attrs.iter() {
|
for attr in record.attrs.iter() {
|
||||||
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
|
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
|
||||||
|
|
|
@ -217,7 +217,7 @@ impl ASTLowerer {
|
||||||
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
|
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
|
fn lower_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
|
||||||
log!(info "entered {}({record})", fn_name!());
|
log!(info "entered {}({record})", fn_name!());
|
||||||
let mut hir_record =
|
let mut hir_record =
|
||||||
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
|
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
|
||||||
|
|
|
@ -179,6 +179,10 @@ impl Args {
|
||||||
self.pos_args.is_empty() && self.kw_args.is_empty()
|
self.pos_args.is_empty() && self.kw_args.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.pos_args.len() + self.kw_args.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn kw_is_empty(&self) -> bool {
|
pub fn kw_is_empty(&self) -> bool {
|
||||||
self.kw_args.is_empty()
|
self.kw_args.is_empty()
|
||||||
}
|
}
|
||||||
|
@ -306,12 +310,13 @@ impl Public {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Attribute {
|
pub struct Attribute {
|
||||||
pub obj: Box<Expr>,
|
pub obj: Box<Expr>,
|
||||||
|
pub vis: Token,
|
||||||
pub name: Local,
|
pub name: Local,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for Attribute {
|
impl NestedDisplay for Attribute {
|
||||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
||||||
write!(f, "({}).{}", self.obj, self.name)
|
write!(f, "({}){}{}", self.obj, self.vis.inspect(), self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,9 +324,10 @@ impl_display_from_nested!(Attribute);
|
||||||
impl_locational!(Attribute, obj, name);
|
impl_locational!(Attribute, obj, name);
|
||||||
|
|
||||||
impl Attribute {
|
impl Attribute {
|
||||||
pub fn new(obj: Expr, name: Local) -> Self {
|
pub fn new(obj: Expr, vis: Token, name: Local) -> Self {
|
||||||
Self {
|
Self {
|
||||||
obj: Box::new(obj),
|
obj: Box::new(obj),
|
||||||
|
vis,
|
||||||
name,
|
name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,8 +404,8 @@ impl Accessor {
|
||||||
Self::Public(Public::new(dot, symbol))
|
Self::Public(Public::new(dot, symbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attr(obj: Expr, name: Local) -> Self {
|
pub fn attr(obj: Expr, vis: Token, name: Local) -> Self {
|
||||||
Self::Attr(Attribute::new(obj, name))
|
Self::Attr(Attribute::new(obj, vis, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
|
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
|
||||||
|
@ -679,13 +685,13 @@ impl RecordAttrs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Record {
|
pub struct NormalRecord {
|
||||||
pub l_brace: Token,
|
pub l_brace: Token,
|
||||||
pub r_brace: Token,
|
pub r_brace: Token,
|
||||||
pub attrs: RecordAttrs,
|
pub attrs: RecordAttrs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for Record {
|
impl NestedDisplay for NormalRecord {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||||
writeln!(f, "{{")?;
|
writeln!(f, "{{")?;
|
||||||
self.attrs.fmt_nest(f, level + 1)?;
|
self.attrs.fmt_nest(f, level + 1)?;
|
||||||
|
@ -693,10 +699,10 @@ impl NestedDisplay for Record {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_display_from_nested!(Record);
|
impl_display_from_nested!(NormalRecord);
|
||||||
impl_locational!(Record, l_brace, r_brace);
|
impl_locational!(NormalRecord, l_brace, r_brace);
|
||||||
|
|
||||||
impl Record {
|
impl NormalRecord {
|
||||||
pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
|
pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
|
||||||
Self {
|
Self {
|
||||||
l_brace,
|
l_brace,
|
||||||
|
@ -706,6 +712,14 @@ impl Record {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z})
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SimpleRecord {
|
||||||
|
pub l_brace: Token,
|
||||||
|
pub r_brace: Token,
|
||||||
|
idents: Vec<Identifier>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct NormalSet {
|
pub struct NormalSet {
|
||||||
l_brace: Token,
|
l_brace: Token,
|
||||||
|
@ -1649,6 +1663,14 @@ impl Decorator {
|
||||||
pub const fn new(expr: Expr) -> Self {
|
pub const fn new(expr: Expr) -> Self {
|
||||||
Self(expr)
|
Self(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr(&self) -> &Expr {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_expr(self) -> Expr {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// symbol as a left value
|
/// symbol as a left value
|
||||||
|
@ -2142,10 +2164,13 @@ pub enum ParamPattern {
|
||||||
Array(ParamArrayPattern),
|
Array(ParamArrayPattern),
|
||||||
Tuple(ParamTuplePattern),
|
Tuple(ParamTuplePattern),
|
||||||
Record(ParamRecordPattern),
|
Record(ParamRecordPattern),
|
||||||
|
Ref(VarName),
|
||||||
|
RefMut(VarName),
|
||||||
|
VarArgs(VarName),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple Record);
|
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
|
||||||
impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record);
|
impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
|
||||||
|
|
||||||
impl ParamPattern {
|
impl ParamPattern {
|
||||||
pub const fn inspect(&self) -> Option<&Str> {
|
pub const fn inspect(&self) -> Option<&Str> {
|
||||||
|
@ -2646,7 +2671,7 @@ pub enum Expr {
|
||||||
Tuple(Tuple),
|
Tuple(Tuple),
|
||||||
Dict(Dict),
|
Dict(Dict),
|
||||||
Set(Set),
|
Set(Set),
|
||||||
Record(Record),
|
Record(NormalRecord),
|
||||||
BinOp(BinOp),
|
BinOp(BinOp),
|
||||||
UnaryOp(UnaryOp),
|
UnaryOp(UnaryOp),
|
||||||
Call(Call),
|
Call(Call),
|
||||||
|
|
|
@ -244,7 +244,12 @@ impl Desugarer {
|
||||||
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
|
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
|
||||||
}
|
}
|
||||||
BufIndex::Record(attr) => {
|
BufIndex::Record(attr) => {
|
||||||
Accessor::attr(obj, Local::dummy_with_line(attr, sig.ln_begin().unwrap()))
|
// TODO: visibility
|
||||||
|
Accessor::attr(
|
||||||
|
obj,
|
||||||
|
Token::from_str(TokenKind::Dot, "."),
|
||||||
|
Local::dummy_with_line(attr, sig.ln_begin().unwrap()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let id = DefId(get_hash(&(&acc, buf_name)));
|
let id = DefId(get_hash(&(&acc, buf_name)));
|
||||||
|
|
|
@ -64,7 +64,7 @@ pub enum ArrayInner {
|
||||||
pub enum BraceContainer {
|
pub enum BraceContainer {
|
||||||
Set(Set),
|
Set(Set),
|
||||||
Dict(Dict),
|
Dict(Dict),
|
||||||
Record(Record),
|
Record(NormalRecord),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform recursive descent parsing.
|
/// Perform recursive descent parsing.
|
||||||
|
@ -372,6 +372,11 @@ impl Parser {
|
||||||
let mut decs = set![];
|
let mut decs = set![];
|
||||||
while let Some(deco) = self.opt_reduce_decorator().map_err(|_| self.stack_dec())? {
|
while let Some(deco) = self.opt_reduce_decorator().map_err(|_| self.stack_dec())? {
|
||||||
decs.insert(deco);
|
decs.insert(deco);
|
||||||
|
if self.cur_is(Newline) {
|
||||||
|
self.skip();
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
Ok(decs)
|
Ok(decs)
|
||||||
|
@ -403,17 +408,44 @@ impl Parser {
|
||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(t) if t.is(Dot) => {
|
Some(t) if t.is(Dot) => {
|
||||||
self.skip();
|
let vis = self.lpop();
|
||||||
let token = self.lpop();
|
let token = self.lpop();
|
||||||
match token.kind {
|
match token.kind {
|
||||||
Symbol => {
|
Symbol => {
|
||||||
let attr = Local::new(token);
|
let attr = Local::new(token);
|
||||||
acc = Accessor::attr(Expr::Accessor(acc), attr);
|
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
|
||||||
}
|
}
|
||||||
NatLit => {
|
NatLit => {
|
||||||
let attr = Literal::from(token);
|
let attr = Literal::from(token);
|
||||||
acc = Accessor::tuple_attr(Expr::Accessor(acc), attr);
|
acc = Accessor::tuple_attr(Expr::Accessor(acc), attr);
|
||||||
}
|
}
|
||||||
|
Newline => {
|
||||||
|
self.restore(token);
|
||||||
|
self.restore(vis);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.restore(token);
|
||||||
|
self.level -= 1;
|
||||||
|
let err = self.skip_and_throw_syntax_err(caused_by!());
|
||||||
|
self.errs.push(err);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(t) if t.is(DblColon) => {
|
||||||
|
let vis = self.lpop();
|
||||||
|
let token = self.lpop();
|
||||||
|
match token.kind {
|
||||||
|
Symbol => {
|
||||||
|
let attr = Local::new(token);
|
||||||
|
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
|
||||||
|
}
|
||||||
|
Newline => {
|
||||||
|
self.restore(token);
|
||||||
|
self.restore(vis);
|
||||||
|
break;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.restore(token);
|
self.restore(token);
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
|
@ -479,39 +511,6 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _validate_const_pos_arg(&mut self, arg: PosArg) -> ParseResult<ConstPosArg> {
|
|
||||||
let expr = self.validate_const_expr(arg.expr)?;
|
|
||||||
Ok(ConstPosArg::new(expr))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _validate_const_kw_arg(&mut self, arg: KwArg) -> ParseResult<ConstKwArg> {
|
|
||||||
let expr = self.validate_const_expr(arg.expr)?;
|
|
||||||
Ok(ConstKwArg::new(arg.keyword, expr))
|
|
||||||
}
|
|
||||||
|
|
||||||
// exprが定数式か確認する
|
|
||||||
fn _validate_const_args(&mut self, args: Args) -> ParseResult<ConstArgs> {
|
|
||||||
let (pos, kw, paren) = args.deconstruct();
|
|
||||||
let mut const_args = ConstArgs::new(vec![], vec![], paren);
|
|
||||||
for arg in pos.into_iter() {
|
|
||||||
match self._validate_const_pos_arg(arg) {
|
|
||||||
Ok(arg) => {
|
|
||||||
const_args.push_pos(arg);
|
|
||||||
}
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for arg in kw.into_iter() {
|
|
||||||
match self._validate_const_kw_arg(arg) {
|
|
||||||
Ok(arg) => {
|
|
||||||
const_args.push_kw(arg);
|
|
||||||
}
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(const_args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For parsing elements of arrays and tuples
|
/// For parsing elements of arrays and tuples
|
||||||
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
|
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
|
@ -595,14 +594,15 @@ impl Parser {
|
||||||
if t.category_is(TC::Literal)
|
if t.category_is(TC::Literal)
|
||||||
|| t.is(Symbol)
|
|| t.is(Symbol)
|
||||||
|| t.category_is(TC::UnaryOp)
|
|| t.category_is(TC::UnaryOp)
|
||||||
|| t.is(Dot)
|
|
||||||
|| t.category_is(TC::Caret)
|
|
||||||
|| t.is(LParen)
|
|| t.is(LParen)
|
||||||
|| t.is(LSqBr)
|
|| t.is(LSqBr)
|
||||||
|| t.is(LBrace) =>
|
|| t.is(LBrace) =>
|
||||||
{
|
{
|
||||||
Some(self.try_reduce_args())
|
Some(self.try_reduce_args())
|
||||||
}
|
}
|
||||||
|
Some(t) if (t.is(Dot) || t.is(DblColon)) && !self.nth_is(1, Newline) => {
|
||||||
|
Some(self.try_reduce_args())
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -828,7 +828,7 @@ impl Parser {
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
let first = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
|
||||||
let first = option_enum_unwrap!(first, Expr::Def).unwrap_or_else(|| todo!());
|
let first = option_enum_unwrap!(first, Expr::Def).unwrap_or_else(|| todo!());
|
||||||
let mut defs = vec![first];
|
let mut defs = vec![first];
|
||||||
loop {
|
loop {
|
||||||
|
@ -839,7 +839,7 @@ impl Parser {
|
||||||
self.skip();
|
self.skip();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let def = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
|
||||||
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!());
|
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!());
|
||||||
defs.push(def);
|
defs.push(def);
|
||||||
}
|
}
|
||||||
|
@ -945,26 +945,7 @@ impl Parser {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Some(t) if t.is(DblColon) => {
|
Some(t) if t.is(DblColon) => {
|
||||||
let dbl_colon = self.lpop();
|
let vis = self.lpop();
|
||||||
match self.lpop() {
|
|
||||||
line_break if line_break.is(Newline) => {
|
|
||||||
let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
|
||||||
let defs = self
|
|
||||||
.try_reduce_method_defs(maybe_class, dbl_colon)
|
|
||||||
.map_err(|_| self.stack_dec())?;
|
|
||||||
return Ok(Expr::MethodDefs(defs));
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
self.restore(other);
|
|
||||||
self.level -= 1;
|
|
||||||
let err = self.skip_and_throw_syntax_err(caused_by!());
|
|
||||||
self.errs.push(err);
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(t) if t.is(Dot) => {
|
|
||||||
let dot = self.lpop();
|
|
||||||
match self.lpop() {
|
match self.lpop() {
|
||||||
symbol if symbol.is(Symbol) => {
|
symbol if symbol.is(Symbol) => {
|
||||||
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
|
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
|
||||||
|
@ -983,14 +964,54 @@ impl Parser {
|
||||||
let call = Call::new(obj, Some(symbol), args);
|
let call = Call::new(obj, Some(symbol), args);
|
||||||
stack.push(ExprOrOp::Expr(Expr::Call(call)));
|
stack.push(ExprOrOp::Expr(Expr::Call(call)));
|
||||||
} else {
|
} else {
|
||||||
let acc = Accessor::attr(obj, Local::new(symbol));
|
let acc = Accessor::attr(obj, vis, Local::new(symbol));
|
||||||
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
|
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
line_break if line_break.is(Newline) => {
|
line_break if line_break.is(Newline) => {
|
||||||
let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||||
let defs = self
|
let defs = self
|
||||||
.try_reduce_method_defs(maybe_class, dot)
|
.try_reduce_method_defs(maybe_class, vis)
|
||||||
|
.map_err(|_| self.stack_dec())?;
|
||||||
|
return Ok(Expr::MethodDefs(defs));
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
self.restore(other);
|
||||||
|
self.level -= 1;
|
||||||
|
let err = self.skip_and_throw_syntax_err(caused_by!());
|
||||||
|
self.errs.push(err);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(t) if t.is(Dot) => {
|
||||||
|
let vis = self.lpop();
|
||||||
|
match self.lpop() {
|
||||||
|
symbol if symbol.is(Symbol) => {
|
||||||
|
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
|
||||||
|
expr
|
||||||
|
} else {
|
||||||
|
self.level -= 1;
|
||||||
|
let err = self.skip_and_throw_syntax_err(caused_by!());
|
||||||
|
self.errs.push(err);
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
if let Some(args) = self
|
||||||
|
.opt_reduce_args()
|
||||||
|
.transpose()
|
||||||
|
.map_err(|_| self.stack_dec())?
|
||||||
|
{
|
||||||
|
let call = Call::new(obj, Some(symbol), args);
|
||||||
|
stack.push(ExprOrOp::Expr(Expr::Call(call)));
|
||||||
|
} else {
|
||||||
|
let acc = Accessor::attr(obj, vis, Local::new(symbol));
|
||||||
|
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line_break if line_break.is(Newline) => {
|
||||||
|
let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||||
|
let defs = self
|
||||||
|
.try_reduce_method_defs(maybe_class, vis)
|
||||||
.map_err(|_| self.stack_dec())?;
|
.map_err(|_| self.stack_dec())?;
|
||||||
return Ok(Expr::MethodDefs(defs));
|
return Ok(Expr::MethodDefs(defs));
|
||||||
}
|
}
|
||||||
|
@ -1113,7 +1134,7 @@ impl Parser {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Dot) => {
|
Some(t) if t.is(Dot) => {
|
||||||
self.lpop();
|
let vis = self.lpop();
|
||||||
match self.lpop() {
|
match self.lpop() {
|
||||||
symbol if symbol.is(Symbol) => {
|
symbol if symbol.is(Symbol) => {
|
||||||
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
|
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
|
||||||
|
@ -1132,7 +1153,7 @@ impl Parser {
|
||||||
let call = Call::new(obj, Some(symbol), args);
|
let call = Call::new(obj, Some(symbol), args);
|
||||||
stack.push(ExprOrOp::Expr(Expr::Call(call)));
|
stack.push(ExprOrOp::Expr(Expr::Call(call)));
|
||||||
} else {
|
} else {
|
||||||
let acc = Accessor::attr(obj, Local::new(symbol));
|
let acc = Accessor::attr(obj, vis, Local::new(symbol));
|
||||||
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
|
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1208,13 +1229,28 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some(t) if t.is(AtSign) => {
|
Some(t) if t.is(AtSign) => {
|
||||||
let decos = self.opt_reduce_decorators()?;
|
let decos = self.opt_reduce_decorators()?;
|
||||||
let expr = self.try_reduce_expr(false)?;
|
let expr = self.try_reduce_chunk(false)?;
|
||||||
let def = option_enum_unwrap!(expr, Expr::Def).unwrap_or_else(|| todo!());
|
let mut def = option_enum_unwrap!(expr, Expr::Def).unwrap_or_else(|| todo!());
|
||||||
let mut subr_sig =
|
match def.sig {
|
||||||
option_enum_unwrap!(def.sig, Signature::Subr).unwrap_or_else(|| todo!());
|
Signature::Subr(mut subr) => {
|
||||||
subr_sig.decorators = decos;
|
subr.decorators = decos;
|
||||||
let expr = Expr::Def(Def::new(Signature::Subr(subr_sig), def.body));
|
let expr = Expr::Def(Def::new(Signature::Subr(subr), def.body));
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
|
}
|
||||||
|
Signature::Var(var) => {
|
||||||
|
let mut last = def.body.block.pop().unwrap();
|
||||||
|
for deco in decos.into_iter() {
|
||||||
|
last = Expr::Call(Call::new(
|
||||||
|
deco.into_expr(),
|
||||||
|
None,
|
||||||
|
Args::new(vec![PosArg::new(last)], vec![], None),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
def.body.block.push(last);
|
||||||
|
let expr = Expr::Def(Def::new(Signature::Var(var), def.body));
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Symbol) || t.is(Dot) => {
|
Some(t) if t.is(Symbol) || t.is(Dot) => {
|
||||||
let call_or_acc = self
|
let call_or_acc = self
|
||||||
|
@ -1370,7 +1406,7 @@ impl Parser {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let first = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
|
||||||
match first {
|
match first {
|
||||||
Expr::Def(def) => {
|
Expr::Def(def) => {
|
||||||
let record = self
|
let record = self
|
||||||
|
@ -1390,7 +1426,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_reduce_record(&mut self, l_brace: Token, first: Def) -> ParseResult<Record> {
|
fn try_reduce_record(&mut self, l_brace: Token, first: Def) -> ParseResult<NormalRecord> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let mut attrs = vec![first];
|
let mut attrs = vec![first];
|
||||||
loop {
|
loop {
|
||||||
|
@ -1403,12 +1439,12 @@ impl Parser {
|
||||||
let r_brace = self.lpop();
|
let r_brace = self.lpop();
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
let attrs = RecordAttrs::from(attrs);
|
let attrs = RecordAttrs::from(attrs);
|
||||||
return Ok(Record::new(l_brace, r_brace, attrs));
|
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let def = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
|
||||||
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!());
|
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!());
|
||||||
attrs.push(def);
|
attrs.push(def);
|
||||||
}
|
}
|
||||||
|
@ -1416,7 +1452,7 @@ impl Parser {
|
||||||
let r_brace = self.lpop();
|
let r_brace = self.lpop();
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
let attrs = RecordAttrs::from(attrs);
|
let attrs = RecordAttrs::from(attrs);
|
||||||
return Ok(Record::new(l_brace, r_brace, attrs));
|
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
|
@ -1558,7 +1594,10 @@ impl Parser {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_record_to_record_pat(&mut self, _record: Record) -> ParseResult<VarRecordPattern> {
|
fn convert_record_to_record_pat(
|
||||||
|
&mut self,
|
||||||
|
_record: NormalRecord,
|
||||||
|
) -> ParseResult<VarRecordPattern> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -1721,6 +1760,32 @@ impl Parser {
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
Ok(param)
|
Ok(param)
|
||||||
}
|
}
|
||||||
|
Expr::Call(mut call) => match *call.obj {
|
||||||
|
Expr::Accessor(Accessor::Local(local)) => match &local.inspect()[..] {
|
||||||
|
"ref" => {
|
||||||
|
assert_eq!(call.args.len(), 1);
|
||||||
|
let var = call.args.remove_pos(0).expr;
|
||||||
|
let var = option_enum_unwrap!(var, Expr::Accessor:(Accessor::Local:(_)))
|
||||||
|
.unwrap_or_else(|| todo!());
|
||||||
|
let pat = ParamPattern::Ref(VarName::new(var.symbol));
|
||||||
|
let param = ParamSignature::new(pat, None, None);
|
||||||
|
self.level -= 1;
|
||||||
|
Ok(param)
|
||||||
|
}
|
||||||
|
"ref!" => {
|
||||||
|
assert_eq!(call.args.len(), 1);
|
||||||
|
let var = call.args.remove_pos(0).expr;
|
||||||
|
let var = option_enum_unwrap!(var, Expr::Accessor:(Accessor::Local:(_)))
|
||||||
|
.unwrap_or_else(|| todo!());
|
||||||
|
let pat = ParamPattern::RefMut(VarName::new(var.symbol));
|
||||||
|
let param = ParamSignature::new(pat, None, None);
|
||||||
|
self.level -= 1;
|
||||||
|
Ok(param)
|
||||||
|
}
|
||||||
|
other => todo!("{other}"),
|
||||||
|
},
|
||||||
|
other => todo!("{other}"),
|
||||||
|
},
|
||||||
other => todo!("{other}"), // Error
|
other => todo!("{other}"), // Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1744,7 +1809,7 @@ impl Parser {
|
||||||
|
|
||||||
fn convert_record_to_param_record_pat(
|
fn convert_record_to_param_record_pat(
|
||||||
&mut self,
|
&mut self,
|
||||||
_record: Record,
|
_record: NormalRecord,
|
||||||
) -> ParseResult<ParamRecordPattern> {
|
) -> ParseResult<ParamRecordPattern> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -1855,7 +1920,10 @@ impl Parser {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_record_to_param_pat(&mut self, _record: Record) -> ParseResult<ParamRecordPattern> {
|
fn convert_record_to_param_pat(
|
||||||
|
&mut self,
|
||||||
|
_record: NormalRecord,
|
||||||
|
) -> ParseResult<ParamRecordPattern> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,21 @@ X = ...
|
||||||
X = deco(X)
|
X = deco(X)
|
||||||
```
|
```
|
||||||
|
|
||||||
Since Erg does not allow reassignment, the above code will not pass, and a decorator is required.
|
Erg does not allow reassignment of variables, so the above code will not pass.
|
||||||
|
For a simple variable, `X = deco(...)` is the same, but for instant blocks and subroutines, you can't do that, so you need decorators.
|
||||||
|
|
||||||
|
```erg
|
||||||
|
@deco
|
||||||
|
f x = ...
|
||||||
|
y = ...
|
||||||
|
x + y
|
||||||
|
|
||||||
|
# Can also prevent code from going horizontal.
|
||||||
|
@LongNameDeco1
|
||||||
|
@LongNameDeco2
|
||||||
|
C = Class ...
|
||||||
|
```
|
||||||
|
|
||||||
Here are some frequently used built-in decorators.
|
Here are some frequently used built-in decorators.
|
||||||
|
|
||||||
## Inheritable
|
## Inheritable
|
||||||
|
|
|
@ -17,7 +17,21 @@ X = ...
|
||||||
X = deco(X)
|
X = deco(X)
|
||||||
```
|
```
|
||||||
|
|
||||||
Ergでは変数の再代入が出来ないので、上のようなコードは通らず、デコレータが必要なのです。
|
Ergでは変数の再代入が出来ないので、上のようなコードは通りません。
|
||||||
|
単なる変数の場合は`X = deco(...)`と同じなのですが、インスタントブロックやサブルーチンの場合はそうすることができないので、デコレータが必要になってきます。
|
||||||
|
|
||||||
|
```erg
|
||||||
|
@deco
|
||||||
|
f x =
|
||||||
|
y = ...
|
||||||
|
x + y
|
||||||
|
|
||||||
|
# コードが横長になるのを防ぐこともできる
|
||||||
|
@LongNameDeco1
|
||||||
|
@LongNameDeco2
|
||||||
|
C = Class ...
|
||||||
|
```
|
||||||
|
|
||||||
以下に、頻出の組み込みデコレータを紹介します。
|
以下に、頻出の組み込みデコレータを紹介します。
|
||||||
|
|
||||||
## Inheritable
|
## Inheritable
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
@Inheritable
|
@Inheritable
|
||||||
Point2D = Class {x = Int; y = Int}
|
Point2D = Class {x = Int; y = Int}
|
||||||
Point2D.
|
Point2D.
|
||||||
new x, y = Self::__new__ {x; y}
|
new x, y = Self::__new__ {x = x; y = y}
|
||||||
norm ref self = self::x**2 + self::y**2
|
norm ref self = self::x**2 + self::y**2
|
||||||
|
|
||||||
Point3D = Inherit Point2D, Additional: {z = Int}
|
Point3D = Inherit Point2D, Additional := {z = Int}
|
||||||
Point3D.
|
Point3D.
|
||||||
@Override
|
@Override
|
||||||
new x, y, z = Self::__new__ {x; y; z}
|
new x, y, z = Self::__new__ {x = x; y = y; z = z}
|
||||||
@Override
|
@Override
|
||||||
norm ref self = self::x**2 + self::y**2 + self::z**2
|
norm ref self = self::x**2 + self::y**2 + self::z**2
|
||||||
|
|
||||||
UnpackPoint2D = Class {x = Int; y = Int}, Impl: Unpack
|
UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack
|
||||||
|
|
||||||
p = UnpackPoint2D::{x = 1; y = 2}
|
p = UnpackPoint2D::{x = 1; y = 2}
|
||||||
UnpackPoint2D::{x; y} = p
|
UnpackPoint2D::{x = x; y = x} = p
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
LitExpr = Class {.i = Int}, Impl: Show
|
LitExpr = Class {.i = Int}, Impl := Show
|
||||||
LitExpr.
|
LitExpr.
|
||||||
new i = Self::__new__ {.i;}
|
new i = Self::__new__ {.i;}
|
||||||
show &self = "{self.i}"
|
show &self = "{self.i}"
|
||||||
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
|
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
||||||
AddExpr.
|
AddExpr.
|
||||||
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
||||||
show &self = "{self.lhs} + {self.rhs}"
|
show &self = "{self.lhs} + {self.rhs}"
|
||||||
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
|
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
||||||
SubExpr.
|
SubExpr.
|
||||||
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
||||||
show &self = "{self.lhs} - {self.rhs}"
|
show &self = "{self.lhs} - {self.rhs}"
|
||||||
PosExpr = Class {.expr = Expr}, Impl: Show
|
PosExpr = Class {.expr = Expr}, Impl := Show
|
||||||
PosExpr.
|
PosExpr.
|
||||||
new expr = Self::__new__ {.expr;}
|
new expr = Self::__new__ {.expr;}
|
||||||
show &self = "+{self.expr}"
|
show &self = "+{self.expr}"
|
||||||
NegExpr = Class {.expr = Expr}, Impl: Show
|
NegExpr = Class {.expr = Expr}, Impl := Show
|
||||||
NegExpr.
|
NegExpr.
|
||||||
new expr = Self::__new__ {.expr;}
|
new expr = Self::__new__ {.expr;}
|
||||||
show &self = "-{self.expr}"
|
show &self = "-{self.expr}"
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
Nil T = Class Impl: Phantom(T) and Eq
|
Nil T = Class Impl := Phantom(T) and Eq
|
||||||
Cons T, N = Inherit {head = T; rest = List(T, N-1)}
|
Cons T, N = Inherit {head = T; rest = List(T, N-1)}
|
||||||
List: (Type, Nat) -> Type
|
List: (Type, Nat) -> Type
|
||||||
List T, 0 = Class Nil T
|
List T, 0 = Class Nil T
|
||||||
List T, N = Class Cons(T, N), Impl: Eq
|
List T, N = Class Cons(T, N), Impl := Eq
|
||||||
List.
|
List.
|
||||||
nil T = List(T, 0).new Nil(T).new()
|
nil T = List(T, 0).new Nil(T).new()
|
||||||
cons|T, N| rest: List(T, N-1), head: T = List(T, N).new Cons(T, N).{head; rest}
|
cons|T, N| rest: List(T, N-1), head: T = List(T, N).new Cons(T, N)::{head; rest}
|
||||||
{nil, cons} = List
|
{nil, cons} = List
|
||||||
|
|
||||||
a = cons(nil(Int), 1) |> cons 2 |> cons 3
|
a = cons(nil(Int), 1) |> cons 2 |> cons 3
|
||||||
match a:
|
match a:
|
||||||
Cons(_, _).{head=h1; rest=Cons(_, _).{head=h2; rest}} ->
|
Cons(_, _)::{head=h1; rest=Cons(_, _)::{head=h2; rest}} ->
|
||||||
assert h1 == 3
|
assert h1 == 3
|
||||||
assert h2 == 2
|
assert h2 == 2
|
||||||
assert rest == Cons.{head = 1; rest = nil(Int)}
|
assert rest == Cons::{head = 1; rest = nil(Int)}
|
||||||
_ ->
|
_ ->
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue