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:
parent
21b0ce1c01
commit
f73d3aa5d7
|
@ -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 | "_" } ;
|
||||
|
|
|
@ -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,34 +103,95 @@ 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() {
|
||||
f.write_char('<')?;
|
||||
let mut first_run = true;
|
||||
for arg in &self.generic_args {
|
||||
if !first_run {
|
||||
f.write_str(", ")?;
|
||||
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 generic_args {
|
||||
if !first_run {
|
||||
f.write_str(", ")?;
|
||||
} else {
|
||||
first_run = false;
|
||||
}
|
||||
write!(f, "{}", arg)?;
|
||||
}
|
||||
f.write_char('>')
|
||||
} else {
|
||||
first_run = false;
|
||||
f.write_str("")
|
||||
}
|
||||
write!(f, "{}", arg)?;
|
||||
}
|
||||
f.write_char('>')
|
||||
} else {
|
||||
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,
|
||||
|
|
|
@ -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,33 +173,77 @@ 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() {
|
||||
crate::lexing::TokenKind::Identifier(ident) => ident,
|
||||
_ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
|
||||
};
|
||||
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() {
|
||||
f.write_char('<')?;
|
||||
let mut first_run = true;
|
||||
for arg in &self.generic_args {
|
||||
if !first_run {
|
||||
f.write_str(", ")?;
|
||||
f.write_str(ident)?;
|
||||
if !generic_args.is_empty() {
|
||||
f.write_char('<')?;
|
||||
let mut first_run = true;
|
||||
for arg in generic_args {
|
||||
if !first_run {
|
||||
f.write_str(", ")?;
|
||||
} else {
|
||||
first_run = false;
|
||||
}
|
||||
write!(f, "{}", arg)?;
|
||||
}
|
||||
f.write_char('>')
|
||||
} else {
|
||||
first_run = false;
|
||||
f.write_str("")
|
||||
}
|
||||
write!(f, "{}", arg)?;
|
||||
}
|
||||
f.write_char('>')
|
||||
} else {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,24 +122,51 @@ impl Parser {
|
|||
}
|
||||
|
||||
fn parse_type(&mut self) -> Result<Type, ParsingError> {
|
||||
let identifier = self.expect(token![Ident])?;
|
||||
if self.expect_peek(token![Ident]) {
|
||||
let identifier = self.expect(token![Ident])?;
|
||||
|
||||
let mut generic_args = vec![];
|
||||
if self.expect_peek(token![<]) {
|
||||
self.expect(token![<])?;
|
||||
if self.expect_peek(token![Ident]) {
|
||||
generic_args.push(self.parse_type()?);
|
||||
}
|
||||
while self.expect_peek(token![Comma]) {
|
||||
self.expect(token![Comma])?;
|
||||
generic_args.push(self.parse_type()?);
|
||||
}
|
||||
self.expect(token![>])?;
|
||||
}
|
||||
Ok(Type::Typical {
|
||||
identifier,
|
||||
generic_args,
|
||||
})
|
||||
} else {
|
||||
// we got a function type
|
||||
self.expect(token![fn])?;
|
||||
self.expect(token![CurvedBracketOpen])?;
|
||||
let mut inputs = vec![];
|
||||
|
||||
let mut generic_args = vec![];
|
||||
if self.expect_peek(token![<]) {
|
||||
self.expect(token![<])?;
|
||||
if self.expect_peek(token![Ident]) {
|
||||
generic_args.push(self.parse_type()?);
|
||||
inputs.push(self.parse_named_type()?);
|
||||
}
|
||||
while self.expect_peek(token![Comma]) {
|
||||
self.expect(token![Comma])?;
|
||||
generic_args.push(self.parse_type()?);
|
||||
inputs.push(self.parse_named_type()?);
|
||||
}
|
||||
self.expect(token![>])?;
|
||||
|
||||
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,
|
||||
})
|
||||
}
|
||||
Ok(Type {
|
||||
identifier,
|
||||
generic_args,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_bracket_string_literal(&mut self) -> Result<StringLiteral, ParsingError> {
|
||||
|
|
Reference in New Issue