use core::fmt;
use strum::{EnumIs, EnumTryAs};
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Span {
pub start: Position,
pub end: Position,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Position {
pub line: u32,
pub column: u32,
pub offset: u32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PrefixedIriRef {
pub prefix: Option<String>,
pub local: String,
}
#[derive(Clone, Debug, PartialEq, EnumIs, EnumTryAs)]
pub enum IriRef {
Full(String),
Prefixed(PrefixedIriRef),
Namespace(Option<String>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiteralSyntax {
pub lexical_form: String,
pub datatype: Option<IriRef>,
pub lang_tag: Option<String>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, EnumIs, EnumTryAs)]
pub enum Atom {
Iri(IriRef),
NodeId(String),
Literal(LiteralSyntax),
Integer(u32),
Equals,
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionNode {
pub name: String,
pub args: Vec<SyntaxNode>,
}
#[derive(Clone, Debug, PartialEq, EnumIs, EnumTryAs)]
pub enum SyntaxNodeKind {
Comment(String),
Atom(Atom),
Function(FunctionNode),
}
#[derive(Clone, Debug, PartialEq)]
pub struct SyntaxNode {
pub span: Span,
pub kind: SyntaxNodeKind,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SyntaxDocument {
pub nodes: Vec<SyntaxNode>,
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
}
impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.start.line == self.end.line {
write!(
f,
"{}:{}-{}",
self.start.line, self.start.column, self.end.column
)
} else {
write!(f, "{}-{}", self.start, self.end)
}
}
}
impl Span {
pub fn new(start: Position, end: Position) -> Self {
Self { start, end }
}
pub fn at(pos: Position) -> Self {
Self {
start: pos,
end: pos,
}
}
pub fn extend_to(self, other: Span) -> Self {
Self {
start: self.start,
end: other.end,
}
}
}
impl FunctionNode {
pub fn semantic_args(&self) -> impl Iterator<Item = &SyntaxNode> {
self.args.iter().filter(|n| !n.kind.is_comment())
}
}
impl SyntaxNode {
pub fn function_name(&self) -> Option<&str> {
match &self.kind {
SyntaxNodeKind::Function(f) => Some(f.name.as_str()),
_ => None,
}
}
pub fn function_args(&self) -> Option<&[SyntaxNode]> {
match &self.kind {
SyntaxNodeKind::Function(f) => Some(f.args.as_slice()),
_ => None,
}
}
pub fn semantic_args(&self) -> Option<impl Iterator<Item = &SyntaxNode>> {
match &self.kind {
SyntaxNodeKind::Function(f) => Some(f.semantic_args()),
_ => None,
}
}
pub fn try_as_iri_ref(&self) -> Option<&IriRef> {
match &self.kind {
SyntaxNodeKind::Atom(Atom::Iri(r)) => Some(r),
_ => None,
}
}
pub fn try_as_integer(&self) -> Option<u32> {
match &self.kind {
SyntaxNodeKind::Atom(v) => v.try_as_integer_ref().map(|v| *v),
_ => None,
}
}
pub fn as_literal_syntax(&self) -> Option<&LiteralSyntax> {
match &self.kind {
SyntaxNodeKind::Atom(v) => v.try_as_literal_ref(),
_ => None,
}
}
pub fn as_node_id(&self) -> Option<&String> {
match &self.kind {
SyntaxNodeKind::Atom(v) => v.try_as_node_id_ref(),
_ => None,
}
}
}