add initial array support

This commit is contained in:
Xiangpeng Hao 2020-11-12 10:24:18 +08:00
parent bf1000f40e
commit 7876235c3f
11 changed files with 149 additions and 10 deletions

View File

@ -172,6 +172,9 @@ fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
out.include.cstdint = true;
out.builtin.rust_slice = true;
}
Type::Array(_) => {
out.include.array = true;
}
Type::Ref(_) | Type::Void(_) => {}
}
}
@ -902,6 +905,11 @@ fn write_type(out: &mut OutFile, ty: &Type) {
}
write!(out, ")>");
}
Type::Array(a) => {
write!(out, "::std::array<");
write_type(out, &a.inner);
write!(out, ", {}>", &a.len);
}
Type::Void(_) => unreachable!(),
}
}
@ -940,7 +948,8 @@ fn write_space_after_type(out: &mut OutFile, ty: &Type) {
| Type::CxxVector(_)
| Type::RustVec(_)
| Type::SliceRefU8(_)
| Type::Fn(_) => write!(out, " "),
| Type::Fn(_)
| Type::Array(_) => write!(out, " "),
Type::Ref(_) => {}
Type::Void(_) | Type::Slice(_) => unreachable!(),
}

View File

@ -2,7 +2,7 @@ use crate::syntax::atom::Atom::{self, *};
use crate::syntax::report::Errors;
use crate::syntax::types::TrivialReason;
use crate::syntax::{
error, ident, Api, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Signature, Slice,
error, ident, Api, Array, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Signature, Slice,
Struct, Ty1, Type, Types,
};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
@ -35,6 +35,7 @@ fn do_typecheck(cx: &mut Check) {
Type::CxxVector(ptr) => check_type_cxx_vector(cx, ptr),
Type::Ref(ty) => check_type_ref(cx, ty),
Type::Slice(ty) => check_type_slice(cx, ty),
Type::Array(array) => check_type_array(cx, array),
Type::Fn(ty) => check_type_fn(cx, ty),
Type::Str(_) | Type::Void(_) | Type::SliceRefU8(_) => {}
}
@ -181,6 +182,21 @@ fn check_type_slice(cx: &mut Check, ty: &Slice) {
cx.error(ty, "only &[u8] is supported so far, not other slice types");
}
fn check_type_array(cx: &mut Check, ty: &Array) {
match &ty.inner {
Type::Ident(ident) => {
if cx.types.rust.contains(&ident.rust) || cx.types.cxx.contains(&ident.rust) {
cx.error(ty, "Only shared structs are supported in array yet");
}
}
Type::RustBox(ty1) => check_type_box(cx, ty1),
Type::RustVec(ty1) => check_type_rust_vec(cx, ty1),
Type::CxxVector(ty1) => check_type_cxx_vector(cx, ty1),
Type::UniquePtr(ty1) => check_type_unique_ptr(cx, ty1),
_ => cx.error(ty, "unsupported array target type"),
};
}
fn check_type_fn(cx: &mut Check, ty: &Signature) {
if ty.throws {
cx.error(ty, "function pointer returning Result is not supported yet");
@ -480,5 +496,6 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
Type::SliceRefU8(_) => "&[u8]".to_owned(),
Type::Fn(_) => "function pointer".to_owned(),
Type::Void(_) => "()".to_owned(),
Type::Array(_) => "array".to_owned(),
}
}

View File

@ -1,4 +1,4 @@
use crate::syntax::{ExternFn, Impl, Include, Receiver, Ref, Signature, Slice, Ty1, Type};
use crate::syntax::{Array, ExternFn, Impl, Include, Receiver, Ref, Signature, Slice, Ty1, Type};
use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::mem;
@ -50,6 +50,7 @@ impl Hash for Type {
Type::Fn(t) => t.hash(state),
Type::Slice(t) => t.hash(state),
Type::SliceRefU8(t) => t.hash(state),
Type::Array(t) => t.hash(state),
Type::Void(_) => {}
}
}
@ -173,6 +174,37 @@ impl Hash for Slice {
}
}
impl Eq for Array {}
impl PartialEq for Array {
fn eq(&self, other: &Array) -> bool {
let Array {
bracket: _,
inner,
semi_token: _,
len,
} = self;
let Array {
bracket: _,
inner: inner2,
semi_token: _,
len: len2,
} = other;
inner == inner2 && len == len2
}
}
impl Hash for Array {
fn hash<H: Hasher>(&self, state: &mut H) {
let Array {
bracket: _,
inner,
semi_token: _,
len,
} = self;
inner.hash(state);
len.to_string().hash(state);
}
}
impl Eq for Signature {}
impl PartialEq for Signature {

View File

@ -31,6 +31,7 @@ impl<'a> Types<'a> {
| Type::SliceRefU8(_) => Definite(true),
Type::UniquePtr(_) | Type::CxxVector(_) => Definite(false),
Type::Ref(ty) => self.determine_improper_ctype(&ty.inner),
Type::Array(ty) => self.determine_improper_ctype(&ty.inner),
}
}
}

View File

@ -165,6 +165,7 @@ pub enum Type {
Void(Span),
Slice(Box<Slice>),
SliceRefU8(Box<Ref>),
Array(Box<Array>),
}
pub struct Ty1 {
@ -189,6 +190,13 @@ pub struct Slice {
pub inner: Type,
}
pub struct Array {
pub bracket: Bracket,
pub inner: Type,
pub semi_token: Token![;],
pub len: usize,
}
#[derive(Copy, Clone, PartialEq)]
pub enum Lang {
Cxx,

View File

@ -3,7 +3,7 @@ use crate::syntax::file::{Item, ItemForeignMod};
use crate::syntax::report::Errors;
use crate::syntax::Atom::*;
use crate::syntax::{
attrs, error, Api, Doc, Enum, ExternFn, ExternType, Impl, Include, IncludeKind, Lang,
attrs, error, Api, Array, Doc, Enum, ExternFn, ExternType, Impl, Include, IncludeKind, Lang,
Namespace, Pair, Receiver, Ref, ResolvableName, Signature, Slice, Struct, Ty1, Type, TypeAlias,
Var, Variant,
};
@ -12,10 +12,10 @@ use quote::{format_ident, quote, quote_spanned};
use syn::parse::{ParseStream, Parser};
use syn::punctuated::Punctuated;
use syn::{
Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, LitStr, Pat,
PathArguments, Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath,
TypeReference, TypeSlice,
Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
Pat, PathArguments, Result, ReturnType, Token, Type as RustType, TypeArray, TypeBareFn,
TypePath, TypeReference, TypeSlice,
};
pub mod kw {
@ -623,10 +623,49 @@ fn parse_type(ty: &RustType, namespace: &Namespace) -> Result<Type> {
RustType::Slice(ty) => parse_type_slice(ty, namespace),
RustType::BareFn(ty) => parse_type_fn(ty, namespace),
RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
RustType::Array(ty) => parse_type_array(ty, namespace),
_ => Err(Error::new_spanned(ty, "unsupported type")),
}
}
fn parse_type_array(ty: &TypeArray, namespace: &Namespace) -> Result<Type> {
let inner = parse_type(&ty.elem, namespace)?;
match &ty.len {
Expr::Lit(lit) => {
if !lit.attrs.is_empty() {
return Err(Error::new_spanned(
ty,
"attribute not allowed in length field",
));
}
match &lit.lit {
Lit::Int(v) => {
let v = match v.base10_parse::<usize>() {
Ok(n_v) => n_v,
Err(_) => {
return Err(Error::new_spanned(
ty,
"Cannot parse integer literal to base10",
))
}
};
Ok(Type::Array(Box::new(Array {
bracket: ty.bracket_token,
inner,
semi_token: ty.semi_token,
len: v,
})))
}
_ => Err(Error::new_spanned(ty, "length literal must be a integer")),
}
}
_ => Err(Error::new_spanned(
ty,
"only literal is currently supported in len field",
)),
}
}
fn parse_type_reference(ty: &TypeReference, namespace: &Namespace) -> Result<Type> {
let inner = parse_type(&ty.elem, namespace)?;
let which = match &inner {

View File

@ -1,7 +1,7 @@
use crate::syntax::atom::Atom::*;
use crate::syntax::{
Atom, Derive, Enum, ExternFn, ExternType, Impl, Receiver, Ref, ResolvableName, Signature,
Slice, Struct, Ty1, Type, TypeAlias, Var,
Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Receiver, Ref, ResolvableName,
Signature, Slice, Struct, Ty1, Type, TypeAlias, Var,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote_spanned, ToTokens};
@ -22,6 +22,7 @@ impl ToTokens for Type {
}
Type::Ref(r) | Type::Str(r) | Type::SliceRefU8(r) => r.to_tokens(tokens),
Type::Slice(s) => s.to_tokens(tokens),
Type::Array(a) => a.to_tokens(tokens),
Type::Fn(f) => f.to_tokens(tokens),
Type::Void(span) => tokens.extend(quote_spanned!(*span=> ())),
}
@ -68,6 +69,16 @@ impl ToTokens for Ref {
}
}
impl ToTokens for Array {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.bracket.surround(tokens, |tokens| {
self.inner.to_tokens(tokens);
self.semi_token.to_tokens(tokens);
self.len.to_tokens(tokens);
});
}
}
impl ToTokens for Slice {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.bracket.surround(tokens, |tokens| {

View File

@ -49,6 +49,7 @@ impl<'a> Types<'a> {
| Type::RustVec(ty) => visit(all, &ty.inner),
Type::Ref(r) => visit(all, &r.inner),
Type::Slice(s) => visit(all, &s.inner),
Type::Array(a) => visit(all, &a.inner),
Type::Fn(f) => {
if let Some(ret) = &f.ret {
visit(all, ret);

View File

@ -116,6 +116,10 @@ pub mod ffi {
i: i32,
}
pub struct Array {
a: [i32; 4],
}
unsafe extern "C++" {
include!("tests/ffi/tests.h");
@ -204,6 +208,7 @@ pub mod ffi {
fn set_succeed(self: Pin<&mut C>, n: usize) -> Result<usize>;
fn get_fail(self: Pin<&mut C>) -> Result<usize>;
fn c_method_on_shared(self: &Shared) -> usize;
fn c_set_array(self: &mut Array, value: i32);
#[rust_name = "i32_overloaded_method"]
fn cOverloadedMethod(&self, x: i32) -> String;
@ -274,6 +279,7 @@ pub mod ffi {
fn get(self: &R) -> usize;
fn set(self: &mut R, n: usize) -> usize;
fn r_method_on_shared(self: &Shared) -> String;
fn r_get_array_sum(self: &Array) -> i32;
#[cxx_name = "rAliasedFunction"]
fn r_aliased_function(x: i32) -> String;
@ -321,6 +327,12 @@ impl ffi::Shared {
}
}
impl ffi::Array {
pub fn r_get_array_sum(&self) -> i32 {
self.a.iter().sum()
}
}
#[derive(Debug)]
struct Error;

View File

@ -32,6 +32,10 @@ size_t C::get_fail() { throw std::runtime_error("unimplemented"); }
size_t Shared::c_method_on_shared() const noexcept { return 2021; }
void Array::c_set_array(int32_t val) noexcept {
this->a = {val, val, val, val};
}
const std::vector<uint8_t> &C::get_v() const { return this->v; }
std::vector<uint8_t> &C::get_v() { return this->v; }

View File

@ -197,6 +197,11 @@ fn test_c_method_calls() {
);
assert!(unique_ptr.as_mut().unwrap().get_fail().is_err());
assert_eq!(2021, ffi::Shared { z: 0 }.c_method_on_shared());
let val = 42;
let mut array = ffi::Array { a: [0, 0, 0, 0] };
array.c_set_array(val);
assert_eq!(array.a.len() as i32 * val, array.r_get_array_sum());
}
#[test]