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]
default = ["lua", "shulkerbox"]
serde = ["dep:serde", "shulkerbox?/serde"]
shulkerbox = ["dep:shulkerbox"]
serde = ["dep:serde"]
lua = ["dep:mlua"]
[target.'cfg(target_arch = "wasm32")'.dependencies]
path-absolutize = { version = "3.1.1", features = ["use_unix_paths_on_wasm"] }
[dependencies]
chksum-md5 = "0.0.0"
colored = "2.1.0"

View File

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

View File

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

View File

@ -97,7 +97,7 @@ impl SourceElement for Annotation {
///
/// ``` ebnf
/// Function:
/// Annotation* 'fn' Identifier '(' ParameterList? ')' Block
/// Annotation* 'pub'? 'fn' Identifier '(' ParameterList? ')' Block
/// ;
///
/// ParameterList:
@ -107,6 +107,8 @@ impl SourceElement for Annotation {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Function {
#[get = "pub"]
public_keyword: Option<Keyword>,
#[get = "pub"]
annotations: Vec<Annotation>,
#[get = "pub"]
@ -130,6 +132,7 @@ impl Function {
pub fn dissolve(
self,
) -> (
Option<Keyword>,
Vec<Annotation>,
Keyword,
Identifier,
@ -139,6 +142,7 @@ impl Function {
Block,
) {
(
self.public_keyword,
self.annotations,
self.function_keyword,
self.identifier,
@ -148,11 +152,21 @@ impl Function {
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 {
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)?;
Some(Declaration::Function(Function {
public_keyword: None,
annotations: Vec::new(),
function_keyword,
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
Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
// parse the annotation