Add support for doc comments
This commit is contained in:
parent
b9bc5438e5
commit
dc288588c8
|
@ -5,12 +5,16 @@ edition = "2021"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = ["shulkerbox"]
|
||||
shulkerbox = ["dep:shulkerbox"]
|
||||
|
||||
[dependencies]
|
||||
colored = "2.1.0"
|
||||
derive_more = { version = "0.99.17", default-features = false, features = ["deref", "from", "deref_mut"] }
|
||||
enum-as-inner = "0.6.0"
|
||||
getset = "0.1.2"
|
||||
shulkerbox = { path = "../shulkerbox" }
|
||||
shulkerbox = { path = "../shulkerbox", optional = true}
|
||||
strum = { version = "0.26.2", features = ["derive"] }
|
||||
strum_macros = "0.26.2"
|
||||
thiserror = "1.0.58"
|
||||
|
|
|
@ -119,5 +119,9 @@ fn compile_statement(statement: &Statement) -> Option<Command> {
|
|||
)))
|
||||
}
|
||||
}
|
||||
Statement::DocComment(doccomment) => {
|
||||
let content = doccomment.content();
|
||||
Some(Command::Comment(content.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ pub enum Token {
|
|||
Punctuation(Punctuation),
|
||||
Numeric(Numeric),
|
||||
Comment(Comment),
|
||||
DocComment(DocComment),
|
||||
CommandLiteral(CommandLiteral),
|
||||
StringLiteral(StringLiteral),
|
||||
}
|
||||
|
@ -90,6 +91,7 @@ impl Token {
|
|||
Self::Punctuation(token) => &token.span,
|
||||
Self::Numeric(token) => &token.span,
|
||||
Self::Comment(token) => &token.span,
|
||||
Self::DocComment(token) => &token.span,
|
||||
Self::CommandLiteral(token) => &token.span,
|
||||
Self::StringLiteral(token) => &token.span,
|
||||
}
|
||||
|
@ -105,6 +107,7 @@ impl SourceElement for Token {
|
|||
Self::Punctuation(token) => token.span(),
|
||||
Self::Numeric(token) => token.span(),
|
||||
Self::Comment(token) => token.span(),
|
||||
Self::DocComment(token) => token.span(),
|
||||
Self::CommandLiteral(token) => token.span(),
|
||||
Self::StringLiteral(token) => token.span(),
|
||||
}
|
||||
|
@ -229,6 +232,27 @@ impl SourceElement for Comment {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a documentation comment in the source code.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct DocComment {
|
||||
/// Is the span that makes up the token.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl SourceElement for DocComment {
|
||||
fn span(&self) -> Span {
|
||||
self.span.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl DocComment {
|
||||
/// Returns the content of the doc comment without the leading `///`.
|
||||
#[must_use]
|
||||
pub fn content(&self) -> &str {
|
||||
&self.span.str().trim()[3..]
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hardcoded literal command in the source code.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct CommandLiteral {
|
||||
|
@ -339,22 +363,37 @@ impl Token {
|
|||
if let Some((_, '/')) = iter.peek() {
|
||||
iter.next();
|
||||
|
||||
let is_doccomment = if let Some((_, '/')) = iter.peek() {
|
||||
iter.next();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
Self::walk_iter(iter, |character| !(character == '\n' || character == '\r'));
|
||||
|
||||
let is_cr = iter
|
||||
.peek()
|
||||
.map_or(false, |(_, character)| character == '\r');
|
||||
|
||||
let span = Self::create_span(start, iter);
|
||||
|
||||
if let (true, Some((_, '\n'))) = (is_cr, iter.next()) {
|
||||
// skips the crlf
|
||||
iter.next();
|
||||
}
|
||||
|
||||
Ok(Comment {
|
||||
span: Self::create_span(start, iter),
|
||||
let comment = if is_doccomment {
|
||||
DocComment { span }.into()
|
||||
} else {
|
||||
Comment {
|
||||
span,
|
||||
kind: CommentKind::Line,
|
||||
}
|
||||
.into())
|
||||
.into()
|
||||
};
|
||||
|
||||
Ok(comment)
|
||||
}
|
||||
// Delimited comment
|
||||
else if let Some((_, '*')) = iter.peek() {
|
||||
|
|
60
src/lib.rs
60
src/lib.rs
|
@ -21,9 +21,11 @@ use std::{cell::Cell, fmt::Display, path::Path};
|
|||
|
||||
use base::{source_file::SourceFile, Handler, Result};
|
||||
use compile::compiler::Compiler;
|
||||
use shulkerbox::{util::compile::CompileOptions, virtual_fs::VFolder};
|
||||
use syntax::syntax_tree::program::Program;
|
||||
|
||||
#[cfg(feature = "shulkerbox")]
|
||||
use shulkerbox::{datapack::Datapack, util::compile::CompileOptions, virtual_fs::VFolder};
|
||||
|
||||
use crate::{base::Error, lexical::token_stream::TokenStream, syntax::parser::Parser};
|
||||
|
||||
/// Converts the given source code to tokens.
|
||||
|
@ -61,13 +63,59 @@ pub fn parse(path: &Path) -> Result<Program> {
|
|||
"An error occured while parsing the source code.",
|
||||
))?;
|
||||
|
||||
if printer.has_printed() {
|
||||
return Err(Error::Other(
|
||||
"An error occurred while parsing the source code.",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(program)
|
||||
}
|
||||
|
||||
/// Transpiles the given source code into a shulkerbox [`Datapack`].
|
||||
///
|
||||
/// # Errors
|
||||
/// - If an error occurs while reading the file.
|
||||
/// - If an error occurs while parsing the source code.
|
||||
/// - If an error occurs while transpiling the source code.
|
||||
#[cfg(feature = "shulkerbox")]
|
||||
pub fn transpile(path: &Path) -> Result<Datapack> {
|
||||
let source_file = SourceFile::load(path)?;
|
||||
|
||||
let printer = Printer::new();
|
||||
|
||||
let tokens = TokenStream::tokenize(&source_file, &printer);
|
||||
|
||||
if printer.has_printed() {
|
||||
return Err(Error::Other(
|
||||
"An error occurred while tokenizing the source code.",
|
||||
));
|
||||
}
|
||||
|
||||
let mut parser = Parser::new(&tokens);
|
||||
let program = parser.parse_program(&printer).ok_or(Error::Other(
|
||||
"An error occured while parsing the source code.",
|
||||
))?;
|
||||
|
||||
if printer.has_printed() {
|
||||
return Err(Error::Other(
|
||||
"An error occurred while parsing the source code.",
|
||||
));
|
||||
}
|
||||
|
||||
let mut compiler = Compiler::new();
|
||||
let datapack = compiler.compile(&program, &printer)?;
|
||||
|
||||
Ok(datapack)
|
||||
}
|
||||
|
||||
/// Compiles the given source code.
|
||||
///
|
||||
/// # Errors
|
||||
/// - If an error occurs while reading the file.
|
||||
/// - If an error occurs while parsing the source code.
|
||||
/// - If an error occurs while transpiling the source code.
|
||||
#[cfg(feature = "shulkerbox")]
|
||||
pub fn compile(path: &Path) -> Result<VFolder> {
|
||||
let source_file = SourceFile::load(path)?;
|
||||
|
||||
|
@ -88,14 +136,22 @@ pub fn compile(path: &Path) -> Result<VFolder> {
|
|||
"An error occured while parsing the source code.",
|
||||
))?;
|
||||
|
||||
if printer.has_printed() {
|
||||
return Err(Error::Other(
|
||||
"An error occurred while parsing the source code.",
|
||||
));
|
||||
}
|
||||
|
||||
// println!("program: {program:#?}");
|
||||
|
||||
let mut compiler = Compiler::new();
|
||||
let datapack = compiler.compile(&program, &printer)?;
|
||||
|
||||
// println!("datapack: {datapack:#?}");
|
||||
|
||||
if printer.has_printed() {
|
||||
return Err(Error::Other(
|
||||
"An error occurred while parsing the source code.",
|
||||
"An error occurred while transpiling the source code.",
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ impl Display for UnexpectedSyntax {
|
|||
};
|
||||
let found_binding = match self.found.clone() {
|
||||
Some(Token::Comment(..)) => "a comment token".to_string(),
|
||||
Some(Token::DocComment(..)) => "a doc comment token".to_string(),
|
||||
Some(Token::Identifier(..)) => "an identifier token".to_string(),
|
||||
Some(Token::Keyword(keyword)) => {
|
||||
format!("a keyword token `{}`", keyword.keyword.as_str())
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
Handler,
|
||||
},
|
||||
lexical::{
|
||||
token::{CommandLiteral, Keyword, KeywordKind, Punctuation, Token},
|
||||
token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token},
|
||||
token_stream::Delimiter,
|
||||
},
|
||||
syntax::{
|
||||
|
@ -25,6 +25,8 @@ use super::expression::ParenthesizedCondition;
|
|||
/// Statement:
|
||||
/// Block
|
||||
/// | LiteralCommand
|
||||
/// | Conditional
|
||||
/// | DocComment
|
||||
/// ;
|
||||
/// ```
|
||||
#[allow(missing_docs)]
|
||||
|
@ -33,6 +35,7 @@ pub enum Statement {
|
|||
Block(Block),
|
||||
LiteralCommand(CommandLiteral),
|
||||
Conditional(Conditional),
|
||||
DocComment(DocComment),
|
||||
}
|
||||
|
||||
impl SourceElement for Statement {
|
||||
|
@ -41,6 +44,7 @@ impl SourceElement for Statement {
|
|||
Self::Block(block) => block.span(),
|
||||
Self::LiteralCommand(literal_command) => literal_command.span(),
|
||||
Self::Conditional(conditional) => conditional.span(),
|
||||
Self::DocComment(doc_comment) => doc_comment.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,6 +261,12 @@ impl<'a> Parser<'a> {
|
|||
})),
|
||||
}
|
||||
}
|
||||
|
||||
Reading::Atomic(Token::DocComment(doc_comment)) => {
|
||||
self.forward();
|
||||
Some(Statement::DocComment(doc_comment))
|
||||
}
|
||||
|
||||
// other
|
||||
unexpected => {
|
||||
handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
|
||||
|
|
Loading…
Reference in New Issue