use std::{io, iter, slice};
use crate::{
parse::{read, Options, Parser, Position, Result},
Cons, Value,
};
#[derive(Debug, Clone, PartialEq)]
pub struct Datum {
value: Value,
info: SpanInfo,
}
impl Datum {
pub(crate) fn into_inner(self) -> (Value, SpanInfo) {
(self.value, self.info)
}
pub fn value(&self) -> &Value {
&self.value
}
pub fn span(&self) -> Span {
self.info.span()
}
pub fn as_ref(&self) -> Ref<'_> {
Ref {
value: &self.value,
info: &self.info,
}
}
pub fn list_iter(&self) -> Option<ListIter<'_>> {
self.as_ref().list_iter()
}
pub fn vector_iter(&self) -> Option<VectorIter<'_>> {
self.as_ref().vector_iter()
}
pub(crate) fn primitive(value: Value, start: Position, end: Position) -> Self {
Datum {
value,
info: SpanInfo::Prim(Span { start, end }),
}
}
pub(crate) fn vec(
elements: Vec<Value>,
element_info: Vec<SpanInfo>,
start: Position,
end: Position,
) -> Self {
Datum {
value: Value::Vector(elements.into()),
info: SpanInfo::Vec(Span { start, end }, element_info),
}
}
pub(crate) fn cons(cell: Cons, meta: [SpanInfo; 2], start: Position, end: Position) -> Self {
Datum {
value: Value::Cons(cell),
info: SpanInfo::Cons(Span::new(start, end), Box::new(meta)),
}
}
pub(crate) fn quotation(name: &str, quoted: Datum, quote_span: Span) -> Self {
let (quoted_value, quoted_info) = quoted.into_inner();
let quoted_end = quoted_info.span().end();
let null_span = Span::new(quoted_end, quoted_end);
Datum {
value: Value::list(vec![Value::symbol(name), quoted_value]),
info: SpanInfo::Cons(
Span::new(quote_span.start(), quoted_end),
Box::new([
SpanInfo::Prim(quote_span),
SpanInfo::Cons(
quoted_info.span(),
Box::new([quoted_info, SpanInfo::Prim(null_span)]),
),
]),
),
}
}
}
impl From<Datum> for Value {
fn from(datum: Datum) -> Self {
datum.value
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Ref<'a> {
value: &'a Value,
info: &'a SpanInfo,
}
impl<'a> AsRef<Value> for Ref<'a> {
fn as_ref(&self) -> &Value {
self.value
}
}
impl<'a> From<Ref<'a>> for Datum {
fn from(r: Ref<'a>) -> Self {
Datum {
value: r.value.clone(),
info: r.info.clone(),
}
}
}
impl<'a> Ref<'a> {
fn new(value: &'a Value, info: &'a SpanInfo) -> Self {
Ref { value, info }
}
pub fn span(&self) -> Span {
self.info.span()
}
pub fn value(&self) -> &'a Value {
self.value
}
pub fn list_iter(&self) -> Option<ListIter<'a>> {
match (self.value, self.info) {
(Value::Cons(cell), SpanInfo::Cons(_, meta)) => Some(ListIter::cons(cell, meta)),
(Value::Null, _) => Some(ListIter::empty()),
_ => None,
}
}
pub fn vector_iter(&self) -> Option<VectorIter<'a>> {
match (self.value, self.info) {
(Value::Vector(elements), SpanInfo::Vec(_, element_meta)) => {
Some(VectorIter(elements.iter().zip(element_meta)))
}
_ => None,
}
}
pub fn as_pair(&self) -> Option<(Ref<'a>, Ref<'a>)> {
let (car, cdr) = self.value.as_pair()?;
match &self.info {
SpanInfo::Cons(_, inner) if inner.len() == 2 => {
Some((Ref::new(car, &inner[0]), Ref::new(cdr, &inner[1])))
}
_ => unreachable!("badly shaped pair span information"),
}
}
}
impl<'a> std::ops::Deref for Ref<'a> {
type Target = Value;
fn deref(&self) -> &Self::Target {
self.value
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span {
start: Position,
end: Position,
}
impl Span {
pub(crate) fn new(start: Position, end: Position) -> Self {
Span { start, end }
}
pub(crate) fn empty() -> Self {
Span {
start: Position::new(0, 0),
end: Position::new(0, 0),
}
}
pub fn start(&self) -> Position {
self.start
}
pub fn end(&self) -> Position {
self.end
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum SpanInfo {
Prim(Span),
Cons(Span, Box<[SpanInfo; 2]>),
Vec(Span, Vec<SpanInfo>),
}
impl SpanInfo {
fn span(&self) -> Span {
match self {
SpanInfo::Prim(span) => *span,
SpanInfo::Cons(span, _) => *span,
SpanInfo::Vec(span, _) => *span,
}
}
pub(crate) fn cons_mut(&mut self) -> Option<&mut [SpanInfo; 2]> {
match self {
SpanInfo::Cons(_, info) => Some(info),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct VectorIter<'a>(iter::Zip<slice::Iter<'a, Value>, slice::Iter<'a, SpanInfo>>);
impl<'a> Iterator for VectorIter<'a> {
type Item = Ref<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(value, info)| Ref { value, info })
}
}
#[derive(Debug, Clone)]
pub struct ListIter<'a>(ListCursor<'a>);
impl<'a> ListIter<'a> {
pub fn is_empty(&self) -> bool {
matches!(&self.0, ListCursor::Exhausted)
}
pub fn peek(&self) -> Option<Ref<'_>> {
match &self.0 {
ListCursor::Cons(cell, info) => Some(Ref {
value: cell.car(),
info: &info[0],
}),
ListCursor::Dot(_, _) => None,
ListCursor::Rest(value, info) => Some(Ref { value, info }),
ListCursor::Exhausted => None,
}
}
fn empty() -> Self {
ListIter(ListCursor::Exhausted)
}
fn cons(cell: &'a Cons, meta: &'a [SpanInfo; 2]) -> Self {
ListIter(ListCursor::Cons(cell, meta))
}
}
#[derive(Debug, Clone)]
enum ListCursor<'a> {
Cons(&'a Cons, &'a [SpanInfo; 2]),
Dot(&'a Value, &'a SpanInfo),
Rest(&'a Value, &'a SpanInfo),
Exhausted,
}
impl<'a> Iterator for ListIter<'a> {
type Item = Ref<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self.0 {
ListCursor::Cons(cell, [car_meta, cdr_meta]) => {
let car = cell.car();
match cdr_meta {
SpanInfo::Cons(_, next) => {
let cell = cell
.cdr()
.as_cons()
.expect("badly shaped list span information");
self.0 = ListCursor::Cons(cell, next);
}
SpanInfo::Prim(_) if cell.cdr().is_null() => {
self.0 = ListCursor::Exhausted;
}
_ => {
self.0 = ListCursor::Dot(cell.cdr(), cdr_meta);
}
}
Some(Ref {
value: car,
info: car_meta,
})
}
ListCursor::Dot(value, info) => {
self.0 = ListCursor::Rest(value, info);
None
}
ListCursor::Rest(value, info) => {
self.0 = ListCursor::Exhausted;
Some(Ref { value, info })
}
ListCursor::Exhausted => None,
}
}
}
fn from_trait<'de, R>(read: R, options: Options) -> Result<Datum>
where
R: read::Read<'de>,
{
let mut parser = Parser::with_options(read, options);
let datum = parser.expect_datum()?;
parser.expect_end()?;
Ok(datum)
}
pub fn from_reader_custom(rdr: impl io::Read, options: Options) -> Result<Datum> {
from_trait(read::IoRead::new(rdr), options)
}
pub fn from_reader(rdr: impl io::Read) -> Result<Datum> {
from_reader_custom(rdr, Options::default())
}
pub fn from_reader_elisp(rdr: impl io::Read) -> Result<Datum> {
from_reader_custom(rdr, Options::elisp())
}
pub fn from_slice_custom(bytes: &[u8], options: Options) -> Result<Datum> {
from_trait(read::SliceRead::new(bytes), options)
}
pub fn from_slice(bytes: &[u8]) -> Result<Datum> {
from_slice_custom(bytes, Options::default())
}
pub fn from_slice_elisp(bytes: &[u8]) -> Result<Datum> {
from_slice_custom(bytes, Options::elisp())
}
pub fn from_str_custom(s: &str, options: Options) -> Result<Datum> {
from_trait(read::StrRead::new(s), options)
}
pub fn from_str(s: &str) -> Result<Datum> {
from_str_custom(s, Options::default())
}
pub fn from_str_elisp(s: &str) -> Result<Datum> {
from_str_custom(s, Options::elisp())
}