conlang: Add constructor expression for structs!
grammar: - Add new rules `PathLike`, `Structor`, `Fielder` - Replace Path with PathLike in Primary expressions cl-ast: - Add nodes for Structor and Fielder cl-parser: - Add branch to path-expression parsing - Parse Structor bodies interpret: - Add TODO
This commit is contained in:
parent
efd442bbfa
commit
5341631781
@ -350,6 +350,8 @@ pub enum ExprKind {
|
||||
Unary(Unary),
|
||||
/// An Array [Index] expression: a[10, 20, 30]
|
||||
Index(Index),
|
||||
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||
Structor(Structor),
|
||||
/// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])*
|
||||
Path(Path),
|
||||
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
||||
@ -466,6 +468,20 @@ pub struct Index {
|
||||
pub indices: Vec<Expr>,
|
||||
}
|
||||
|
||||
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Structor {
|
||||
pub to: Path,
|
||||
pub init: Vec<Fielder>,
|
||||
}
|
||||
|
||||
/// A [Struct field initializer] expression: [Identifier] (`=` [Expr])?
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Fielder {
|
||||
pub name: Identifier,
|
||||
pub init: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
/// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]`
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Array {
|
||||
|
@ -424,6 +424,7 @@ mod display {
|
||||
ExprKind::Binary(v) => v.fmt(f),
|
||||
ExprKind::Unary(v) => v.fmt(f),
|
||||
ExprKind::Index(v) => v.fmt(f),
|
||||
ExprKind::Structor(v) => v.fmt(f),
|
||||
ExprKind::Path(v) => v.fmt(f),
|
||||
ExprKind::Literal(v) => v.fmt(f),
|
||||
ExprKind::Array(v) => v.fmt(f),
|
||||
@ -540,6 +541,25 @@ mod display {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Structor {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { to, init } = self;
|
||||
write!(f, "{to}: ")?;
|
||||
separate(init, ", ")(f.delimit(INLINE_BRACES))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Fielder {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { name, init } = self;
|
||||
write!(f, "{name}")?;
|
||||
if let Some(init) = init {
|
||||
write!(f, ": {init}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Array {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
separate(&self.values, ", ")(f.delimit(INLINE_SQUARE))
|
||||
|
@ -269,6 +269,22 @@ pub trait Fold {
|
||||
indices: indices.into_iter().map(|e| self.fold_expr(e)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_structor(&mut self, s: Structor) -> Structor {
|
||||
let Structor { to, init } = s;
|
||||
Structor {
|
||||
to: self.fold_path(to),
|
||||
init: init.into_iter().map(|f| self.fold_fielder(f)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_fielder(&mut self, f: Fielder) -> Fielder {
|
||||
let Fielder { name, init } = f;
|
||||
Fielder {
|
||||
name: self.fold_identifier(name),
|
||||
init: init.map(|e| Box::new(self.fold_expr(*e))),
|
||||
}
|
||||
}
|
||||
fn fold_array(&mut self, a: Array) -> Array {
|
||||
let Array { values } = a;
|
||||
Array { values: values.into_iter().map(|e| self.fold_expr(e)).collect() }
|
||||
@ -499,6 +515,7 @@ pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> Ex
|
||||
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),
|
||||
ExprKind::Unary(u) => ExprKind::Unary(folder.fold_unary(u)),
|
||||
ExprKind::Index(i) => ExprKind::Index(folder.fold_index(i)),
|
||||
ExprKind::Structor(s) => ExprKind::Structor(folder.fold_structor(s)),
|
||||
ExprKind::Path(p) => ExprKind::Path(folder.fold_path(p)),
|
||||
ExprKind::Literal(l) => ExprKind::Literal(folder.fold_literal(l)),
|
||||
ExprKind::Array(a) => ExprKind::Array(folder.fold_array(a)),
|
||||
|
@ -228,6 +228,18 @@ pub trait Visit<'a>: Sized {
|
||||
self.visit_expr_kind(head);
|
||||
indices.iter().for_each(|e| self.visit_expr(e));
|
||||
}
|
||||
fn visit_structor(&mut self, s: &'a Structor) {
|
||||
let Structor { to, init } = s;
|
||||
self.visit_path(to);
|
||||
init.iter().for_each(|e| self.visit_fielder(e))
|
||||
}
|
||||
fn visit_fielder(&mut self, f: &'a Fielder) {
|
||||
let Fielder { name, init } = f;
|
||||
self.visit_identifier(name);
|
||||
if let Some(init) = init {
|
||||
self.visit_expr(init);
|
||||
}
|
||||
}
|
||||
fn visit_array(&mut self, a: &'a Array) {
|
||||
let Array { values } = a;
|
||||
values.iter().for_each(|e| self.visit_expr(e))
|
||||
@ -415,6 +427,7 @@ pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
|
||||
ExprKind::Binary(b) => visitor.visit_binary(b),
|
||||
ExprKind::Unary(u) => visitor.visit_unary(u),
|
||||
ExprKind::Index(i) => visitor.visit_index(i),
|
||||
ExprKind::Structor(s) => visitor.visit_structor(s),
|
||||
ExprKind::Path(p) => visitor.visit_path(p),
|
||||
ExprKind::Literal(l) => visitor.visit_literal(l),
|
||||
ExprKind::Array(a) => visitor.visit_array(a),
|
||||
|
@ -126,17 +126,18 @@ impl Interpret for Expr {
|
||||
impl Interpret for ExprKind {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
match self {
|
||||
ExprKind::Empty => Ok(ConValue::Empty),
|
||||
ExprKind::Assign(v) => v.interpret(env),
|
||||
ExprKind::Binary(v) => v.interpret(env),
|
||||
ExprKind::Unary(v) => v.interpret(env),
|
||||
ExprKind::Index(v) => v.interpret(env),
|
||||
ExprKind::Structor(v) => v.interpret(env),
|
||||
ExprKind::Path(v) => v.interpret(env),
|
||||
ExprKind::Literal(v) => v.interpret(env),
|
||||
ExprKind::Array(v) => v.interpret(env),
|
||||
ExprKind::ArrayRep(v) => v.interpret(env),
|
||||
ExprKind::AddrOf(v) => v.interpret(env),
|
||||
ExprKind::Block(v) => v.interpret(env),
|
||||
ExprKind::Empty => Ok(ConValue::Empty),
|
||||
ExprKind::Group(v) => v.interpret(env),
|
||||
ExprKind::Tuple(v) => v.interpret(env),
|
||||
ExprKind::Loop(v) => v.interpret(env),
|
||||
@ -322,6 +323,11 @@ impl Interpret for Index {
|
||||
Ok(head)
|
||||
}
|
||||
}
|
||||
impl Interpret for Structor {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
todo!("struct construction in {env}")
|
||||
}
|
||||
}
|
||||
impl Interpret for Path {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { absolute: _, parts } = self;
|
||||
|
@ -91,6 +91,8 @@ pub enum Parsing {
|
||||
Unary,
|
||||
UnaryKind,
|
||||
Index,
|
||||
Structor,
|
||||
Fielder,
|
||||
Call,
|
||||
Member,
|
||||
PathExpr,
|
||||
@ -190,6 +192,8 @@ impl Display for Parsing {
|
||||
Parsing::Unary => "a unary expression",
|
||||
Parsing::UnaryKind => "a unary operator",
|
||||
Parsing::Index => "an indexing expression",
|
||||
Parsing::Structor => "a struct constructor expression",
|
||||
Parsing::Fielder => "a struct field expression",
|
||||
Parsing::Call => "a call expression",
|
||||
Parsing::Member => "a member access expression",
|
||||
Parsing::PathExpr => "a path",
|
||||
|
@ -820,7 +820,7 @@ impl<'t> Parser<'t> {
|
||||
// Prefix expressions
|
||||
let mut head = match self.peek_kind(Parsing::Unary)? {
|
||||
literal_like!() => self.literal()?.into(),
|
||||
path_like!() => self.path()?.into(),
|
||||
path_like!() => self.exprkind_pathlike()?,
|
||||
TokenKind::Punct(Punct::Amp | Punct::AmpAmp) => self.addrof()?.into(),
|
||||
TokenKind::Punct(Punct::LCurly) => self.block()?.into(),
|
||||
TokenKind::Punct(Punct::LBrack) => self.exprkind_arraylike()?,
|
||||
@ -912,6 +912,38 @@ impl<'t> Parser<'t> {
|
||||
Ok(head)
|
||||
}
|
||||
|
||||
/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
|
||||
pub fn exprkind_pathlike(&mut self) -> PResult<ExprKind> {
|
||||
let head = self.path()?;
|
||||
Ok(match self.match_op(Punct::Colon, Parsing::PathExpr) {
|
||||
Ok(_) => ExprKind::Structor(self.structor_body(head)?),
|
||||
Err(_) => ExprKind::Path(head),
|
||||
})
|
||||
}
|
||||
|
||||
/// [Structor]Body = `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||
pub fn structor_body(&mut self, to: Path) -> PResult<Structor> {
|
||||
let init = delim(
|
||||
sep(Self::fielder, Punct::Comma, CURLIES.1, Parsing::Structor),
|
||||
CURLIES,
|
||||
Parsing::Structor,
|
||||
)(self)?;
|
||||
|
||||
Ok(Structor { to, init })
|
||||
}
|
||||
|
||||
/// [Fielder] = [Identifier] (`:` [Expr])?
|
||||
pub fn fielder(&mut self) -> PResult<Fielder> {
|
||||
const PARSING: Parsing = Parsing::Fielder;
|
||||
Ok(Fielder {
|
||||
name: self.identifier()?,
|
||||
init: match self.match_op(Punct::Colon, PARSING) {
|
||||
Ok(_) => Some(Box::new(self.expr()?)),
|
||||
Err(_) => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// [Array] = '[' ([Expr] ',')* [Expr]? ']'
|
||||
///
|
||||
/// Array and ArrayRef are ambiguous until the second token,
|
||||
|
@ -391,6 +391,7 @@ pub mod yamlify {
|
||||
ExprKind::Binary(k) => k.yaml(y),
|
||||
ExprKind::Unary(k) => k.yaml(y),
|
||||
ExprKind::Index(k) => k.yaml(y),
|
||||
ExprKind::Structor(k) => k.yaml(y),
|
||||
ExprKind::Path(k) => k.yaml(y),
|
||||
ExprKind::Literal(k) => k.yaml(y),
|
||||
ExprKind::Array(k) => k.yaml(y),
|
||||
@ -461,6 +462,18 @@ pub mod yamlify {
|
||||
y.key("Index").pair("head", head).list(indices);
|
||||
}
|
||||
}
|
||||
impl Yamlify for Structor {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
let Self { to, init } = self;
|
||||
y.key("Structor").pair("to", to).list(init);
|
||||
}
|
||||
}
|
||||
impl Yamlify for Fielder {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
let Self { name: Identifier(name), init } = self;
|
||||
y.key("Fielder").pair("name", name).pair("init", init);
|
||||
}
|
||||
}
|
||||
impl Yamlify for Array {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
let Self { values } = self;
|
||||
|
@ -103,12 +103,15 @@ Call = Index ('(' Tuple? ')')* ;
|
||||
Index = Primary ('[' Indices ']')* ;
|
||||
Indices = (Expr ',')* Expr? ;
|
||||
|
||||
Primary = Literal | Path | Array | ArrayRep | AddrOf
|
||||
| Block | Group | Loop
|
||||
| If | While | For | Break | Return | Continue;
|
||||
Primary = Literal | PathLike | Array | ArrayRep | AddrOf | Block | Group
|
||||
| Loop | If | While | For | Break | Return | Continue;
|
||||
|
||||
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
||||
|
||||
PathLike = Path | Structor ;
|
||||
Structor = Path ':' '{' (Fielder ',')* Fielder? '}' ;
|
||||
Fielder = Identifier ('=' Expr)? ;
|
||||
|
||||
Array = '[' (Expr ',')* Expr? ']' ;
|
||||
ArrayRep = '[' Expr ';' Expr ']' ;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user