conlang: Struct, tuple member accesses, member function call syntax
Currently uses UFCS in the interpreter. This may change after type checking?
This commit is contained in:
parent
a033e9f33b
commit
8d8928b8a8
@ -352,6 +352,8 @@ pub enum ExprKind {
|
|||||||
Binary(Binary),
|
Binary(Binary),
|
||||||
/// A [Unary] expression: [`UnaryKind`]\* [`Expr`]
|
/// A [Unary] expression: [`UnaryKind`]\* [`Expr`]
|
||||||
Unary(Unary),
|
Unary(Unary),
|
||||||
|
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
||||||
|
Member(Member),
|
||||||
/// An Array [Index] expression: a[10, 20, 30]
|
/// An Array [Index] expression: a[10, 20, 30]
|
||||||
Index(Index),
|
Index(Index),
|
||||||
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||||
@ -443,7 +445,6 @@ pub enum BinaryKind {
|
|||||||
Mul,
|
Mul,
|
||||||
Div,
|
Div,
|
||||||
Rem,
|
Rem,
|
||||||
Dot,
|
|
||||||
Call,
|
Call,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,6 +466,22 @@ pub enum UnaryKind {
|
|||||||
/// Unused
|
/// Unused
|
||||||
Tilde,
|
Tilde,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Member {
|
||||||
|
pub head: Box<ExprKind>,
|
||||||
|
pub kind: MemberKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of [Member] access
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MemberKind {
|
||||||
|
Call(Identifier, Tuple),
|
||||||
|
Struct(Identifier),
|
||||||
|
Tuple(Literal),
|
||||||
|
}
|
||||||
|
|
||||||
/// A repeated [Index] expression: a[10, 20, 30][40, 50, 60]
|
/// A repeated [Index] expression: a[10, 20, 30][40, 50, 60]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
|
@ -422,6 +422,7 @@ mod display {
|
|||||||
ExprKind::Assign(v) => v.fmt(f),
|
ExprKind::Assign(v) => v.fmt(f),
|
||||||
ExprKind::Binary(v) => v.fmt(f),
|
ExprKind::Binary(v) => v.fmt(f),
|
||||||
ExprKind::Unary(v) => v.fmt(f),
|
ExprKind::Unary(v) => v.fmt(f),
|
||||||
|
ExprKind::Member(v) => v.fmt(f),
|
||||||
ExprKind::Index(v) => v.fmt(f),
|
ExprKind::Index(v) => v.fmt(f),
|
||||||
ExprKind::Structor(v) => v.fmt(f),
|
ExprKind::Structor(v) => v.fmt(f),
|
||||||
ExprKind::Path(v) => v.fmt(f),
|
ExprKind::Path(v) => v.fmt(f),
|
||||||
@ -474,7 +475,6 @@ mod display {
|
|||||||
let Self { kind, parts } = self;
|
let Self { kind, parts } = self;
|
||||||
let (head, tail) = parts.borrow();
|
let (head, tail) = parts.borrow();
|
||||||
match kind {
|
match kind {
|
||||||
BinaryKind::Dot => write!(f, "{head}{kind}{tail}"),
|
|
||||||
BinaryKind::Call => write!(f, "{head}{tail}"),
|
BinaryKind::Call => write!(f, "{head}{tail}"),
|
||||||
_ => write!(f, "{head} {kind} {tail}"),
|
_ => write!(f, "{head} {kind} {tail}"),
|
||||||
}
|
}
|
||||||
@ -505,7 +505,6 @@ mod display {
|
|||||||
BinaryKind::Mul => "*",
|
BinaryKind::Mul => "*",
|
||||||
BinaryKind::Div => "/",
|
BinaryKind::Div => "/",
|
||||||
BinaryKind::Rem => "%",
|
BinaryKind::Rem => "%",
|
||||||
BinaryKind::Dot => ".",
|
|
||||||
BinaryKind::Call => "()",
|
BinaryKind::Call => "()",
|
||||||
}
|
}
|
||||||
.fmt(f)
|
.fmt(f)
|
||||||
@ -532,6 +531,23 @@ mod display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Member {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self { head, kind } = self;
|
||||||
|
write!(f, "{head}.{kind}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for MemberKind {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
MemberKind::Call(name, args) => write!(f, "{name}{args}"),
|
||||||
|
MemberKind::Struct(name) => write!(f, "{name}"),
|
||||||
|
MemberKind::Tuple(name) => write!(f, "{name}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Index {
|
impl Display for Index {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self { head, indices } = self;
|
let Self { head, indices } = self;
|
||||||
@ -735,6 +751,7 @@ mod convert {
|
|||||||
Assign => ExprKind::Assign,
|
Assign => ExprKind::Assign,
|
||||||
Binary => ExprKind::Binary,
|
Binary => ExprKind::Binary,
|
||||||
Unary => ExprKind::Unary,
|
Unary => ExprKind::Unary,
|
||||||
|
Member => ExprKind::Member,
|
||||||
Index => ExprKind::Index,
|
Index => ExprKind::Index,
|
||||||
Path => ExprKind::Path,
|
Path => ExprKind::Path,
|
||||||
Literal => ExprKind::Literal,
|
Literal => ExprKind::Literal,
|
||||||
|
@ -262,6 +262,13 @@ pub trait Fold {
|
|||||||
fn fold_unary_kind(&mut self, kind: UnaryKind) -> UnaryKind {
|
fn fold_unary_kind(&mut self, kind: UnaryKind) -> UnaryKind {
|
||||||
kind
|
kind
|
||||||
}
|
}
|
||||||
|
fn fold_member(&mut self, m: Member) -> Member {
|
||||||
|
let Member { head, kind } = m;
|
||||||
|
Member { head: Box::new(self.fold_expr_kind(*head)), kind: self.fold_member_kind(kind) }
|
||||||
|
}
|
||||||
|
fn fold_member_kind(&mut self, kind: MemberKind) -> MemberKind {
|
||||||
|
or_fold_member_kind(self, kind)
|
||||||
|
}
|
||||||
fn fold_index(&mut self, i: Index) -> Index {
|
fn fold_index(&mut self, i: Index) -> Index {
|
||||||
let Index { head, indices } = i;
|
let Index { head, indices } = i;
|
||||||
Index {
|
Index {
|
||||||
@ -517,6 +524,7 @@ pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> Ex
|
|||||||
ExprKind::Assign(a) => ExprKind::Assign(folder.fold_assign(a)),
|
ExprKind::Assign(a) => ExprKind::Assign(folder.fold_assign(a)),
|
||||||
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),
|
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),
|
||||||
ExprKind::Unary(u) => ExprKind::Unary(folder.fold_unary(u)),
|
ExprKind::Unary(u) => ExprKind::Unary(folder.fold_unary(u)),
|
||||||
|
ExprKind::Member(m) => ExprKind::Member(folder.fold_member(m)),
|
||||||
ExprKind::Index(i) => ExprKind::Index(folder.fold_index(i)),
|
ExprKind::Index(i) => ExprKind::Index(folder.fold_index(i)),
|
||||||
ExprKind::Structor(s) => ExprKind::Structor(folder.fold_structor(s)),
|
ExprKind::Structor(s) => ExprKind::Structor(folder.fold_structor(s)),
|
||||||
ExprKind::Path(p) => ExprKind::Path(folder.fold_path(p)),
|
ExprKind::Path(p) => ExprKind::Path(folder.fold_path(p)),
|
||||||
@ -536,3 +544,12 @@ pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> Ex
|
|||||||
ExprKind::Continue(c) => ExprKind::Continue(folder.fold_continue(c)),
|
ExprKind::Continue(c) => ExprKind::Continue(folder.fold_continue(c)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn or_fold_member_kind<F: Fold + ?Sized>(folder: &mut F, kind: MemberKind) -> MemberKind {
|
||||||
|
match kind {
|
||||||
|
MemberKind::Call(name, args) => {
|
||||||
|
MemberKind::Call(folder.fold_identifier(name), folder.fold_tuple(args))
|
||||||
|
}
|
||||||
|
MemberKind::Struct(name) => MemberKind::Struct(folder.fold_identifier(name)),
|
||||||
|
MemberKind::Tuple(name) => MemberKind::Tuple(folder.fold_literal(name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -223,6 +223,14 @@ pub trait Visit<'a>: Sized {
|
|||||||
self.visit_expr_kind(tail);
|
self.visit_expr_kind(tail);
|
||||||
}
|
}
|
||||||
fn visit_unary_kind(&mut self, _kind: &'a UnaryKind) {}
|
fn visit_unary_kind(&mut self, _kind: &'a UnaryKind) {}
|
||||||
|
fn visit_member(&mut self, m: &'a Member) {
|
||||||
|
let Member { head, kind } = m;
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_member_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_member_kind(&mut self, kind: &'a MemberKind) {
|
||||||
|
or_visit_member_kind(self, kind)
|
||||||
|
}
|
||||||
fn visit_index(&mut self, i: &'a Index) {
|
fn visit_index(&mut self, i: &'a Index) {
|
||||||
let Index { head, indices } = i;
|
let Index { head, indices } = i;
|
||||||
self.visit_expr_kind(head);
|
self.visit_expr_kind(head);
|
||||||
@ -431,6 +439,7 @@ pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
|
|||||||
ExprKind::Assign(a) => visitor.visit_assign(a),
|
ExprKind::Assign(a) => visitor.visit_assign(a),
|
||||||
ExprKind::Binary(b) => visitor.visit_binary(b),
|
ExprKind::Binary(b) => visitor.visit_binary(b),
|
||||||
ExprKind::Unary(u) => visitor.visit_unary(u),
|
ExprKind::Unary(u) => visitor.visit_unary(u),
|
||||||
|
ExprKind::Member(m) => visitor.visit_member(m),
|
||||||
ExprKind::Index(i) => visitor.visit_index(i),
|
ExprKind::Index(i) => visitor.visit_index(i),
|
||||||
ExprKind::Structor(s) => visitor.visit_structor(s),
|
ExprKind::Structor(s) => visitor.visit_structor(s),
|
||||||
ExprKind::Path(p) => visitor.visit_path(p),
|
ExprKind::Path(p) => visitor.visit_path(p),
|
||||||
@ -450,3 +459,13 @@ pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
|
|||||||
ExprKind::Continue(c) => visitor.visit_continue(c),
|
ExprKind::Continue(c) => visitor.visit_continue(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn or_visit_member_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a MemberKind) {
|
||||||
|
match kind {
|
||||||
|
MemberKind::Call(field, args) => {
|
||||||
|
visitor.visit_identifier(field);
|
||||||
|
visitor.visit_tuple(args);
|
||||||
|
}
|
||||||
|
MemberKind::Struct(field) => visitor.visit_identifier(field),
|
||||||
|
MemberKind::Tuple(field) => visitor.visit_literal(field),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -130,6 +130,7 @@ impl Interpret for ExprKind {
|
|||||||
ExprKind::Assign(v) => v.interpret(env),
|
ExprKind::Assign(v) => v.interpret(env),
|
||||||
ExprKind::Binary(v) => v.interpret(env),
|
ExprKind::Binary(v) => v.interpret(env),
|
||||||
ExprKind::Unary(v) => v.interpret(env),
|
ExprKind::Unary(v) => v.interpret(env),
|
||||||
|
ExprKind::Member(v) => v.interpret(env),
|
||||||
ExprKind::Index(v) => v.interpret(env),
|
ExprKind::Index(v) => v.interpret(env),
|
||||||
ExprKind::Structor(v) => v.interpret(env),
|
ExprKind::Structor(v) => v.interpret(env),
|
||||||
ExprKind::Path(v) => v.interpret(env),
|
ExprKind::Path(v) => v.interpret(env),
|
||||||
@ -256,7 +257,6 @@ impl Interpret for Binary {
|
|||||||
BinaryKind::Mul => head * tail,
|
BinaryKind::Mul => head * tail,
|
||||||
BinaryKind::Div => head / tail,
|
BinaryKind::Div => head / tail,
|
||||||
BinaryKind::Rem => head % tail,
|
BinaryKind::Rem => head % tail,
|
||||||
BinaryKind::Dot => todo!("search within a type's namespace!"),
|
|
||||||
BinaryKind::Call => match tail {
|
BinaryKind::Call => match tail {
|
||||||
ConValue::Empty => head.call(env, &[]),
|
ConValue::Empty => head.call(env, &[]),
|
||||||
ConValue::Tuple(args) => head.call(env, &args),
|
ConValue::Tuple(args) => head.call(env, &args),
|
||||||
@ -313,6 +313,26 @@ impl Interpret for Unary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Interpret for Member {
|
||||||
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
|
let Member { head, kind } = self;
|
||||||
|
let head = head.interpret(env)?;
|
||||||
|
match (head, kind) {
|
||||||
|
(ConValue::Tuple(v), MemberKind::Tuple(Literal::Int(id))) => v
|
||||||
|
.get(*id as usize)
|
||||||
|
.cloned()
|
||||||
|
.ok_or(Error::OobIndex(*id as usize, v.len())),
|
||||||
|
(head, MemberKind::Call(name, args)) => {
|
||||||
|
let mut values = vec![head];
|
||||||
|
for arg in &args.exprs {
|
||||||
|
values.push(arg.interpret(env)?);
|
||||||
|
}
|
||||||
|
env.call(name.0, &values)
|
||||||
|
}
|
||||||
|
_ => Err(Error::TypeError)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Interpret for Index {
|
impl Interpret for Index {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { head, indices } = self;
|
let Self { head, indices } = self;
|
||||||
|
@ -862,6 +862,7 @@ impl<'t> Parser<'t> {
|
|||||||
Some(match op {
|
Some(match op {
|
||||||
Punct::LBrack => Precedence::Index,
|
Punct::LBrack => Precedence::Index,
|
||||||
Punct::LParen => Precedence::Call,
|
Punct::LParen => Precedence::Call,
|
||||||
|
Punct::Dot => Precedence::Member,
|
||||||
_ => None?,
|
_ => None?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -889,6 +890,10 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
Punct::Dot => {
|
||||||
|
let kind = self.access()?;
|
||||||
|
Member { head: Box::new(head), kind }.into()
|
||||||
|
}
|
||||||
_ => Err(self.error(Unexpected(TokenKind::Punct(op)), parsing))?,
|
_ => Err(self.error(Unexpected(TokenKind::Punct(op)), parsing))?,
|
||||||
};
|
};
|
||||||
continue;
|
continue;
|
||||||
@ -922,6 +927,28 @@ impl<'t> Parser<'t> {
|
|||||||
Ok(head)
|
Ok(head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn access(&mut self) -> PResult<MemberKind> {
|
||||||
|
const PARSING: Parsing = Parsing::Member;
|
||||||
|
const DEL: (Punct, Punct) = PARENS; // delimiter
|
||||||
|
match self.peek_kind(PARSING)? {
|
||||||
|
TokenKind::Identifier => {
|
||||||
|
let name = self.identifier()?;
|
||||||
|
if self.match_op(DEL.0, PARSING).is_err() {
|
||||||
|
Ok(MemberKind::Struct(name))
|
||||||
|
} else {
|
||||||
|
let exprs = sep(Self::expr, Punct::Comma, DEL.1, PARSING)(self)?;
|
||||||
|
self.match_op(DEL.1, PARSING)?; // should succeed
|
||||||
|
Ok(MemberKind::Call(name, Tuple { exprs }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenKind::Literal => {
|
||||||
|
let name = self.literal()?; // TODO: Maybe restrict this to just
|
||||||
|
Ok(MemberKind::Tuple(name))
|
||||||
|
}
|
||||||
|
t => Err(self.error(Unexpected(t), PARSING)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
|
/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
|
||||||
pub fn exprkind_pathlike(&mut self) -> PResult<ExprKind> {
|
pub fn exprkind_pathlike(&mut self) -> PResult<ExprKind> {
|
||||||
let head = self.path()?;
|
let head = self.path()?;
|
||||||
@ -1174,7 +1201,7 @@ impl Precedence {
|
|||||||
}
|
}
|
||||||
pub fn postfix(self) -> Option<(u8, ())> {
|
pub fn postfix(self) -> Option<(u8, ())> {
|
||||||
match self {
|
match self {
|
||||||
Self::Index | Self::Call => Some((self.level(), ())),
|
Self::Index | Self::Call | Self::Member => Some((self.level(), ())),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1190,7 +1217,6 @@ impl From<BinaryKind> for Precedence {
|
|||||||
use BinaryKind as Op;
|
use BinaryKind as Op;
|
||||||
match value {
|
match value {
|
||||||
Op::Call => Precedence::Call,
|
Op::Call => Precedence::Call,
|
||||||
Op::Dot => Precedence::Member,
|
|
||||||
Op::Mul | Op::Div | Op::Rem => Precedence::Term,
|
Op::Mul | Op::Div | Op::Rem => Precedence::Term,
|
||||||
Op::Add | Op::Sub => Precedence::Factor,
|
Op::Add | Op::Sub => Precedence::Factor,
|
||||||
Op::Shl | Op::Shr => Precedence::Shift,
|
Op::Shl | Op::Shr => Precedence::Shift,
|
||||||
@ -1264,6 +1290,5 @@ operator! {
|
|||||||
Star => Mul,
|
Star => Mul,
|
||||||
Slash => Div,
|
Slash => Div,
|
||||||
Rem => Rem,
|
Rem => Rem,
|
||||||
Dot => Dot,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -391,6 +391,7 @@ pub mod yamlify {
|
|||||||
ExprKind::Assign(k) => k.yaml(y),
|
ExprKind::Assign(k) => k.yaml(y),
|
||||||
ExprKind::Binary(k) => k.yaml(y),
|
ExprKind::Binary(k) => k.yaml(y),
|
||||||
ExprKind::Unary(k) => k.yaml(y),
|
ExprKind::Unary(k) => k.yaml(y),
|
||||||
|
ExprKind::Member(k) => k.yaml(y),
|
||||||
ExprKind::Index(k) => k.yaml(y),
|
ExprKind::Index(k) => k.yaml(y),
|
||||||
ExprKind::Structor(k) => k.yaml(y),
|
ExprKind::Structor(k) => k.yaml(y),
|
||||||
ExprKind::Path(k) => k.yaml(y),
|
ExprKind::Path(k) => k.yaml(y),
|
||||||
@ -451,6 +452,21 @@ pub mod yamlify {
|
|||||||
y.value(self);
|
y.value(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Yamlify for Member {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
let Self { head, kind } = self;
|
||||||
|
y.key("Member").pair("head", head).pair("kind", kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Yamlify for MemberKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
match self {
|
||||||
|
MemberKind::Call(id, args) => y.pair("id", id).pair("args", args),
|
||||||
|
MemberKind::Struct(id) => y.pair("id", id),
|
||||||
|
MemberKind::Tuple(id) => y.pair("id", id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Yamlify for Tuple {
|
impl Yamlify for Tuple {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { exprs } = self;
|
let Self { exprs } = self;
|
||||||
|
@ -95,7 +95,8 @@ Term = Unary (TermOp Unary )* ;
|
|||||||
|
|
||||||
Unary = (UnaryKind)* Member ;
|
Unary = (UnaryKind)* Member ;
|
||||||
|
|
||||||
Member = Call ('.' Call)* ;
|
Member = Call (Access)* ;
|
||||||
|
Access = '.' (Identifier ('(' Tuple? ')')? | Literal) ;
|
||||||
|
|
||||||
Call = Index ('(' Tuple? ')')* ;
|
Call = Index ('(' Tuple? ')')* ;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user