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:
		| @@ -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 ']' ; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user