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),
|
Unary(Unary),
|
||||||
/// 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]? `}`
|
||||||
|
Structor(Structor),
|
||||||
/// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])*
|
/// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])*
|
||||||
Path(Path),
|
Path(Path),
|
||||||
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
||||||
@ -466,6 +468,20 @@ pub struct Index {
|
|||||||
pub indices: Vec<Expr>,
|
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`])\* `]`
|
/// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]`
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Array {
|
pub struct Array {
|
||||||
|
@ -424,6 +424,7 @@ mod display {
|
|||||||
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::Index(v) => v.fmt(f),
|
ExprKind::Index(v) => v.fmt(f),
|
||||||
|
ExprKind::Structor(v) => v.fmt(f),
|
||||||
ExprKind::Path(v) => v.fmt(f),
|
ExprKind::Path(v) => v.fmt(f),
|
||||||
ExprKind::Literal(v) => v.fmt(f),
|
ExprKind::Literal(v) => v.fmt(f),
|
||||||
ExprKind::Array(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 {
|
impl Display for Array {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
separate(&self.values, ", ")(f.delimit(INLINE_SQUARE))
|
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(),
|
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 {
|
fn fold_array(&mut self, a: Array) -> Array {
|
||||||
let Array { values } = a;
|
let Array { values } = a;
|
||||||
Array { values: values.into_iter().map(|e| self.fold_expr(e)).collect() }
|
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::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::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::Path(p) => ExprKind::Path(folder.fold_path(p)),
|
ExprKind::Path(p) => ExprKind::Path(folder.fold_path(p)),
|
||||||
ExprKind::Literal(l) => ExprKind::Literal(folder.fold_literal(l)),
|
ExprKind::Literal(l) => ExprKind::Literal(folder.fold_literal(l)),
|
||||||
ExprKind::Array(a) => ExprKind::Array(folder.fold_array(a)),
|
ExprKind::Array(a) => ExprKind::Array(folder.fold_array(a)),
|
||||||
|
@ -228,6 +228,18 @@ pub trait Visit<'a>: Sized {
|
|||||||
self.visit_expr_kind(head);
|
self.visit_expr_kind(head);
|
||||||
indices.iter().for_each(|e| self.visit_expr(e));
|
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) {
|
fn visit_array(&mut self, a: &'a Array) {
|
||||||
let Array { values } = a;
|
let Array { values } = a;
|
||||||
values.iter().for_each(|e| self.visit_expr(e))
|
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::Binary(b) => visitor.visit_binary(b),
|
||||||
ExprKind::Unary(u) => visitor.visit_unary(u),
|
ExprKind::Unary(u) => visitor.visit_unary(u),
|
||||||
ExprKind::Index(i) => visitor.visit_index(i),
|
ExprKind::Index(i) => visitor.visit_index(i),
|
||||||
|
ExprKind::Structor(s) => visitor.visit_structor(s),
|
||||||
ExprKind::Path(p) => visitor.visit_path(p),
|
ExprKind::Path(p) => visitor.visit_path(p),
|
||||||
ExprKind::Literal(l) => visitor.visit_literal(l),
|
ExprKind::Literal(l) => visitor.visit_literal(l),
|
||||||
ExprKind::Array(a) => visitor.visit_array(a),
|
ExprKind::Array(a) => visitor.visit_array(a),
|
||||||
|
@ -126,17 +126,18 @@ impl Interpret for Expr {
|
|||||||
impl Interpret for ExprKind {
|
impl Interpret for ExprKind {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
match self {
|
match self {
|
||||||
|
ExprKind::Empty => Ok(ConValue::Empty),
|
||||||
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::Index(v) => v.interpret(env),
|
ExprKind::Index(v) => v.interpret(env),
|
||||||
|
ExprKind::Structor(v) => v.interpret(env),
|
||||||
ExprKind::Path(v) => v.interpret(env),
|
ExprKind::Path(v) => v.interpret(env),
|
||||||
ExprKind::Literal(v) => v.interpret(env),
|
ExprKind::Literal(v) => v.interpret(env),
|
||||||
ExprKind::Array(v) => v.interpret(env),
|
ExprKind::Array(v) => v.interpret(env),
|
||||||
ExprKind::ArrayRep(v) => v.interpret(env),
|
ExprKind::ArrayRep(v) => v.interpret(env),
|
||||||
ExprKind::AddrOf(v) => v.interpret(env),
|
ExprKind::AddrOf(v) => v.interpret(env),
|
||||||
ExprKind::Block(v) => v.interpret(env),
|
ExprKind::Block(v) => v.interpret(env),
|
||||||
ExprKind::Empty => Ok(ConValue::Empty),
|
|
||||||
ExprKind::Group(v) => v.interpret(env),
|
ExprKind::Group(v) => v.interpret(env),
|
||||||
ExprKind::Tuple(v) => v.interpret(env),
|
ExprKind::Tuple(v) => v.interpret(env),
|
||||||
ExprKind::Loop(v) => v.interpret(env),
|
ExprKind::Loop(v) => v.interpret(env),
|
||||||
@ -322,6 +323,11 @@ impl Interpret for Index {
|
|||||||
Ok(head)
|
Ok(head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Interpret for Structor {
|
||||||
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
|
todo!("struct construction in {env}")
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Interpret for Path {
|
impl Interpret for Path {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { absolute: _, parts } = self;
|
let Self { absolute: _, parts } = self;
|
||||||
|
@ -91,6 +91,8 @@ pub enum Parsing {
|
|||||||
Unary,
|
Unary,
|
||||||
UnaryKind,
|
UnaryKind,
|
||||||
Index,
|
Index,
|
||||||
|
Structor,
|
||||||
|
Fielder,
|
||||||
Call,
|
Call,
|
||||||
Member,
|
Member,
|
||||||
PathExpr,
|
PathExpr,
|
||||||
@ -190,6 +192,8 @@ impl Display for Parsing {
|
|||||||
Parsing::Unary => "a unary expression",
|
Parsing::Unary => "a unary expression",
|
||||||
Parsing::UnaryKind => "a unary operator",
|
Parsing::UnaryKind => "a unary operator",
|
||||||
Parsing::Index => "an indexing expression",
|
Parsing::Index => "an indexing expression",
|
||||||
|
Parsing::Structor => "a struct constructor expression",
|
||||||
|
Parsing::Fielder => "a struct field expression",
|
||||||
Parsing::Call => "a call expression",
|
Parsing::Call => "a call expression",
|
||||||
Parsing::Member => "a member access expression",
|
Parsing::Member => "a member access expression",
|
||||||
Parsing::PathExpr => "a path",
|
Parsing::PathExpr => "a path",
|
||||||
|
@ -820,7 +820,7 @@ impl<'t> Parser<'t> {
|
|||||||
// Prefix expressions
|
// Prefix expressions
|
||||||
let mut head = match self.peek_kind(Parsing::Unary)? {
|
let mut head = match self.peek_kind(Parsing::Unary)? {
|
||||||
literal_like!() => self.literal()?.into(),
|
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::Amp | Punct::AmpAmp) => self.addrof()?.into(),
|
||||||
TokenKind::Punct(Punct::LCurly) => self.block()?.into(),
|
TokenKind::Punct(Punct::LCurly) => self.block()?.into(),
|
||||||
TokenKind::Punct(Punct::LBrack) => self.exprkind_arraylike()?,
|
TokenKind::Punct(Punct::LBrack) => self.exprkind_arraylike()?,
|
||||||
@ -912,6 +912,38 @@ impl<'t> Parser<'t> {
|
|||||||
Ok(head)
|
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] = '[' ([Expr] ',')* [Expr]? ']'
|
||||||
///
|
///
|
||||||
/// Array and ArrayRef are ambiguous until the second token,
|
/// Array and ArrayRef are ambiguous until the second token,
|
||||||
|
@ -391,6 +391,7 @@ pub mod yamlify {
|
|||||||
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::Index(k) => k.yaml(y),
|
ExprKind::Index(k) => k.yaml(y),
|
||||||
|
ExprKind::Structor(k) => k.yaml(y),
|
||||||
ExprKind::Path(k) => k.yaml(y),
|
ExprKind::Path(k) => k.yaml(y),
|
||||||
ExprKind::Literal(k) => k.yaml(y),
|
ExprKind::Literal(k) => k.yaml(y),
|
||||||
ExprKind::Array(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);
|
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 {
|
impl Yamlify for Array {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { values } = self;
|
let Self { values } = self;
|
||||||
|
@ -103,12 +103,15 @@ Call = Index ('(' Tuple? ')')* ;
|
|||||||
Index = Primary ('[' Indices ']')* ;
|
Index = Primary ('[' Indices ']')* ;
|
||||||
Indices = (Expr ',')* Expr? ;
|
Indices = (Expr ',')* Expr? ;
|
||||||
|
|
||||||
Primary = Literal | Path | Array | ArrayRep | AddrOf
|
Primary = Literal | PathLike | Array | ArrayRep | AddrOf | Block | Group
|
||||||
| Block | Group | Loop
|
| Loop | If | While | For | Break | Return | Continue;
|
||||||
| If | While | For | Break | Return | Continue;
|
|
||||||
|
|
||||||
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
||||||
|
|
||||||
|
PathLike = Path | Structor ;
|
||||||
|
Structor = Path ':' '{' (Fielder ',')* Fielder? '}' ;
|
||||||
|
Fielder = Identifier ('=' Expr)? ;
|
||||||
|
|
||||||
Array = '[' (Expr ',')* Expr? ']' ;
|
Array = '[' (Expr ',')* Expr? ']' ;
|
||||||
ArrayRep = '[' Expr ';' Expr ']' ;
|
ArrayRep = '[' Expr ';' Expr ']' ;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user