use super::expression::{Expression, ExpressionKind};
use crate::{
antlr::{
hamelinparser::{IdentifierContextAll, IdentifierContextAttrs, SimpleIdentifierContextAll},
interval,
},
antlr::{parse_identifier, parse_simple_identifier},
err::TranslationError,
tree::ast::context::{FromCst, ParseContext},
};
use antlr_rust::tree::ParseTree;
use derive_more::derive::{From, TryUnwrap};
use serde::{Deserialize, Serialize};
use std::{
fmt::{Display, Formatter},
hash::{Hash, Hasher},
ops::{Add, RangeInclusive},
rc::Rc,
str::FromStr,
sync::Arc,
};
use super::node::{Span, Spannable};
#[derive(Debug, Clone, PartialEq, From, TryUnwrap, Hash, Eq)]
pub enum Identifier {
Simple(SimpleIdentifier),
Compound(CompoundIdentifier),
}
#[derive(Debug, Clone, PartialEq, From, TryUnwrap, Hash, Eq)]
pub enum ParsedIdentifier {
Valid(Identifier),
Error(Arc<TranslationError>),
}
#[derive(Debug, Clone, PartialEq, From, TryUnwrap, Hash, Eq)]
pub enum ParsedSimpleIdentifier {
Valid(SimpleIdentifier),
Error(Arc<TranslationError>),
}
pub struct IdentifierPrefixes<'a> {
parts: &'a [SimpleIdentifier],
current_len: usize,
}
impl<'a> Iterator for IdentifierPrefixes<'a> {
type Item = Identifier;
fn next(&mut self) -> Option<Self::Item> {
if self.current_len >= self.parts.len() {
return None;
}
let prefix = if self.current_len == 1 {
Identifier::Simple(self.parts[0].clone())
} else {
Identifier::Compound(CompoundIdentifier {
parts: self.parts[0..self.current_len].to_vec(),
})
};
self.current_len += 1;
Some(prefix)
}
}
impl Spannable for Identifier {
fn span(&self) -> Option<RangeInclusive<usize>> {
match self {
Identifier::Simple(s) => s.span(),
Identifier::Compound(c) => c.span(),
}
}
}
impl Display for Identifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Identifier::Simple(s) => write!(f, "{}", s),
Identifier::Compound(c) => write!(f, "{}", c),
}
}
}
impl Serialize for Identifier {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Simple(s) => serializer.serialize_str(&s.to_string()),
Self::Compound(c) => serializer.serialize_str(&c.to_string()),
}
}
}
impl<'de> Deserialize<'de> for Identifier {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
if s.is_empty() {
return Err(serde::de::Error::custom("empty identifier"));
}
Identifier::parse(&s).map_err(serde::de::Error::custom)
}
}
impl FromCst<Rc<IdentifierContextAll<'static>>> for ParsedIdentifier {
fn from_cst_with_context(
cst: Rc<IdentifierContextAll<'static>>,
ctx: &mut ParseContext,
) -> Self {
let simple_idents: Vec<SimpleIdentifier> = match cst
.simpleIdentifier_all()
.into_iter()
.map(|si| ParsedSimpleIdentifier::from_cst_with_context(si.as_ref(), ctx))
.try_fold(Vec::new(), |mut acc, parsed| {
parsed.valid().map(|si| {
acc.push(si);
acc
})
}) {
Ok(idents) => idents,
Err(e) => {
ctx.add_error(e.clone());
return e.into();
}
};
match simple_idents.as_slice() {
[] => {
let err = ctx.error("expected identifier").at(cst.as_ref()).emit();
err.into()
}
[single] => Identifier::Simple(single.clone()).into(),
[first, second, rest @ ..] => {
CompoundIdentifier::new(first.clone(), second.clone(), rest.to_vec()).into()
}
}
}
}
impl ParsedSimpleIdentifier {
pub fn valid_ref(&self) -> Result<&SimpleIdentifier, Arc<TranslationError>> {
match self {
ParsedSimpleIdentifier::Valid(si) => Ok(si),
ParsedSimpleIdentifier::Error(err) => Err(err.clone()),
}
}
pub fn valid(self) -> Result<SimpleIdentifier, Arc<TranslationError>> {
match self {
ParsedSimpleIdentifier::Valid(si) => Ok(si),
ParsedSimpleIdentifier::Error(err) => Err(err),
}
}
}
impl ParsedIdentifier {
pub fn valid_ref(&self) -> Result<&Identifier, Arc<TranslationError>> {
match self {
ParsedIdentifier::Valid(id) => Ok(id),
ParsedIdentifier::Error(err) => Err(err.clone()),
}
}
pub fn valid(self) -> Result<Identifier, Arc<TranslationError>> {
match self {
ParsedIdentifier::Valid(id) => Ok(id),
ParsedIdentifier::Error(err) => Err(err),
}
}
}
impl Display for ParsedIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.valid_ref()
.map(|id| write!(f, "{}", id))
.unwrap_or_else(|_| write!(f, "<error>"))
}
}
impl Spannable for ParsedIdentifier {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.valid_ref().ok().and_then(|id| id.span())
}
}
impl Display for ParsedSimpleIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.valid_ref()
.map(|id| write!(f, "{}", id))
.unwrap_or_else(|_| write!(f, "<error>"))
}
}
impl Spannable for ParsedSimpleIdentifier {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.valid_ref().ok().and_then(|id| id.span())
}
}
impl From<SimpleIdentifier> for ParsedIdentifier {
fn from(si: SimpleIdentifier) -> Self {
ParsedIdentifier::Valid(Identifier::Simple(si))
}
}
impl From<CompoundIdentifier> for ParsedIdentifier {
fn from(ci: CompoundIdentifier) -> Self {
ParsedIdentifier::Valid(Identifier::Compound(ci))
}
}
impl From<ParsedSimpleIdentifier> for ParsedIdentifier {
fn from(value: ParsedSimpleIdentifier) -> Self {
match value {
ParsedSimpleIdentifier::Valid(si) => ParsedIdentifier::Valid(Identifier::Simple(si)),
ParsedSimpleIdentifier::Error(err) => ParsedIdentifier::Error(err),
}
}
}
impl Identifier {
pub fn parse(s: impl Into<String>) -> Result<Self, TranslationError> {
let mut ctx = ParseContext::new();
let cst = parse_identifier(s.into()).map_err(|errors| {
errors
.0
.into_iter()
.next()
.unwrap_or_else(|| ctx.error("cannot parse identifier").emit().as_ref().clone())
})?;
match ParsedIdentifier::from_cst_with_context(cst, &mut ctx) {
ParsedIdentifier::Valid(id) => Ok(id),
ParsedIdentifier::Error(err) => Err((*err).clone()),
}
}
pub fn infer_from_expression(expr: &Expression) -> Option<ParsedIdentifier> {
let current = match &expr.kind {
ExpressionKind::FunctionCall(func_call)
if func_call.positional_args.is_empty() && func_call.named_args.is_empty() =>
{
return Some(match func_call.name.valid_ref() {
Ok(simple_id) => SimpleIdentifier::with_arc_name(simple_id.name.clone()).into(),
Err(err) => err.into(),
});
}
ExpressionKind::TsTrunc(tstrunc) => tstrunc.expression.as_ref(),
ExpressionKind::Cast(cast) => cast.expression.as_ref(),
_ => expr,
};
let mut fields = Vec::new();
let mut inner = current;
while let ExpressionKind::FieldLookup(field_lookup) = &inner.kind {
fields.push(field_lookup.field_identifier.clone());
inner = field_lookup.value.as_ref();
}
match &inner.kind {
ExpressionKind::FieldReference(col_ref) => {
fields.reverse();
match col_ref.field_name.valid_ref() {
Ok(field_name) => {
if fields.is_empty() {
Some(SimpleIdentifier::with_arc_name(field_name.name.clone()).into())
} else {
let mut parts =
vec![SimpleIdentifier::with_arc_name(field_name.name.clone())];
for field in fields {
match field.valid() {
Ok(simple_id) => parts.push(simple_id),
Err(err) => return Some(err.into()),
}
}
Some(CompoundIdentifier { parts }.into())
}
}
Err(err) => Some(err.into()),
}
}
_ => None, }
}
pub fn first(&self) -> SimpleIdentifier {
match self {
Identifier::Simple(s) => s.first(),
Identifier::Compound(c) => c.first(),
}
}
pub fn prefixes(&self) -> IdentifierPrefixes<'_> {
IdentifierPrefixes {
parts: match self {
Identifier::Compound(c) => &c.parts,
_ => &[],
},
current_len: 1,
}
}
pub fn rest(&self) -> Option<Identifier> {
match self {
Identifier::Simple(s) => s.rest(),
Identifier::Compound(c) => Some(c.rest()),
}
}
pub fn last(&self) -> SimpleIdentifier {
match self {
Identifier::Simple(s) => s.last(),
Identifier::Compound(c) => c.last(),
}
}
pub fn has_prefix(&self, prefix: &Identifier) -> bool {
match self {
Identifier::Simple(s) => s.has_prefix(prefix),
Identifier::Compound(c) => c.has_prefix(prefix),
}
}
pub fn strip_prefix(&self, prefix: &Identifier) -> Option<Identifier> {
match self {
Identifier::Simple(s) => s.strip_prefix(prefix),
Identifier::Compound(c) => c.strip_prefix(prefix),
}
}
pub fn segments(&self) -> &[SimpleIdentifier] {
match self {
Identifier::Simple(s) => std::slice::from_ref(s),
Identifier::Compound(c) => &c.parts,
}
}
pub fn from_segments(segments: Vec<SimpleIdentifier>) -> Option<Identifier> {
match segments.as_slice() {
[] => None,
[single] => Some(single.clone().into()),
[first, second, rest @ ..] => {
Some(CompoundIdentifier::new(first.clone(), second.clone(), rest.to_vec()).into())
}
}
}
pub fn prepend(self, prefix: Identifier) -> CompoundIdentifier {
let mut parts = prefix.segments().to_vec();
parts.extend(self.segments().iter().cloned());
CompoundIdentifier { parts }
}
}
#[derive(Debug, Clone)]
pub struct SimpleIdentifier {
pub span: Span,
name: Arc<str>,
}
impl SimpleIdentifier {
pub fn new(name: impl Into<String>) -> Self {
let s: String = name.into();
Self {
span: Span::NONE,
name: Arc::from(s.as_str()),
}
}
pub(crate) fn with_arc_name(name: Arc<str>) -> Self {
Self {
span: Span::NONE,
name,
}
}
pub fn as_str(&self) -> &str {
&self.name
}
pub fn name(&self) -> &str {
&self.name
}
pub fn is_clean(&self) -> bool {
parse_simple_identifier(self.name.to_string()).is_ok()
}
}
impl AsRef<str> for SimpleIdentifier {
fn as_ref(&self) -> &str {
&self.name
}
}
impl PartialEq<str> for SimpleIdentifier {
fn eq(&self, other: &str) -> bool {
&*self.name == other
}
}
impl PartialEq<&str> for SimpleIdentifier {
fn eq(&self, other: &&str) -> bool {
&*self.name == *other
}
}
impl SimpleIdentifier {
pub fn parse(s: impl Into<String>) -> Result<Self, TranslationError> {
let mut ctx = ParseContext::new();
match parse_simple_identifier(s.into()) {
Ok(cst) => {
match ParsedSimpleIdentifier::from_cst_with_context(cst.as_ref(), &mut ctx) {
ParsedSimpleIdentifier::Valid(identifier) => Ok(identifier),
ParsedSimpleIdentifier::Error(err) => Err((*err).clone()),
}
}
Err(parse_errors) => {
let err =
parse_errors.0.into_iter().next().unwrap_or_else(|| {
ctx.error("cant parse identifier").emit().as_ref().clone()
});
Err(err)
}
}
}
}
impl Spannable for SimpleIdentifier {
fn span(&self) -> Option<RangeInclusive<usize>> {
self.span.to_range()
}
}
impl FromCst<&SimpleIdentifierContextAll<'static>> for ParsedSimpleIdentifier {
fn from_cst_with_context(
cst: &SimpleIdentifierContextAll<'static>,
ctx: &mut ParseContext,
) -> Self {
match cst {
SimpleIdentifierContextAll::BackQuotedIdentifierContext(parser_ctx) => {
let text = parser_ctx.get_text();
match text.get(1..text.len() - 1) {
Some(inner) => {
let unescaped = inner.replace("``", "`");
SimpleIdentifier {
span: interval(parser_ctx).into(),
name: ctx.intern(&unescaped),
}
.into()
}
None => {
let err = ctx
.error("invalid backtick identifier")
.at(parser_ctx)
.emit();
err.into()
}
}
}
SimpleIdentifierContextAll::UnquotedIdentifierContext(parser_ctx) => SimpleIdentifier {
span: interval(parser_ctx).into(),
name: ctx.intern(&parser_ctx.get_text()),
}
.into(),
SimpleIdentifierContextAll::Error(parser_ctx) => {
let err = ctx.error("parse_error").at(parser_ctx).emit();
err.into()
}
}
}
}
impl FromStr for Identifier {
type Err = TranslationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl FromStr for SimpleIdentifier {
type Err = TranslationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl From<&str> for SimpleIdentifier {
fn from(s: &str) -> Self {
SimpleIdentifier {
span: Span::NONE,
name: Arc::from(s),
}
}
}
impl PartialEq for SimpleIdentifier {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for SimpleIdentifier {}
impl Hash for SimpleIdentifier {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl Display for SimpleIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_clean() {
write!(f, "{}", self.name)
} else {
let escaped = self.name.replace('`', "``");
write!(f, "`{}`", escaped)
}
}
}
impl Serialize for SimpleIdentifier {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for SimpleIdentifier {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
SimpleIdentifier::parse(s).map_err(serde::de::Error::custom)
}
}
impl SimpleIdentifier {
pub fn first(&self) -> SimpleIdentifier {
self.clone()
}
pub fn rest(&self) -> Option<Identifier> {
None
}
pub fn last(&self) -> SimpleIdentifier {
self.clone()
}
pub fn has_prefix(&self, _prefix: &Identifier) -> bool {
false
}
pub fn strip_prefix(&self, _prefix: &Identifier) -> Option<Identifier> {
None
}
pub fn prepend(self, prefix: Identifier) -> CompoundIdentifier {
let id: Identifier = self.into();
id.prepend(prefix)
}
}
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
pub struct CompoundIdentifier {
parts: Vec<SimpleIdentifier>,
}
impl CompoundIdentifier {
pub fn new(
first: SimpleIdentifier,
second: SimpleIdentifier,
rest: Vec<SimpleIdentifier>,
) -> Self {
let mut parts = vec![first, second];
parts.extend(rest);
Self { parts }
}
pub fn from_two(first: impl Into<String>, second: impl Into<String>) -> Self {
Self {
parts: vec![SimpleIdentifier::new(first), SimpleIdentifier::new(second)],
}
}
}
impl Spannable for CompoundIdentifier {
fn span(&self) -> Option<RangeInclusive<usize>> {
let first_span = self.parts.first()?.span()?;
let last_span = self.parts.last()?.span()?;
Some(*first_span.start()..=*last_span.end())
}
}
impl Display for CompoundIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for (i, part) in self.parts.iter().enumerate() {
if i > 0 {
write!(f, ".")?;
}
write!(f, "{}", part)?;
}
Ok(())
}
}
impl CompoundIdentifier {
pub fn parts(&self) -> &[SimpleIdentifier] {
&self.parts
}
pub fn into_parts(self) -> Vec<SimpleIdentifier> {
self.parts
}
pub fn rest_parts(&self) -> &[SimpleIdentifier] {
&self.parts[1..]
}
pub fn first(&self) -> SimpleIdentifier {
self.parts[0].clone()
}
pub fn rest(&self) -> Identifier {
match &self.parts[1..] {
[single] => single.clone().into(),
parts => CompoundIdentifier {
parts: parts.to_vec(),
}
.into(),
}
}
pub fn last(&self) -> SimpleIdentifier {
self.parts[self.parts.len() - 1].clone()
}
pub fn has_prefix(&self, prefix: &Identifier) -> bool {
match prefix {
Identifier::Simple(prefix_simple) => {
self.parts.len() > 1 && self.parts[0] == *prefix_simple
}
Identifier::Compound(prefix_compound) => {
let prefix_len = prefix_compound.parts().len();
if self.parts.len() <= prefix_len {
return false;
}
for i in 0..prefix_len {
if self.parts[i] != prefix_compound.parts()[i] {
return false;
}
}
true
}
}
}
pub fn strip_prefix(&self, prefix: &Identifier) -> Option<Identifier> {
let mut current: Identifier = self.clone().into();
let mut prefix_current = prefix.clone();
loop {
let c = current.first();
let p = prefix_current.first();
if c == p {
match prefix_current.rest() {
None => {
return current.rest();
}
Some(prefix_rest) => {
match current.rest() {
None => return None, Some(current_rest) => {
current = current_rest;
prefix_current = prefix_rest;
}
}
}
}
} else {
return None;
}
}
}
}
impl Add for Identifier {
type Output = Identifier;
fn add(self, suffix: Identifier) -> Identifier {
suffix.prepend(self).into()
}
}
use crate::sql::expression::identifier::{
CompoundIdentifier as SqlCompoundIdentifier, Identifier as SqlIdentifier,
SimpleIdentifier as SqlSimpleIdentifier,
};
impl From<SqlSimpleIdentifier> for SimpleIdentifier {
fn from(sql_ident: SqlSimpleIdentifier) -> Self {
SimpleIdentifier::new(sql_ident.name)
}
}
impl From<SqlCompoundIdentifier> for CompoundIdentifier {
fn from(sql_ident: SqlCompoundIdentifier) -> Self {
CompoundIdentifier {
parts: sql_ident.into_vec().into_iter().map(|p| p.into()).collect(),
}
}
}
impl From<SqlIdentifier> for Identifier {
fn from(sql_ident: SqlIdentifier) -> Self {
match sql_ident {
SqlIdentifier::Simple(simple) => Identifier::Simple(simple.into()),
SqlIdentifier::Compound(compound) => Identifier::Compound(compound.into()),
}
}
}
impl From<SqlSimpleIdentifier> for Identifier {
fn from(sql_ident: SqlSimpleIdentifier) -> Self {
Identifier::Simple(sql_ident.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{tree::builder::*, types::STRING};
fn identifier_from_expr(expr: &Expression) -> Identifier {
match Identifier::infer_from_expression(expr) {
Some(ParsedIdentifier::Valid(identifier)) => identifier,
Some(ParsedIdentifier::Error(e)) => panic!("expected valid identifier, got {:?}", e),
None => panic!("could not infer identifier from expression"),
}
}
#[test]
fn test_simple_identifier_creation() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("test").into();
match id {
Identifier::Simple(simple) => {
assert!(simple == "test");
assert!(simple.span.is_none());
}
_ => panic!("Expected simple identifier"),
}
}
#[test]
fn test_compound_identifier_creation() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("schema").dot("table").into();
match id {
Identifier::Compound(compound) => {
assert_eq!(compound.parts().len(), 2);
assert!(compound.parts()[0] == "schema");
assert!(compound.parts()[1] == "table");
}
_ => panic!("Expected compound identifier"),
}
}
#[test]
fn test_compound_identifier_with_three_parts() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("catalog").dot("schema").dot("table").into();
match id {
Identifier::Compound(compound) => {
assert_eq!(compound.parts().len(), 3);
assert!(compound.parts()[0] == "catalog");
assert!(compound.parts()[1] == "schema");
assert!(compound.parts()[2] == "table");
}
_ => panic!("Expected compound identifier"),
}
}
#[test]
fn test_identifier_from_column_reference() {
let expr = field_ref("foo").build();
let ident = identifier_from_expr(&expr);
match ident {
Identifier::Simple(s) => assert!(s == "foo"),
_ => panic!("Expected Simple identifier"),
}
}
#[test]
fn test_identifier_from_field_access_two_levels() {
let expr = field(field_ref("foo"), "bar").build();
let ident = identifier_from_expr(&expr);
match ident {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 2);
assert!(c.parts()[0] == "foo");
assert!(c.parts()[1] == "bar");
}
_ => panic!("Expected Compound identifier"),
}
}
#[test]
fn test_identifier_from_field_access_three_levels() {
let expr = field(field(field_ref("foo"), "bar"), "baz").build();
let ident = identifier_from_expr(&expr);
match ident {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 3);
assert!(c.parts()[0] == "foo");
assert!(c.parts()[1] == "bar");
assert!(c.parts()[2] == "baz");
}
_ => panic!("Expected Compound identifier"),
}
}
#[test]
fn test_identifier_from_zero_arg_function() {
let expr = call("now").build();
let ident = identifier_from_expr(&expr);
match ident {
Identifier::Simple(s) => assert!(s == "now"),
_ => panic!("Expected Simple identifier from zero-arg function"),
}
}
#[test]
fn test_identifier_from_cast() {
let expr = cast(field_ref("foo"), STRING).build();
let ident = identifier_from_expr(&expr);
match ident {
Identifier::Simple(s) => assert!(s == "foo"),
_ => panic!("Expected Simple identifier from cast"),
}
}
#[test]
fn test_identifier_from_cast_with_field_access() {
let expr = cast(field(field_ref("foo"), "bar"), STRING).build();
let ident = identifier_from_expr(&expr);
match ident {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 2);
assert!(c.parts()[0] == "foo");
assert!(c.parts()[1] == "bar");
}
_ => panic!("Expected Compound identifier from cast of field access"),
}
}
#[test]
fn test_identifier_first() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("x").into();
let first = id.first();
assert!(first == "x");
let id: Identifier = ident("x").dot("y").into();
let first = id.first();
assert!(first == "x");
}
#[test]
fn test_identifier_rest() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("x").into();
assert_eq!(id.rest(), None);
let id: Identifier = ident("x").dot("y").into();
match id.rest() {
Some(Identifier::Simple(s)) => assert!(s == "y"),
_ => panic!("Expected Simple identifier"),
}
let id: Identifier = ident("x").dot("y").dot("z").into();
match id.rest() {
Some(Identifier::Compound(c)) => {
assert_eq!(c.parts.len(), 2);
assert!(c.parts()[0] == "y");
assert!(c.parts()[1] == "z");
}
_ => panic!("Expected Compound identifier"),
}
}
#[test]
fn test_identifier_last() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("x").into();
let last = id.last();
assert!(last == "x");
let id: Identifier = ident("x").dot("y").into();
let last = id.last();
assert!(last == "y");
let id: Identifier = ident("x").dot("y").dot("z").into();
let last = id.last();
assert!(last == "z");
}
#[test]
fn test_identifier_has_prefix() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("x").dot("y").dot("z").into();
let prefix: Identifier = ident("x").dot("y").into();
assert!(id.has_prefix(&prefix));
let id: Identifier = ident("x").dot("y").into();
let prefix: Identifier = ident("x").into();
assert!(id.has_prefix(&prefix));
let id: Identifier = ident("x").into();
let prefix: Identifier = ident("x").into();
assert!(!id.has_prefix(&prefix));
let id: Identifier = ident("x").into();
let prefix: Identifier = ident("y").into();
assert!(!id.has_prefix(&prefix));
let id: Identifier = ident("x").into();
let prefix: Identifier = ident("x").dot("y").into();
assert!(!id.has_prefix(&prefix));
let id: Identifier = ident("x").dot("y").dot("z").into();
let prefix: Identifier = ident("x").into();
assert!(id.has_prefix(&prefix));
let id: Identifier = ident("x").dot("y").into();
let prefix: Identifier = ident("x").dot("z").into();
assert!(!id.has_prefix(&prefix));
}
#[test]
fn test_identifier_strip_prefix() {
use crate::tree::builder::identifier::ident;
let id: Identifier = ident("x").dot("y").dot("z").into();
let prefix: Identifier = ident("x").dot("y").into();
match id.strip_prefix(&prefix) {
Some(Identifier::Simple(s)) => assert!(s == "z"),
_ => panic!("Expected Some(Simple(z))"),
}
let id: Identifier = ident("x").dot("y").into();
let prefix: Identifier = ident("x").into();
match id.strip_prefix(&prefix) {
Some(Identifier::Simple(s)) => assert!(s == "y"),
_ => panic!("Expected Some(Simple(y))"),
}
let id: Identifier = ident("x").into();
let prefix: Identifier = ident("x").into();
assert_eq!(id.strip_prefix(&prefix), None);
let id: Identifier = ident("x").into();
let prefix: Identifier = ident("y").into();
assert_eq!(id.strip_prefix(&prefix), None);
let id: Identifier = ident("x").into();
let prefix: Identifier = ident("x").dot("y").into();
assert_eq!(id.strip_prefix(&prefix), None);
}
#[test]
fn test_identifier_add() {
use crate::tree::builder::identifier::ident;
let prefix: Identifier = ident("x").into();
let suffix: Identifier = ident("y").into();
let result = prefix + suffix;
match result {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 2);
assert!(c.parts()[0] == "x");
assert!(c.parts()[1] == "y");
}
_ => panic!("Expected Compound identifier"),
}
let prefix: Identifier = ident("x").into();
let suffix: Identifier = ident("y").dot("z").into();
let result = prefix + suffix;
match result {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 3);
assert!(c.parts()[0] == "x");
assert!(c.parts()[1] == "y");
assert!(c.parts()[2] == "z");
}
_ => panic!("Expected Compound identifier"),
}
let prefix: Identifier = ident("x").dot("y").into();
let suffix: Identifier = ident("z").into();
let result = prefix + suffix;
match result {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 3);
assert!(c.parts()[0] == "x");
assert!(c.parts()[1] == "y");
assert!(c.parts()[2] == "z");
}
_ => panic!("Expected Compound identifier"),
}
let prefix: Identifier = ident("x").dot("y").into();
let suffix: Identifier = ident("z").dot("a").into();
let result = prefix + suffix;
match result {
Identifier::Compound(c) => {
assert_eq!(c.parts.len(), 4);
assert!(c.parts()[0] == "x");
assert!(c.parts()[1] == "y");
assert!(c.parts()[2] == "z");
assert!(c.parts()[3] == "a");
}
_ => panic!("Expected Compound identifier"),
}
}
}