Implement public keyword for functions

This commit is contained in:
Moritz Hölting 2024-06-09 17:59:56 +02:00
parent f00302c8af
commit e80809b3f9
4 changed files with 79 additions and 5 deletions

View File

@ -7,10 +7,13 @@ edition = "2021"
[features] [features]
default = ["lua", "shulkerbox"] default = ["lua", "shulkerbox"]
serde = ["dep:serde", "shulkerbox?/serde"]
shulkerbox = ["dep:shulkerbox"] shulkerbox = ["dep:shulkerbox"]
serde = ["dep:serde"]
lua = ["dep:mlua"] lua = ["dep:mlua"]
[target.'cfg(target_arch = "wasm32")'.dependencies]
path-absolutize = { version = "3.1.1", features = ["use_unix_paths_on_wasm"] }
[dependencies] [dependencies]
chksum-md5 = "0.0.0" chksum-md5 = "0.0.0"
colored = "2.1.0" colored = "2.1.0"

View File

@ -4,7 +4,12 @@
### Program ### Program
```ebnf ```ebnf
Program: Declaration*; Program: Namespace Declaration*;
```
### Namespace
```ebnf
Namespace: 'namespace' StringLiteral;
``` ```
### Declaration ### Declaration
@ -15,7 +20,7 @@ Declaration: FunctionDeclaration;
### FunctionDeclaration ### FunctionDeclaration
```ebnf ```ebnf
Function: Function:
Annotation* 'fn' Identifier '(' ParameterList? ')' Block Annotation* 'pub'? 'fn' Identifier '(' ParameterList? ')' Block
; ;
ParameterList: ParameterList:
Identifier (',' Identifier)* ','? Identifier (',' Identifier)* ','?

View File

@ -19,6 +19,7 @@ use super::{error::UnterminatedDelimitedComment, Error};
#[allow(missing_docs)] #[allow(missing_docs)]
pub enum KeywordKind { pub enum KeywordKind {
Function, Function,
Pub,
If, If,
Else, Else,
Align, Align,
@ -76,6 +77,7 @@ impl KeywordKind {
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
Self::Function => "fn", Self::Function => "fn",
Self::Pub => "pub",
Self::If => "if", Self::If => "if",
Self::Else => "else", Self::Else => "else",
Self::Align => "align", Self::Align => "align",

View File

@ -97,7 +97,7 @@ impl SourceElement for Annotation {
/// ///
/// ``` ebnf /// ``` ebnf
/// Function: /// Function:
/// Annotation* 'fn' Identifier '(' ParameterList? ')' Block /// Annotation* 'pub'? 'fn' Identifier '(' ParameterList? ')' Block
/// ; /// ;
/// ///
/// ParameterList: /// ParameterList:
@ -107,6 +107,8 @@ impl SourceElement for Annotation {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Function { pub struct Function {
#[get = "pub"]
public_keyword: Option<Keyword>,
#[get = "pub"] #[get = "pub"]
annotations: Vec<Annotation>, annotations: Vec<Annotation>,
#[get = "pub"] #[get = "pub"]
@ -130,6 +132,7 @@ impl Function {
pub fn dissolve( pub fn dissolve(
self, self,
) -> ( ) -> (
Option<Keyword>,
Vec<Annotation>, Vec<Annotation>,
Keyword, Keyword,
Identifier, Identifier,
@ -139,6 +142,7 @@ impl Function {
Block, Block,
) { ) {
( (
self.public_keyword,
self.annotations, self.annotations,
self.function_keyword, self.function_keyword,
self.identifier, self.identifier,
@ -148,11 +152,21 @@ impl Function {
self.block, self.block,
) )
} }
/// Returns `true` if the function is public.
#[must_use]
pub fn is_public(&self) -> bool {
self.public_keyword.is_some()
}
} }
impl SourceElement for Function { impl SourceElement for Function {
fn span(&self) -> Span { fn span(&self) -> Span {
self.function_keyword.span.join(&self.block.span()).unwrap() self.public_keyword
.as_ref()
.map_or_else(|| self.function_keyword.span(), SourceElement::span)
.join(&self.block.span())
.unwrap()
} }
} }
@ -231,6 +245,7 @@ impl<'a> Parser<'a> {
let block = self.parse_block(handler)?; let block = self.parse_block(handler)?;
Some(Declaration::Function(Function { Some(Declaration::Function(Function {
public_keyword: None,
annotations: Vec::new(), annotations: Vec::new(),
function_keyword, function_keyword,
identifier, identifier,
@ -241,6 +256,55 @@ impl<'a> Parser<'a> {
})) }))
} }
Reading::Atomic(Token::Keyword(pub_keyword))
if pub_keyword.keyword == KeywordKind::Pub =>
{
// eat the public keyword
self.forward();
// parse the function keyword
let function_keyword_reading = self.next_significant_token();
match function_keyword_reading {
Reading::Atomic(Token::Keyword(function_keyword))
if function_keyword.keyword == KeywordKind::Function =>
{
// eat the function keyword
self.forward();
// parse the identifier
let identifier = self.parse_identifier(handler)?;
let delimited_tree = self.parse_enclosed_list(
Delimiter::Parenthesis,
',',
|parser: &mut Parser<'_>| parser.parse_identifier(handler),
handler,
)?;
// parse the block
let block = self.parse_block(handler)?;
Some(Declaration::Function(Function {
public_keyword: Some(pub_keyword),
annotations: Vec::new(),
function_keyword,
identifier,
open_paren: delimited_tree.open,
parameters: delimited_tree.list,
close_paren: delimited_tree.close,
block,
}))
}
unexpected => {
handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
expected: SyntaxKind::Keyword(KeywordKind::Function),
found: unexpected.into_token(),
}));
None
}
}
}
// parse annotations // parse annotations
Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => { Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
// parse the annotation // parse the annotation