use std::fmt;
use rowan::GreenNodeBuilder;
use super::grammar;
use super::lexer::Lexer;
use super::parser::Event;
use super::Diagnostic;
use crate::parser::Parser;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
pub enum SyntaxKind {
Unknown,
Unparsed,
Whitespace,
Comment,
Version,
Float,
Integer,
Ident,
SingleQuote,
DoubleQuote,
OpenHeredoc,
CloseHeredoc,
ArrayTypeKeyword,
BooleanTypeKeyword,
FileTypeKeyword,
FloatTypeKeyword,
IntTypeKeyword,
MapTypeKeyword,
ObjectTypeKeyword,
PairTypeKeyword,
StringTypeKeyword,
AfterKeyword,
AliasKeyword,
AsKeyword,
CallKeyword,
CommandKeyword,
ElseKeyword,
FalseKeyword,
IfKeyword,
InKeyword,
ImportKeyword,
InputKeyword,
MetaKeyword,
NoneKeyword,
NullKeyword,
ObjectKeyword,
OutputKeyword,
ParameterMetaKeyword,
RuntimeKeyword,
ScatterKeyword,
StructKeyword,
TaskKeyword,
ThenKeyword,
TrueKeyword,
VersionKeyword,
WorkflowKeyword,
DirectoryTypeKeyword,
HintsKeyword,
RequirementsKeyword,
OpenBrace,
CloseBrace,
OpenBracket,
CloseBracket,
Assignment,
Colon,
Comma,
OpenParen,
CloseParen,
QuestionMark,
Exclamation,
Plus,
Minus,
LogicalOr,
LogicalAnd,
Asterisk,
Slash,
Percent,
Equal,
NotEqual,
LessEqual,
GreaterEqual,
Less,
Greater,
Dot,
LiteralStringText,
LiteralCommandText,
PlaceholderOpen,
#[doc(hidden)]
Abandoned,
RootNode,
VersionStatementNode,
ImportStatementNode,
ImportAliasNode,
StructDefinitionNode,
TaskDefinitionNode,
WorkflowDefinitionNode,
UnboundDeclNode,
BoundDeclNode,
InputSectionNode,
OutputSectionNode,
CommandSectionNode,
RuntimeSectionNode,
RuntimeItemNode,
PrimitiveTypeNode,
MapTypeNode,
ArrayTypeNode,
PairTypeNode,
ObjectTypeNode,
TypeRefNode,
MetadataSectionNode,
ParameterMetadataSectionNode,
MetadataObjectItemNode,
MetadataObjectNode,
MetadataArrayNode,
LiteralIntegerNode,
LiteralFloatNode,
LiteralBooleanNode,
LiteralNoneNode,
LiteralNullNode,
LiteralStringNode,
LiteralPairNode,
LiteralArrayNode,
LiteralMapNode,
LiteralMapItemNode,
LiteralObjectNode,
LiteralObjectItemNode,
LiteralStructNode,
LiteralStructItemNode,
ParenthesizedExprNode,
NameRefNode,
IfExprNode,
LogicalNotExprNode,
NegationExprNode,
LogicalOrExprNode,
LogicalAndExprNode,
EqualityExprNode,
InequalityExprNode,
LessExprNode,
LessEqualExprNode,
GreaterExprNode,
GreaterEqualExprNode,
AdditionExprNode,
SubtractionExprNode,
MultiplicationExprNode,
DivisionExprNode,
ModuloExprNode,
CallExprNode,
IndexExprNode,
AccessExprNode,
PlaceholderNode,
PlaceholderSepOptionNode,
PlaceholderDefaultOptionNode,
PlaceholderTrueFalseOptionNode,
ConditionalStatementNode,
ScatterStatementNode,
CallStatementNode,
CallTargetNode,
CallAliasNode,
CallAfterNode,
CallInputItemNode,
MAX,
}
impl From<SyntaxKind> for rowan::SyntaxKind {
fn from(kind: SyntaxKind) -> Self {
rowan::SyntaxKind(kind as u16)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WorkflowDescriptionLanguage;
impl rowan::Language for WorkflowDescriptionLanguage {
type Kind = SyntaxKind;
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
assert!(raw.0 <= SyntaxKind::MAX as u16);
unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
}
fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
kind.into()
}
}
pub type SyntaxNode = rowan::SyntaxNode<WorkflowDescriptionLanguage>;
pub type SyntaxToken = rowan::SyntaxToken<WorkflowDescriptionLanguage>;
pub type SyntaxElement = rowan::SyntaxElement<WorkflowDescriptionLanguage>;
pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<WorkflowDescriptionLanguage>;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct SyntaxTree(SyntaxNode);
impl SyntaxTree {
pub fn parse(source: &str) -> (Self, Vec<Diagnostic>) {
let parser = Parser::new(Lexer::new(source));
let (events, errors) = grammar::document(source, parser);
Self::build(source, events, errors)
}
fn build(
source: &str,
mut events: Vec<Event>,
diagnostics: Vec<Diagnostic>,
) -> (Self, Vec<Diagnostic>) {
let mut builder = GreenNodeBuilder::default();
let mut ancestors = Vec::new();
for i in 0..events.len() {
match std::mem::replace(&mut events[i], Event::abandoned()) {
Event::NodeStarted {
kind,
forward_parent,
} => {
ancestors.push(kind);
let mut idx = i;
let mut fp: Option<usize> = forward_parent;
while let Some(distance) = fp {
idx += distance;
fp = match std::mem::replace(&mut events[idx], Event::abandoned()) {
Event::NodeStarted {
kind,
forward_parent,
} => {
ancestors.push(kind);
forward_parent
}
_ => unreachable!(),
};
}
for kind in ancestors.drain(..).rev() {
if kind != SyntaxKind::Abandoned {
builder.start_node(kind.into());
}
}
}
Event::NodeFinished => builder.finish_node(),
Event::Token { kind, span } => {
builder.token(kind.into(), &source[span.start()..span.end()])
}
}
}
(Self(SyntaxNode::new_root(builder.finish())), diagnostics)
}
pub fn root(&self) -> &SyntaxNode {
&self.0
}
pub fn into_syntax(self) -> SyntaxNode {
self.0
}
}
impl fmt::Display for SyntaxTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Debug for SyntaxTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}