use codespan::Span;
use std::borrow::Cow;
use std::fmt;
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::Deref;
use thiserror::Error;
use uuid::Uuid;
#[derive(Debug, Clone)]
pub struct File {
pub elements: Vec<Toplevel>,
}
impl File {
pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
for el in self.elements.iter() {
el.visit_type_idents(&mut f);
}
}
}
#[derive(Debug, Clone)]
pub enum Toplevel {
Import(Vec<Sp<String>>),
Include(Vec<Sp<String>>),
Interface(Interface),
Typelib(Typelib),
Enum(Enum),
CppQuote(String),
}
impl Toplevel {
pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
match self {
Toplevel::Import(_) => {}
Toplevel::Include(_) => {}
Toplevel::Interface(el) => el.visit_type_idents(&mut f),
Toplevel::Typelib(_) => {}
Toplevel::Enum(_) => {}
Toplevel::CppQuote(_) => {}
}
}
}
#[derive(Debug, Clone)]
pub struct Interface {
pub name: String,
pub attrs: Vec<ItfAttr>,
pub defn: Option<InterfaceDefn>,
}
#[derive(Debug, Clone)]
pub struct InterfaceDefn {
pub base: Option<Sp<String>>,
pub elems: Vec<Function>,
}
impl Interface {
pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
let Some(InterfaceDefn { base, elems, .. }) = &self.defn else {
return;
};
if let Some(el) = base {
f(el);
}
for el in elems.iter() {
el.visit_type_idents(&mut f);
}
}
pub fn guid(&self) -> Option<Uuid> {
for a in self.attrs.iter() {
match a {
Attr::Uuid(id) => return Some(*id),
_ => {}
}
}
None
}
}
#[derive(Debug, Clone)]
pub struct Enum {
pub name: String,
}
#[derive(Debug, Clone)]
pub enum Attr {
Default,
Dual,
HelpString(String),
Local,
Object,
OleAutomation,
PointerDefault(PointerType),
Restricted,
Uuid(Uuid),
Version(u16, u16),
}
pub type ItfAttr = Attr;
pub type TlbAttr = Attr;
pub type ClassAttr = Attr;
#[derive(Debug, Clone)]
pub struct Typelib {
pub name: String,
pub attrs: Vec<TlbAttr>,
pub elems: Vec<TlbElem>,
}
#[derive(Debug, Clone)]
pub enum TlbElem {
ImportLib(String),
Interface(Interface),
Class(Class),
}
#[derive(Debug, Clone)]
pub struct Class {
pub name: String,
pub attrs: Vec<ClassAttr>,
pub elems: Vec<ClassElem>,
}
#[derive(Debug, Clone)]
pub enum ClassElem {
Interface(Interface),
}
#[derive(Debug, Clone, Copy)]
pub enum PointerType {
Unique,
Ref,
Ptr,
}
#[derive(Debug, Clone)]
pub struct Function {
pub attrs: Vec<FnAttr>,
pub ret: Ctype,
pub name: String,
pub args: Vec<FnArg>,
}
impl Function {
pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
self.ret.visit_type_idents(&mut f);
for el in self.args.iter() {
el.visit_type_idents(&mut f);
}
}
}
#[derive(Debug, Clone)]
pub enum FnAttr {
PointerType(PointerType),
PropGet,
PropPut,
PropPutRef,
}
#[derive(Debug, Clone)]
pub struct FnArg {
pub attrs: Vec<Sp<ArgAttr>>,
pub name: Option<Sp<String>>,
pub ty: Sp<Ctype>,
pub arr: bool,
}
impl FnArg {
pub fn visit_type_idents<F: FnMut(&str)>(&self, f: F) {
self.ty.visit_type_idents(f);
}
}
#[derive(Debug, Clone)]
pub enum ArgAttr {
In,
MaxIs(Vec<Option<Cexpr>>),
Out,
PointerType(PointerType),
Poly(String),
RetVal,
SizeIs(Vec<Option<Cexpr>>),
}
#[derive(Debug, Clone)]
pub enum Cexpr {
Ident(String),
Deref(Box<Cexpr>),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Ctype {
pub typename: String,
pub is_const: bool,
pub indirection: Vec<Ptr>,
}
impl Ctype {
pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
f(&self.typename);
}
pub fn is_void(&self) -> bool {
&self.typename == "void" && self.indirection.is_empty()
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Ptr {
pub is_const: bool,
}
#[derive(Debug, Clone)]
pub struct Str<'a>(Vec<StrComponent<'a>>);
#[derive(Debug, Clone)]
pub enum StrComponent<'a> {
Literal(&'a str),
Esc(char),
}
impl<'a> StrComponent<'a> {
fn len(&self) -> usize {
match self {
StrComponent::Literal(v) => v.len(),
StrComponent::Esc(v) => v.len_utf8(),
}
}
}
impl<'a> Str<'a> {
pub fn from_str(s: &'a str) -> Result<Self, StrError> {
let mut state = Vec::new();
let mut iter = s.char_indices();
while let Some((pos, ch)) = iter.next() {
if ch == '\\' {
let (_, esc_type) = iter.next().ok_or(StrError::PartialEscape)?;
if esc_type == 'u' || esc_type == 'U' {
let size = if esc_type == 'u' { 4 } else { 8 };
let (from, _) = iter.next().ok_or(StrError::PartialEscape)?;
for _ in 2..size {
let _ = iter.next().ok_or(StrError::PartialEscape)?;
}
let (to, last) = iter.next().ok_or(StrError::PartialEscape)?;
let to = to + last.len_utf8();
let spec = &s[from..to];
let num = u32::from_str_radix(s, 16)
.map_err(|_| StrError::InvalidUnicode(from, spec.to_owned(), to))?;
state.push(StrComponent::Esc(
char::from_u32(num as u32).ok_or(StrError::InvalidUnicode(
from,
spec.to_owned(),
to,
))?,
));
} else if esc_type == 'n' {
state.push(StrComponent::Esc('\n'));
} else if esc_type == 'r' {
state.push(StrComponent::Esc('\r'));
} else if esc_type == 't' {
state.push(StrComponent::Esc('\t'));
} else if esc_type == '0' {
state.push(StrComponent::Esc('\0'));
}
} else {
if let Some(StrComponent::Literal(ref mut lit)) = state.last_mut() {
let diff = lit.as_ptr() as usize - s.as_ptr() as usize;
*lit = &s[diff..diff + lit.len() + ch.len_utf8()];
} else {
state.push(StrComponent::Literal(&s[pos..pos + ch.len_utf8()]));
}
}
}
Ok(Str(state))
}
fn to_string(&self) -> String {
let len = self.0.iter().map(|v| v.len()).sum();
let mut s = String::with_capacity(len);
for el in self.0.iter() {
match el {
StrComponent::Literal(v) => s.push_str(v.as_ref()),
StrComponent::Esc(v) => s.push(*v),
}
}
s
}
pub fn to_str(&self) -> Cow<str> {
match &*self.0 {
[] => Cow::Borrowed(""),
[StrComponent::Literal(s)] => Cow::Borrowed(s.as_ref()),
_ => Cow::Owned(self.to_string()),
}
}
}
impl<'a> Display for Str<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for el in self.0.iter() {
match el {
StrComponent::Literal(v) => write!(f, "{}", v)?,
StrComponent::Esc(v) => write!(f, "{}", v)?,
}
}
Ok(())
}
}
#[derive(Debug, Error)]
pub enum StrError {
#[error("partial escape sequence")]
PartialEscape,
#[error("invalid unicode escape: {1}")]
InvalidUnicode(usize, String, usize),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Sp<T> {
inner: T,
span: Span,
}
impl<T> Deref for Sp<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T, R> AsRef<R> for Sp<T>
where
T: AsRef<R>,
R: ?Sized,
{
fn as_ref(&self) -> &R {
self.inner.as_ref()
}
}
impl<T> Sp<T> {
pub fn new(inner: T, left: usize, right: usize) -> Self {
Self::new_from_span(inner, Span::new(left as u32, right as u32))
}
pub fn new_from_span(inner: T, span: Span) -> Self {
Self { inner, span }
}
pub fn inner(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn span(&self) -> Span {
self.span
}
pub fn map<F, R>(self, f: F) -> Sp<R>
where
F: FnOnce(T) -> R,
{
Sp {
inner: f(self.inner),
span: self.span,
}
}
}