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), | ||||
|     /// 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 ']' ; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user