feat(parser): Add support for parsing function pointer types

Notably these diverge from rust, by requiring argument names. This is a
deliberate design decision, as it help users to guess what's going to be
passed into their callback.
This commit is contained in:
Benedikt Peetz 2024-03-24 19:35:09 +01:00
parent 21b0ce1c01
commit f73d3aa5d7
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
5 changed files with 309 additions and 81 deletions

View File

@ -35,7 +35,7 @@ Namespace = {DocComment} {Attribute} "mod" Identifier "{" {Function | Namespace
Structure = {DocComment} {Attribute} "struct" Identifier "{" [DocNamedType {"," DocNamedType } [","]] "}";
Enumeration = {DocComment} {Attribute} "enum" Identifier "{" [DocIdentifier {"," DocIdentifier} [","]] "}";
Type = Identifier ["<" Type {"," Type} ">"];
Type = Identifier ["<" Type {"," Type} ">"] | "fn" "(" [NamedType {"," NamedType }] ")" [ "->" Type ];
StringLiteral = ["r"] "\"" {ANYTHING} "\"" | "r" "#" {"#"} "\"" {ANYTHING} "#" {"#"} "\"";
Identifier = (CHARACTER | "_") { NUMBER | CHARACTER | "_" } ;

View File

@ -25,7 +25,7 @@ use std::fmt::{Display, Write};
use crate::lexing::TokenKind;
use super::unchecked;
use super::unchecked::{self, DeriveValue};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Variant {
@ -103,19 +103,34 @@ pub struct Function {
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Type {
pub identifier: Identifier,
pub generic_args: Vec<Type>,
pub enum Type {
Typical {
identifier: Identifier,
generic_args: Vec<Type>,
},
Function {
inputs: Vec<NamedType>,
output: Option<Box<Type>>,
},
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ident = &self.identifier.name;
f.write_str(ident)?;
if !self.generic_args.is_empty() {
impl Type {
pub fn print_generics(&self) -> String {
let mut output = String::new();
self.display_generics(&mut output)
.expect("This should fail");
output
}
pub fn display_generics<T: Write>(&self, f: &mut T) -> std::fmt::Result {
match self {
Type::Typical {
identifier: _,
generic_args,
} => {
if !generic_args.is_empty() {
f.write_char('<')?;
let mut first_run = true;
for arg in &self.generic_args {
for arg in generic_args {
if !first_run {
f.write_str(", ")?;
} else {
@ -128,9 +143,55 @@ impl Display for Type {
f.write_str("")
}
}
Type::Function { .. } => {
unimplemented!("This function should only be called for the 'Typical' enum variant")
}
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Typical {
identifier,
generic_args: _,
} => {
f.write_str(&identifier.name)?;
self.display_generics(f)
}
Type::Function { inputs, output } => {
f.write_str("fn(")?;
if !inputs.is_empty() {
f.write_str(
&inputs
.iter()
.map(|ty| ty.to_string())
.collect::<Vec<_>>()
.join(", "),
)?;
}
f.write_str(")")?;
if let Some(output) = output {
f.write_str("-> ")?;
f.write_str(output.to_string().as_str())?;
}
Ok(())
}
}
}
}
impl Display for NamedType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.name.name)?;
f.write_str(": ")?;
f.write_str(self.r#type.to_string().as_str())
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct NamedType {
pub name: Identifier,
pub r#type: Type,

View File

@ -25,7 +25,7 @@
use std::fmt::{Display, Write};
use crate::lexing::{Token, TokenSpan};
use crate::lexing::{Token, TokenKind, TokenSpan};
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct CommandSpec {
@ -173,23 +173,46 @@ pub struct NamedType {
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Type {
pub identifier: Token, // Will later become an Identifier
pub generic_args: Vec<Type>,
pub enum Type {
Typical {
identifier: Token, // Will later become an Identifier
generic_args: Vec<Type>,
},
Function {
inputs: Vec<NamedType>,
output: Option<Box<Type>>,
},
}
impl Display for NamedType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ident = match self.name.kind() {
crate::lexing::TokenKind::Identifier(ident) => ident,
_ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
};
f.write_str(ident)?;
f.write_str(": ")?;
f.write_str(self.r#type.to_string().as_str())
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let ident = match self.identifier.kind() {
match self {
Type::Typical {
identifier,
generic_args,
} => {
let ident = match identifier.kind() {
crate::lexing::TokenKind::Identifier(ident) => ident,
_ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
};
f.write_str(ident)?;
if !self.generic_args.is_empty() {
if !generic_args.is_empty() {
f.write_char('<')?;
let mut first_run = true;
for arg in &self.generic_args {
for arg in generic_args {
if !first_run {
f.write_str(", ")?;
} else {
@ -202,4 +225,25 @@ impl Display for Type {
f.write_str("")
}
}
Type::Function { inputs, output } => {
f.write_str("fn(")?;
if !inputs.is_empty() {
f.write_str(
&inputs
.iter()
.map(|ty| ty.to_string())
.collect::<Vec<_>>()
.join(", "),
)?;
}
f.write_str(")")?;
if let Some(output) = output {
f.write_str("-> ")?;
f.write_str(output.to_string().as_str())?;
}
Ok(())
}
}
}
}

View File

@ -286,25 +286,101 @@ impl Parser {
})
}
fn process_type(&mut self, mut r#type: UncheckedType) -> Result<Type, ParsingError> {
let identifier: Identifier =
mem::take(&mut r#type.identifier.kind).to_identifier(Variant::Void);
fn process_type(&mut self, r#type: UncheckedType) -> Result<Type, ParsingError> {
match r#type {
UncheckedType::Typical {
identifier,
generic_args,
} => self.process_typical_type(identifier, generic_args),
UncheckedType::Function { inputs, output } => {
self.process_function_type(inputs, output)
}
}
}
fn process_typical_type(
&mut self,
mut type_identifier: Token,
generic_args: Vec<UncheckedType>,
) -> Result<Type, ParsingError> {
fn match_to_vector_struct(matches: Vec<&UncheckedStructure>) -> Vec<Identifier> {
matches
.first()
.expect("This exists")
.namespaces
.iter()
.map(|token| match token.kind() {
TokenKind::Identifier(ident) => Identifier {
name: ident.to_owned(),
variant: Variant::Namespace,
},
_ => unreachable!("This should not be here"),
})
.collect()
}
fn match_to_vector_enum(matches: Vec<&UncheckedEnumeration>) -> Vec<Identifier> {
matches
.first()
.expect("This exists")
.namespaces
.iter()
.map(|token| match token.kind() {
TokenKind::Identifier(ident) => Identifier {
name: ident.to_owned(),
variant: Variant::Namespace,
},
_ => unreachable!("This should not be here"),
})
.collect()
}
let identifier: Identifier =
mem::take(&mut type_identifier.kind).to_identifier(Variant::Void);
let variant: Variant;
if self
let matched_structures: Vec<_> = self
.structures
.iter()
.map(|r#struct| (r#struct.identifier.kind.clone()).to_identifier(Variant::Void))
.any(|ident| ident == identifier)
{
variant = Variant::Structure;
} else if self
.filter(|r#struct| {
(r#struct.identifier.kind.clone()).to_identifier(Variant::Void) == identifier
})
.collect();
let matched_enumerations: Vec<_> = self
.enumerations
.iter()
.map(|r#enum| (r#enum.identifier.kind.clone()).to_identifier(Variant::Void))
.any(|ident| ident == identifier)
{
variant = Variant::Enumeration;
.filter(|r#enum| {
(r#enum.identifier.kind.clone()).to_identifier(Variant::Void) == identifier
})
.collect();
if !matched_structures.is_empty() {
if matched_structures.len() != 1 {
return Err(error::ParsingError::StructureCopied {
structure: identifier,
span: *matched_structures
.first()
.expect("Exists")
.identifier
.span(),
});
}
variant = Variant::Structure {
namespace: match_to_vector_struct(matched_structures),
};
} else if !matched_enumerations.is_empty() {
if matched_enumerations.len() != 1 {
return Err(error::ParsingError::EnumerationCopied {
enumeration: identifier,
span: *matched_enumerations
.first()
.expect("Exists")
.identifier
.span(),
});
}
variant = Variant::Enumeration {
namespace: match_to_vector_enum(matched_enumerations),
};
} else if BASE_TYPES
.iter()
.any(|(ident, _)| ident == &identifier.name)
@ -313,7 +389,7 @@ impl Parser {
} else {
return Err(ParsingError::TypeNotDeclared {
r#type: identifier,
span: r#type.identifier.span,
span: type_identifier.span,
});
}
let identifier: Identifier = Identifier {
@ -338,43 +414,63 @@ impl Parser {
if !fitting_types
.iter()
.any(|generic_number| *generic_number == &r#type.generic_args.len())
.any(|generic_number| *generic_number == &generic_args.len())
{
if r#type.generic_args.len() < **min_fitting_type {
if generic_args.len() < **min_fitting_type {
return Err(ParsingError::NotEnoughGenericArgs {
expected_min: **min_fitting_type,
got: r#type.generic_args.len(),
got: generic_args.len(),
r#type: identifier,
span: r#type.identifier.span,
span: type_identifier.span,
});
} else if r#type.generic_args.len() > **max_fitting_type {
} else if generic_args.len() > **max_fitting_type {
return Err(ParsingError::TooManyGenericArgs {
expected_max: **max_fitting_type,
got: r#type.generic_args.len(),
got: generic_args.len(),
r#type: identifier,
span: r#type.identifier.span,
span: type_identifier.span,
});
}
}
} else if fitting_types.is_empty() && !r#type.generic_args.is_empty() {
} else if fitting_types.is_empty() && !generic_args.is_empty() {
// Self declared types can not have generic arguments
return Err(ParsingError::TooManyGenericArgs {
expected_max: 0,
got: r#type.generic_args.len(),
got: generic_args.len(),
r#type: identifier,
span: r#type.identifier.span,
span: type_identifier.span,
});
}
}
let mut generic_args = vec![];
for generic_arg in r#type.generic_args {
generic_args.push(self.process_type(generic_arg)?);
let mut new_generic_args: Vec<checked::Type> = vec![];
for generic_arg in generic_args {
new_generic_args.push(self.process_type(generic_arg)?);
}
Ok(Type {
Ok(Type::Typical {
identifier,
generic_args,
generic_args: new_generic_args,
})
}
fn process_function_type(
&mut self,
inputs: Vec<UncheckedNamedType>,
output: Option<Box<UncheckedType>>,
) -> Result<Type, ParsingError> {
let inputs = inputs
.into_iter()
.map(|input| self.process_named_type(input))
.collect::<Result<Vec<NamedType>, ParsingError>>()?;
let mut new_output = None;
if let Some(output) = output {
new_output = Some(Box::new(self.process_type(*output)?));
}
Ok(Type::Function {
inputs,
output: new_output,
})
}
}

View File

@ -122,6 +122,7 @@ impl Parser {
}
fn parse_type(&mut self) -> Result<Type, ParsingError> {
if self.expect_peek(token![Ident]) {
let identifier = self.expect(token![Ident])?;
let mut generic_args = vec![];
@ -136,10 +137,36 @@ impl Parser {
}
self.expect(token![>])?;
}
Ok(Type {
Ok(Type::Typical {
identifier,
generic_args,
})
} else {
// we got a function type
self.expect(token![fn])?;
self.expect(token![CurvedBracketOpen])?;
let mut inputs = vec![];
if self.expect_peek(token![Ident]) {
inputs.push(self.parse_named_type()?);
}
while self.expect_peek(token![Comma]) {
self.expect(token![Comma])?;
inputs.push(self.parse_named_type()?);
}
self.expect(token![CurvedBracketClose])?;
let mut output_type = None;
if self.expect_peek(token![->]) {
self.expect(token![->])?;
output_type = Some(Box::new(self.parse_type()?));
}
Ok(Type::Function {
inputs,
output: output_type,
})
}
}
fn parse_bracket_string_literal(&mut self) -> Result<StringLiteral, ParsingError> {