conlang: Add array and slice type syntax
This commit is contained in:
parent
b3d62c09aa
commit
3511575669
@ -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)? ;
|
||||||
|
Loading…
Reference in New Issue
Block a user