conlang: Add array and slice type syntax
This commit is contained in:
		| @@ -253,12 +253,27 @@ pub enum TyKind { | |||||||
|     Never, |     Never, | ||||||
|     Empty, |     Empty, | ||||||
|     Path(Path), |     Path(Path), | ||||||
|  |     Array(TyArray), | ||||||
|  |     Slice(TySlice), | ||||||
|     Tuple(TyTuple), |     Tuple(TyTuple), | ||||||
|     Ref(TyRef), |     Ref(TyRef), | ||||||
|     Fn(TyFn), |     Fn(TyFn), | ||||||
|     // TODO: slice, array types |     // TODO: slice, array types | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// An array of [`T`](Ty) | ||||||
|  | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||||||
|  | pub struct TyArray { | ||||||
|  |     pub ty: Box<TyKind>, | ||||||
|  |     pub count: usize, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// A [Ty]pe slice expression: `[T]` | ||||||
|  | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||||||
|  | pub struct TySlice { | ||||||
|  |     pub ty: Box<TyKind>, | ||||||
|  | } | ||||||
|  |  | ||||||
| /// A tuple of [Ty]pes | /// A tuple of [Ty]pes | ||||||
| #[derive(Clone, Debug, PartialEq, Eq, Hash)] | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||||||
| pub struct TyTuple { | pub struct TyTuple { | ||||||
|   | |||||||
| @@ -307,6 +307,8 @@ mod display { | |||||||
|                 TyKind::Never => "!".fmt(f), |                 TyKind::Never => "!".fmt(f), | ||||||
|                 TyKind::Empty => "()".fmt(f), |                 TyKind::Empty => "()".fmt(f), | ||||||
|                 TyKind::Path(v) => v.fmt(f), |                 TyKind::Path(v) => v.fmt(f), | ||||||
|  |                 TyKind::Array(v) => v.fmt(f), | ||||||
|  |                 TyKind::Slice(v) => v.fmt(f), | ||||||
|                 TyKind::Tuple(v) => v.fmt(f), |                 TyKind::Tuple(v) => v.fmt(f), | ||||||
|                 TyKind::Ref(v) => v.fmt(f), |                 TyKind::Ref(v) => v.fmt(f), | ||||||
|                 TyKind::Fn(v) => v.fmt(f), |                 TyKind::Fn(v) => v.fmt(f), | ||||||
| @@ -314,6 +316,20 @@ mod display { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     impl Display for TyArray { | ||||||
|  |         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |             let Self { ty, count } = self; | ||||||
|  |             write!(f, "[{ty}; {count}]") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl Display for TySlice { | ||||||
|  |         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |             let Self { ty } = self; | ||||||
|  |             write!(f, "[{ty}]") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     impl Display for TyTuple { |     impl Display for TyTuple { | ||||||
|         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|             separate(&self.types, ", ")(f.delimit(INLINE_PARENS)) |             separate(&self.types, ", ")(f.delimit(INLINE_PARENS)) | ||||||
|   | |||||||
| @@ -172,6 +172,14 @@ pub trait Fold { | |||||||
|     fn fold_ty_kind(&mut self, kind: TyKind) -> TyKind { |     fn fold_ty_kind(&mut self, kind: TyKind) -> TyKind { | ||||||
|         or_fold_ty_kind(self, kind) |         or_fold_ty_kind(self, kind) | ||||||
|     } |     } | ||||||
|  |     fn fold_ty_array(&mut self, a: TyArray) -> TyArray { | ||||||
|  |         let TyArray { ty, count } = a; | ||||||
|  |         TyArray { ty: Box::new(self.fold_ty_kind(*ty)), count } | ||||||
|  |     } | ||||||
|  |     fn fold_ty_slice(&mut self, s: TySlice) -> TySlice { | ||||||
|  |         let TySlice { ty } = s; | ||||||
|  |         TySlice { ty: Box::new(self.fold_ty_kind(*ty)) } | ||||||
|  |     } | ||||||
|     fn fold_ty_tuple(&mut self, t: TyTuple) -> TyTuple { |     fn fold_ty_tuple(&mut self, t: TyTuple) -> TyTuple { | ||||||
|         let TyTuple { types } = t; |         let TyTuple { types } = t; | ||||||
|         TyTuple { |         TyTuple { | ||||||
| @@ -500,6 +508,8 @@ pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind | |||||||
|         TyKind::Never => TyKind::Never, |         TyKind::Never => TyKind::Never, | ||||||
|         TyKind::Empty => TyKind::Empty, |         TyKind::Empty => TyKind::Empty, | ||||||
|         TyKind::Path(p) => TyKind::Path(folder.fold_path(p)), |         TyKind::Path(p) => TyKind::Path(folder.fold_path(p)), | ||||||
|  |         TyKind::Array(a) => TyKind::Array(folder.fold_ty_array(a)), | ||||||
|  |         TyKind::Slice(s) => TyKind::Slice(folder.fold_ty_slice(s)), | ||||||
|         TyKind::Tuple(t) => TyKind::Tuple(folder.fold_ty_tuple(t)), |         TyKind::Tuple(t) => TyKind::Tuple(folder.fold_ty_tuple(t)), | ||||||
|         TyKind::Ref(t) => TyKind::Ref(folder.fold_ty_ref(t)), |         TyKind::Ref(t) => TyKind::Ref(folder.fold_ty_ref(t)), | ||||||
|         TyKind::Fn(t) => TyKind::Fn(folder.fold_ty_fn(t)), |         TyKind::Fn(t) => TyKind::Fn(folder.fold_ty_fn(t)), | ||||||
|   | |||||||
| @@ -145,6 +145,14 @@ pub trait Visit<'a>: Sized { | |||||||
|     fn visit_ty_kind(&mut self, kind: &'a TyKind) { |     fn visit_ty_kind(&mut self, kind: &'a TyKind) { | ||||||
|         or_visit_ty_kind(self, kind) |         or_visit_ty_kind(self, kind) | ||||||
|     } |     } | ||||||
|  |     fn visit_ty_array(&mut self, a: &'a TyArray) { | ||||||
|  |         let TyArray { ty, count: _ } = a; | ||||||
|  |         self.visit_ty_kind(ty); | ||||||
|  |     } | ||||||
|  |     fn visit_ty_slice(&mut self, s: &'a TySlice) { | ||||||
|  |         let TySlice { ty } = s; | ||||||
|  |         self.visit_ty_kind(ty) | ||||||
|  |     } | ||||||
|     fn visit_ty_tuple(&mut self, t: &'a TyTuple) { |     fn visit_ty_tuple(&mut self, t: &'a TyTuple) { | ||||||
|         let TyTuple { types } = t; |         let TyTuple { types } = t; | ||||||
|         types.iter().for_each(|kind| self.visit_ty_kind(kind)) |         types.iter().for_each(|kind| self.visit_ty_kind(kind)) | ||||||
| @@ -424,6 +432,8 @@ pub fn or_visit_ty_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a TyKind) { | |||||||
|         TyKind::Never => {} |         TyKind::Never => {} | ||||||
|         TyKind::Empty => {} |         TyKind::Empty => {} | ||||||
|         TyKind::Path(p) => visitor.visit_path(p), |         TyKind::Path(p) => visitor.visit_path(p), | ||||||
|  |         TyKind::Array(t) => visitor.visit_ty_array(t), | ||||||
|  |         TyKind::Slice(t) => visitor.visit_ty_slice(t), | ||||||
|         TyKind::Tuple(t) => visitor.visit_ty_tuple(t), |         TyKind::Tuple(t) => visitor.visit_ty_tuple(t), | ||||||
|         TyKind::Ref(t) => visitor.visit_ty_ref(t), |         TyKind::Ref(t) => visitor.visit_ty_ref(t), | ||||||
|         TyKind::Fn(t) => visitor.visit_ty_fn(t), |         TyKind::Fn(t) => visitor.visit_ty_fn(t), | ||||||
|   | |||||||
| @@ -78,6 +78,8 @@ pub enum Parsing { | |||||||
|  |  | ||||||
|     Ty, |     Ty, | ||||||
|     TyKind, |     TyKind, | ||||||
|  |     TySlice, | ||||||
|  |     TyArray, | ||||||
|     TyTuple, |     TyTuple, | ||||||
|     TyRef, |     TyRef, | ||||||
|     TyFn, |     TyFn, | ||||||
| @@ -181,13 +183,15 @@ impl Display for Parsing { | |||||||
|  |  | ||||||
|             Parsing::Ty => "a type", |             Parsing::Ty => "a type", | ||||||
|             Parsing::TyKind => "a type", |             Parsing::TyKind => "a type", | ||||||
|  |             Parsing::TySlice => "a slice type", | ||||||
|  |             Parsing::TyArray => "an array type", | ||||||
|             Parsing::TyTuple => "a tuple of types", |             Parsing::TyTuple => "a tuple of types", | ||||||
|             Parsing::TyRef => "a reference type", |             Parsing::TyRef => "a reference type", | ||||||
|             Parsing::TyFn => "a function pointer type", |             Parsing::TyFn => "a function pointer type", | ||||||
|  |  | ||||||
|             Parsing::Path => "a path", |             Parsing::Path => "a path", | ||||||
|             Parsing::PathPart => "a path component", |             Parsing::PathPart => "a path component", | ||||||
|              |  | ||||||
|             Parsing::Stmt => "a statement", |             Parsing::Stmt => "a statement", | ||||||
|             Parsing::StmtKind => "a statement", |             Parsing::StmtKind => "a statement", | ||||||
|             Parsing::Let => "a local variable declaration", |             Parsing::Let => "a local variable declaration", | ||||||
|   | |||||||
| @@ -673,6 +673,7 @@ impl<'t> Parser<'t> { | |||||||
|                 TyKind::Never |                 TyKind::Never | ||||||
|             } |             } | ||||||
|             TokenKind::Punct(Punct::Amp) | TokenKind::Punct(Punct::AmpAmp) => self.tyref()?.into(), |             TokenKind::Punct(Punct::Amp) | TokenKind::Punct(Punct::AmpAmp) => self.tyref()?.into(), | ||||||
|  |             TokenKind::Punct(Punct::LBrack) => self.tyslice_or_array()?, | ||||||
|             TokenKind::Punct(Punct::LParen) => { |             TokenKind::Punct(Punct::LParen) => { | ||||||
|                 let out = self.tytuple()?; |                 let out = self.tytuple()?; | ||||||
|                 match out.types.is_empty() { |                 match out.types.is_empty() { | ||||||
| @@ -687,6 +688,32 @@ impl<'t> Parser<'t> { | |||||||
|  |  | ||||||
|         Ok(out) |         Ok(out) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// [`TySlice`] = `[` [Ty] `]`  \ | ||||||
|  |     /// [`TyArray`] = `[` [Ty] `;` [usize] `]` | ||||||
|  |     pub fn tyslice_or_array(&mut self) -> PResult<TyKind> { | ||||||
|  |         self.match_op(BRACKETS.0, Parsing::TySlice)?; | ||||||
|  |         let ty = self.tykind()?; | ||||||
|  |         let (out, kind) = match self.match_op(Punct::Semi, Parsing::TyArray).is_ok() { | ||||||
|  |             true => { | ||||||
|  |                 let literal = self.match_type(TokenKind::Literal, Parsing::TyArray)?; | ||||||
|  |                 let &TokenData::Integer(count) = literal.data() else { | ||||||
|  |                     Err(self.error(Unexpected(TokenKind::Literal), Parsing::TyArray))? | ||||||
|  |                 }; | ||||||
|  |                 ( | ||||||
|  |                     TyKind::Array(TyArray { ty: Box::new(ty), count: count as _ }), | ||||||
|  |                     Parsing::TyArray, | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             false => ( | ||||||
|  |                 TyKind::Slice(TySlice { ty: Box::new(ty) }), | ||||||
|  |                 Parsing::TySlice, | ||||||
|  |             ), | ||||||
|  |         }; | ||||||
|  |         self.match_op(BRACKETS.1, kind)?; | ||||||
|  |         Ok(out) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// [TyTuple] = `(` ([Ty] `,`)* [Ty]? `)` |     /// [TyTuple] = `(` ([Ty] `,`)* [Ty]? `)` | ||||||
|     pub fn tytuple(&mut self) -> PResult<TyTuple> { |     pub fn tytuple(&mut self) -> PResult<TyTuple> { | ||||||
|         const PARSING: Parsing = Parsing::TyTuple; |         const PARSING: Parsing = Parsing::TyTuple; | ||||||
|   | |||||||
| @@ -614,6 +614,8 @@ pub mod yamlify { | |||||||
|                 TyKind::Tuple(t) => y.yaml(t), |                 TyKind::Tuple(t) => y.yaml(t), | ||||||
|                 TyKind::Ref(t) => y.yaml(t), |                 TyKind::Ref(t) => y.yaml(t), | ||||||
|                 TyKind::Fn(t) => y.yaml(t), |                 TyKind::Fn(t) => y.yaml(t), | ||||||
|  |                 TyKind::Slice(_) => todo!(), | ||||||
|  |                 TyKind::Array(_) => todo!(), | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -639,6 +641,18 @@ pub mod yamlify { | |||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     impl Yamlify for TyArray { | ||||||
|  |         fn yaml(&self, y: &mut Yamler) { | ||||||
|  |             let Self { ty, count } = self; | ||||||
|  |             y.key("TyArray").pair("ty", ty).pair("count", count); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     impl Yamlify for TySlice { | ||||||
|  |         fn yaml(&self, y: &mut Yamler) { | ||||||
|  |             let Self { ty } = self; | ||||||
|  |             y.key("TyArray").pair("ty", ty); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     impl Yamlify for TyTuple { |     impl Yamlify for TyTuple { | ||||||
|         fn yaml(&self, y: &mut Yamler) { |         fn yaml(&self, y: &mut Yamler) { | ||||||
|             let Self { types } = self; |             let Self { types } = self; | ||||||
|   | |||||||
| @@ -172,7 +172,7 @@ pub mod evaluate { | |||||||
|  |  | ||||||
|     use super::*; |     use super::*; | ||||||
|     use crate::module; |     use crate::module; | ||||||
|     use cl_ast::{Sym, Ty, TyFn, TyKind, TyRef, TyTuple}; |     use cl_ast::{Sym, Ty, TyArray, TyFn, TyKind, TyRef, TySlice, TyTuple}; | ||||||
|  |  | ||||||
|     /// Things that can be evaluated as a type expression |     /// Things that can be evaluated as a type expression | ||||||
|     pub trait EvaluableTypeExpression { |     pub trait EvaluableTypeExpression { | ||||||
| @@ -197,6 +197,8 @@ pub mod evaluate { | |||||||
|                 TyKind::Empty => prj.anon_types[&TypeKind::Empty], |                 TyKind::Empty => prj.anon_types[&TypeKind::Empty], | ||||||
|                 // TyKind::Path must be looked up explicitly |                 // TyKind::Path must be looked up explicitly | ||||||
|                 TyKind::Path(path) => path.evaluate(prj, parent)?, |                 TyKind::Path(path) => path.evaluate(prj, parent)?, | ||||||
|  |                 TyKind::Slice(slice) => slice.evaluate(prj, parent)?, | ||||||
|  |                 TyKind::Array(array) => array.evaluate(prj, parent)?, | ||||||
|                 TyKind::Tuple(tup) => tup.evaluate(prj, parent)?, |                 TyKind::Tuple(tup) => tup.evaluate(prj, parent)?, | ||||||
|                 TyKind::Ref(tyref) => tyref.evaluate(prj, parent)?, |                 TyKind::Ref(tyref) => tyref.evaluate(prj, parent)?, | ||||||
|                 TyKind::Fn(tyfn) => tyfn.evaluate(prj, parent)?, |                 TyKind::Fn(tyfn) => tyfn.evaluate(prj, parent)?, | ||||||
| @@ -220,6 +222,38 @@ pub mod evaluate { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     impl EvaluableTypeExpression for TySlice { | ||||||
|  |         type Out = DefID; | ||||||
|  |  | ||||||
|  |         fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> { | ||||||
|  |             let ty = self.ty.evaluate(prj, parent)?; | ||||||
|  |             let root = prj.root; | ||||||
|  |             let id = prj.insert_anonymous_type(TypeKind::Slice(ty), move || Def { | ||||||
|  |                 module: module::Module::new(root), | ||||||
|  |                 node: Node::new(Default::default(), None), | ||||||
|  |                 kind: DefKind::Type(TypeKind::Slice(ty)), | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             Ok(id) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl EvaluableTypeExpression for TyArray { | ||||||
|  |         type Out = DefID; | ||||||
|  |  | ||||||
|  |         fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<Self::Out, String> { | ||||||
|  |             let kind = TypeKind::Array(self.ty.evaluate(prj, parent)?, self.count); | ||||||
|  |             let root = prj.root; | ||||||
|  |             let id = prj.insert_anonymous_type(kind.clone(), move || Def { | ||||||
|  |                 module: module::Module::new(root), | ||||||
|  |                 node: Node::new(Default::default(), None), | ||||||
|  |                 kind: DefKind::Type(kind), | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             Ok(id) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     impl EvaluableTypeExpression for TyTuple { |     impl EvaluableTypeExpression for TyTuple { | ||||||
|         type Out = DefID; |         type Out = DefID; | ||||||
|         fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<DefID, String> { |         fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<DefID, String> { | ||||||
|   | |||||||
| @@ -50,10 +50,12 @@ UseTree     = '*' | '{' (UseTree ',')* UseTree? '}' | |||||||
|             | PathPart ('::' UseTree | "as" Identifier)? ; |             | PathPart ('::' UseTree | "as" Identifier)? ; | ||||||
|  |  | ||||||
| (* type *) | (* type *) | ||||||
| Ty          = Never | Empty | Path | TyTuple | TyRef | TyFn ; | Ty          = Never | Empty | Path | TyArray | TySlice | TyTuple | TyRef | TyFn ; | ||||||
| Never       = '!' ; | Never       = '!' ; | ||||||
| Empty       = '(' ')' ; | Empty       = '(' ')' ; | ||||||
| TyTuple     = '(' (Ty ',')* Ty? ')' ; | TyTuple     = '(' (Ty ',')* Ty? ')' ; | ||||||
|  | TyArray     = '[' Ty ';' INTEGER ']' ; | ||||||
|  | TySlice     = '[' Ty ']' ; | ||||||
| TyRef       = Amps* Path ; | TyRef       = Amps* Path ; | ||||||
| Amps        = '&' | '&&' ; | Amps        = '&' | '&&' ; | ||||||
| TyFn        = "fn" TyTuple ('->' Ty)? ; | TyFn        = "fn" TyTuple ('->' Ty)? ; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user