conlang: Add array and slice type syntax
This commit is contained in:
		| @@ -253,12 +253,27 @@ pub enum TyKind { | ||||
|     Never, | ||||
|     Empty, | ||||
|     Path(Path), | ||||
|     Array(TyArray), | ||||
|     Slice(TySlice), | ||||
|     Tuple(TyTuple), | ||||
|     Ref(TyRef), | ||||
|     Fn(TyFn), | ||||
|     // 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 | ||||
| #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||||
| pub struct TyTuple { | ||||
|   | ||||
| @@ -307,6 +307,8 @@ mod display { | ||||
|                 TyKind::Never => "!".fmt(f), | ||||
|                 TyKind::Empty => "()".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::Ref(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 { | ||||
|         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|             separate(&self.types, ", ")(f.delimit(INLINE_PARENS)) | ||||
|   | ||||
| @@ -172,6 +172,14 @@ pub trait Fold { | ||||
|     fn fold_ty_kind(&mut self, kind: TyKind) -> TyKind { | ||||
|         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 { | ||||
|         let TyTuple { types } = t; | ||||
|         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::Empty => TyKind::Empty, | ||||
|         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::Ref(t) => TyKind::Ref(folder.fold_ty_ref(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) { | ||||
|         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) { | ||||
|         let TyTuple { types } = t; | ||||
|         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::Empty => {} | ||||
|         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::Ref(t) => visitor.visit_ty_ref(t), | ||||
|         TyKind::Fn(t) => visitor.visit_ty_fn(t), | ||||
|   | ||||
| @@ -78,6 +78,8 @@ pub enum Parsing { | ||||
|  | ||||
|     Ty, | ||||
|     TyKind, | ||||
|     TySlice, | ||||
|     TyArray, | ||||
|     TyTuple, | ||||
|     TyRef, | ||||
|     TyFn, | ||||
| @@ -181,6 +183,8 @@ impl Display for Parsing { | ||||
|  | ||||
|             Parsing::Ty => "a type", | ||||
|             Parsing::TyKind => "a type", | ||||
|             Parsing::TySlice => "a slice type", | ||||
|             Parsing::TyArray => "an array type", | ||||
|             Parsing::TyTuple => "a tuple of types", | ||||
|             Parsing::TyRef => "a reference type", | ||||
|             Parsing::TyFn => "a function pointer type", | ||||
|   | ||||
| @@ -673,6 +673,7 @@ impl<'t> Parser<'t> { | ||||
|                 TyKind::Never | ||||
|             } | ||||
|             TokenKind::Punct(Punct::Amp) | TokenKind::Punct(Punct::AmpAmp) => self.tyref()?.into(), | ||||
|             TokenKind::Punct(Punct::LBrack) => self.tyslice_or_array()?, | ||||
|             TokenKind::Punct(Punct::LParen) => { | ||||
|                 let out = self.tytuple()?; | ||||
|                 match out.types.is_empty() { | ||||
| @@ -687,6 +688,32 @@ impl<'t> Parser<'t> { | ||||
|  | ||||
|         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]? `)` | ||||
|     pub fn tytuple(&mut self) -> PResult<TyTuple> { | ||||
|         const PARSING: Parsing = Parsing::TyTuple; | ||||
|   | ||||
| @@ -614,6 +614,8 @@ pub mod yamlify { | ||||
|                 TyKind::Tuple(t) => y.yaml(t), | ||||
|                 TyKind::Ref(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 { | ||||
|         fn yaml(&self, y: &mut Yamler) { | ||||
|             let Self { types } = self; | ||||
|   | ||||
| @@ -172,7 +172,7 @@ pub mod evaluate { | ||||
|  | ||||
|     use super::*; | ||||
|     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 | ||||
|     pub trait EvaluableTypeExpression { | ||||
| @@ -197,6 +197,8 @@ pub mod evaluate { | ||||
|                 TyKind::Empty => prj.anon_types[&TypeKind::Empty], | ||||
|                 // TyKind::Path must be looked up explicitly | ||||
|                 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::Ref(tyref) => tyref.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 { | ||||
|         type Out = DefID; | ||||
|         fn evaluate(&self, prj: &mut Project, parent: DefID) -> Result<DefID, String> { | ||||
|   | ||||
| @@ -50,10 +50,12 @@ UseTree     = '*' | '{' (UseTree ',')* UseTree? '}' | ||||
|             | PathPart ('::' UseTree | "as" Identifier)? ; | ||||
|  | ||||
| (* type *) | ||||
| Ty          = Never | Empty | Path | TyTuple | TyRef | TyFn ; | ||||
| Ty          = Never | Empty | Path | TyArray | TySlice | TyTuple | TyRef | TyFn ; | ||||
| Never       = '!' ; | ||||
| Empty       = '(' ')' ; | ||||
| TyTuple     = '(' (Ty ',')* Ty? ')' ; | ||||
| TyArray     = '[' Ty ';' INTEGER ']' ; | ||||
| TySlice     = '[' Ty ']' ; | ||||
| TyRef       = Amps* Path ; | ||||
| Amps        = '&' | '&&' ; | ||||
| TyFn        = "fn" TyTuple ('->' Ty)? ; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user