Update parser

This commit is contained in:
Shunsuke Shibayama 2022-09-02 11:45:47 +09:00
parent 6d09b8a4df
commit fc5ad07660
12 changed files with 242 additions and 113 deletions

View file

@ -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]
fn payload(self) -> Vec<$Inner> {
self.0
@ -232,7 +232,7 @@ macro_rules! impl_stream_for_wrapper {
#[macro_export]
macro_rules! impl_stream {
($Strc: ident, $Inner: ident, $field: ident) => {
impl erg_common::traits::Stream<$Inner> for $Strc {
impl $crate::traits::Stream<$Inner> for $Strc {
#[inline]
fn payload(self) -> Vec<$Inner> {
self.$field

View file

@ -701,6 +701,9 @@ impl CodeGenerator {
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) {
if body.is_type() {
return self.emit_mono_type_def(sig, body);

View file

@ -264,7 +264,7 @@ impl Evaluator {
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![];
for attr in record.attrs.iter() {
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {

View file

@ -217,7 +217,7 @@ impl ASTLowerer {
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!());
let mut hir_record =
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());

View file

@ -179,6 +179,10 @@ impl Args {
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 {
self.kw_args.is_empty()
}
@ -306,12 +310,13 @@ impl Public {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Attribute {
pub obj: Box<Expr>,
pub vis: Token,
pub name: Local,
}
impl NestedDisplay for Attribute {
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 Attribute {
pub fn new(obj: Expr, name: Local) -> Self {
pub fn new(obj: Expr, vis: Token, name: Local) -> Self {
Self {
obj: Box::new(obj),
vis,
name,
}
}
@ -398,8 +404,8 @@ impl Accessor {
Self::Public(Public::new(dot, symbol))
}
pub fn attr(obj: Expr, name: Local) -> Self {
Self::Attr(Attribute::new(obj, name))
pub fn attr(obj: Expr, vis: Token, name: Local) -> Self {
Self::Attr(Attribute::new(obj, vis, name))
}
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
@ -679,13 +685,13 @@ impl RecordAttrs {
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Record {
pub struct NormalRecord {
pub l_brace: Token,
pub r_brace: Token,
pub attrs: RecordAttrs,
}
impl NestedDisplay for Record {
impl NestedDisplay for NormalRecord {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{{")?;
self.attrs.fmt_nest(f, level + 1)?;
@ -693,10 +699,10 @@ impl NestedDisplay for Record {
}
}
impl_display_from_nested!(Record);
impl_locational!(Record, l_brace, r_brace);
impl_display_from_nested!(NormalRecord);
impl_locational!(NormalRecord, l_brace, r_brace);
impl Record {
impl NormalRecord {
pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
Self {
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)]
pub struct NormalSet {
l_brace: Token,
@ -1649,6 +1663,14 @@ impl Decorator {
pub const fn new(expr: Expr) -> Self {
Self(expr)
}
pub fn expr(&self) -> &Expr {
&self.0
}
pub fn into_expr(self) -> Expr {
self.0
}
}
/// symbol as a left value
@ -2142,10 +2164,13 @@ pub enum ParamPattern {
Array(ParamArrayPattern),
Tuple(ParamTuplePattern),
Record(ParamRecordPattern),
Ref(VarName),
RefMut(VarName),
VarArgs(VarName),
}
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple Record);
impl_locational_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, Ref, RefMut, VarArgs);
impl ParamPattern {
pub const fn inspect(&self) -> Option<&Str> {
@ -2646,7 +2671,7 @@ pub enum Expr {
Tuple(Tuple),
Dict(Dict),
Set(Set),
Record(Record),
Record(NormalRecord),
BinOp(BinOp),
UnaryOp(UnaryOp),
Call(Call),

View file

@ -244,7 +244,12 @@ impl Desugarer {
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
}
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)));

View file

@ -64,7 +64,7 @@ pub enum ArrayInner {
pub enum BraceContainer {
Set(Set),
Dict(Dict),
Record(Record),
Record(NormalRecord),
}
/// Perform recursive descent parsing.
@ -372,6 +372,11 @@ impl Parser {
let mut decs = set![];
while let Some(deco) = self.opt_reduce_decorator().map_err(|_| self.stack_dec())? {
decs.insert(deco);
if self.cur_is(Newline) {
self.skip();
} else {
todo!()
}
}
self.level -= 1;
Ok(decs)
@ -403,17 +408,44 @@ impl Parser {
loop {
match self.peek() {
Some(t) if t.is(Dot) => {
self.skip();
let vis = self.lpop();
let token = self.lpop();
match token.kind {
Symbol => {
let attr = Local::new(token);
acc = Accessor::attr(Expr::Accessor(acc), attr);
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
}
NatLit => {
let attr = Literal::from(token);
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.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
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
debug_call_info!(self);
@ -595,14 +594,15 @@ impl Parser {
if t.category_is(TC::Literal)
|| t.is(Symbol)
|| t.category_is(TC::UnaryOp)
|| t.is(Dot)
|| t.category_is(TC::Caret)
|| t.is(LParen)
|| t.is(LSqBr)
|| t.is(LBrace) =>
{
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,
}
}
@ -828,7 +828,7 @@ impl Parser {
} else {
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 mut defs = vec![first];
loop {
@ -839,7 +839,7 @@ impl Parser {
self.skip();
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!());
defs.push(def);
}
@ -945,26 +945,7 @@ impl Parser {
));
}
Some(t) if t.is(DblColon) => {
let dbl_colon = 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();
let vis = self.lpop();
match self.lpop() {
symbol if symbol.is(Symbol) => {
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
@ -983,14 +964,54 @@ impl Parser {
let call = Call::new(obj, Some(symbol), args);
stack.push(ExprOrOp::Expr(Expr::Call(call)));
} 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)));
}
}
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, 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())?;
return Ok(Expr::MethodDefs(defs));
}
@ -1113,7 +1134,7 @@ impl Parser {
));
}
Some(t) if t.is(Dot) => {
self.lpop();
let vis = self.lpop();
match self.lpop() {
symbol if symbol.is(Symbol) => {
let obj = if let Some(ExprOrOp::Expr(expr)) = stack.pop() {
@ -1132,7 +1153,7 @@ impl Parser {
let call = Call::new(obj, Some(symbol), args);
stack.push(ExprOrOp::Expr(Expr::Call(call)));
} 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)));
}
}
@ -1208,14 +1229,29 @@ impl Parser {
}
Some(t) if t.is(AtSign) => {
let decos = self.opt_reduce_decorators()?;
let expr = self.try_reduce_expr(false)?;
let def = option_enum_unwrap!(expr, Expr::Def).unwrap_or_else(|| todo!());
let mut subr_sig =
option_enum_unwrap!(def.sig, Signature::Subr).unwrap_or_else(|| todo!());
subr_sig.decorators = decos;
let expr = Expr::Def(Def::new(Signature::Subr(subr_sig), def.body));
let expr = self.try_reduce_chunk(false)?;
let mut def = option_enum_unwrap!(expr, Expr::Def).unwrap_or_else(|| todo!());
match def.sig {
Signature::Subr(mut subr) => {
subr.decorators = decos;
let expr = Expr::Def(Def::new(Signature::Subr(subr), def.body));
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) => {
let call_or_acc = self
.try_reduce_call_or_acc()
@ -1370,7 +1406,7 @@ impl Parser {
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 {
Expr::Def(def) => {
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);
let mut attrs = vec![first];
loop {
@ -1403,12 +1439,12 @@ impl Parser {
let r_brace = self.lpop();
self.level -= 1;
let attrs = RecordAttrs::from(attrs);
return Ok(Record::new(l_brace, r_brace, attrs));
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
} else {
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!());
attrs.push(def);
}
@ -1416,7 +1452,7 @@ impl Parser {
let r_brace = self.lpop();
self.level -= 1;
let attrs = RecordAttrs::from(attrs);
return Ok(Record::new(l_brace, r_brace, attrs));
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
}
_ => todo!(),
}
@ -1558,7 +1594,10 @@ impl Parser {
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);
todo!()
}
@ -1721,6 +1760,32 @@ impl Parser {
self.level -= 1;
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
}
}
@ -1744,7 +1809,7 @@ impl Parser {
fn convert_record_to_param_record_pat(
&mut self,
_record: Record,
_record: NormalRecord,
) -> ParseResult<ParamRecordPattern> {
debug_call_info!(self);
todo!()
@ -1855,7 +1920,10 @@ impl Parser {
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);
todo!()
}

View file

@ -20,7 +20,21 @@ 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.
## Inheritable

View file

@ -17,7 +17,21 @@ X = ...
X = deco(X)
```
Ergでは変数の再代入が出来ないので、上のようなコードは通らず、デコレータが必要なのです。
Ergでは変数の再代入が出来ないので、上のようなコードは通りません。
単なる変数の場合は`X = deco(...)`と同じなのですが、インスタントブロックやサブルーチンの場合はそうすることができないので、デコレータが必要になってきます。
```erg
@deco
f x =
y = ...
x + y
# コードが横長になるのを防ぐこともできる
@LongNameDeco1
@LongNameDeco2
C = Class ...
```
以下に、頻出の組み込みデコレータを紹介します。
## Inheritable

View file

@ -1,17 +1,17 @@
@Inheritable
Point2D = Class {x = Int; y = Int}
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
Point3D = Inherit Point2D, Additional: {z = Int}
Point3D = Inherit Point2D, Additional := {z = Int}
Point3D.
@Override
new x, y, z = Self::__new__ {x; y; z}
new x, y, z = Self::__new__ {x = x; y = y; z = z}
@Override
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}
UnpackPoint2D::{x; y} = p
UnpackPoint2D::{x = x; y = x} = p

View file

@ -1,20 +1,20 @@
LitExpr = Class {.i = Int}, Impl: Show
LitExpr = Class {.i = Int}, Impl := Show
LitExpr.
new i = Self::__new__ {.i;}
show &self = "{self.i}"
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
AddExpr.
new lhs, rhs = Self::__new__ {.lhs; .rhs}
show &self = "{self.lhs} + {self.rhs}"
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
SubExpr.
new lhs, rhs = Self::__new__ {.lhs; .rhs}
show &self = "{self.lhs} - {self.rhs}"
PosExpr = Class {.expr = Expr}, Impl: Show
PosExpr = Class {.expr = Expr}, Impl := Show
PosExpr.
new expr = Self::__new__ {.expr;}
show &self = "+{self.expr}"
NegExpr = Class {.expr = Expr}, Impl: Show
NegExpr = Class {.expr = Expr}, Impl := Show
NegExpr.
new expr = Self::__new__ {.expr;}
show &self = "-{self.expr}"

View file

@ -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)}
List: (Type, Nat) -> Type
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.
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
a = cons(nil(Int), 1) |> cons 2 |> cons 3
match a:
Cons(_, _).{head=h1; rest=Cons(_, _).{head=h2; rest}} ->
Cons(_, _)::{head=h1; rest=Cons(_, _)::{head=h2; rest}} ->
assert h1 == 3
assert h2 == 2
assert rest == Cons.{head = 1; rest = nil(Int)}
assert rest == Cons::{head = 1; rest = nil(Int)}
_ ->
pass