Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic binding generation #264

Closed
wants to merge 131 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
15f80d7
Add initial header translation
madsmtm Sep 4, 2022
c8be96d
Closer to usable
madsmtm Sep 7, 2022
2315c68
Mostly works with NSCursor
madsmtm Sep 7, 2022
197a05e
Mostly works with NSAlert.h
madsmtm Sep 8, 2022
2474385
Refactor a bit
madsmtm Sep 9, 2022
91cc01c
AppKit is now parse-able
madsmtm Sep 9, 2022
d09866c
handle reserved keywords
madsmtm Sep 9, 2022
556a5d8
Handle protocols somewhat
madsmtm Sep 9, 2022
f3093fc
Handle the few remaining entity kinds
madsmtm Sep 9, 2022
fb6096c
Works with Foundation
madsmtm Sep 9, 2022
399afc8
Cleanup
madsmtm Sep 9, 2022
61535ee
Refactor
madsmtm Sep 9, 2022
80a3404
Refactor Method to (almost) be PartialEq
madsmtm Sep 9, 2022
8249f69
Parse more things
madsmtm Sep 9, 2022
236d9d3
Parse NSConsumed
madsmtm Sep 9, 2022
68503bb
Verify memory management
madsmtm Sep 9, 2022
00522fe
More work
madsmtm Sep 9, 2022
5e95345
Fix reserved keywords
madsmtm Sep 9, 2022
bc25f91
Refactor statements
madsmtm Sep 9, 2022
7e35057
Add initial availability
madsmtm Sep 9, 2022
29b7560
Prepare RustType
madsmtm Sep 9, 2022
00b4678
Split RustType up in parse and ToToken part
madsmtm Sep 9, 2022
69a3d46
Add icrate
madsmtm Dec 8, 2022
5956025
Add config files
madsmtm Sep 17, 2022
cb9da7d
Temporarily disable protocol generation
madsmtm Sep 17, 2022
e7d9e13
Generate files
madsmtm Sep 17, 2022
f4165ee
Add initial generated files for Foundation
madsmtm Sep 17, 2022
88f5459
Skip "index" header
madsmtm Sep 17, 2022
0044e4d
Add basic imports
madsmtm Sep 17, 2022
c6a6058
Allow skipping methods
madsmtm Sep 17, 2022
1aecbea
Properly emit `unsafe`
madsmtm Sep 17, 2022
522955a
Make classes public
madsmtm Sep 17, 2022
1a59c17
Rename objc feature flag
madsmtm Sep 17, 2022
9ba52d1
Improve imports somewhat
madsmtm Sep 17, 2022
0d9a20c
Further import improvements
madsmtm Sep 17, 2022
09381b2
Handle basic typedefs
madsmtm Sep 19, 2022
ca1093f
Improve generics handling
madsmtm Sep 19, 2022
ac6a706
Improve pointers to objects
madsmtm Sep 19, 2022
5a4c02f
Refactor RustType::TypeDef
madsmtm Sep 19, 2022
7652279
Mostly support generics
madsmtm Sep 19, 2022
d9f6424
Refactor config setup
madsmtm Sep 19, 2022
3cd224a
Small fixes
madsmtm Sep 19, 2022
fc07a0c
Support nested generics
madsmtm Sep 19, 2022
2b181be
Comment out a bit of debug logging
madsmtm Sep 19, 2022
0cd5ee8
Emit all files
madsmtm Sep 19, 2022
02792f1
Parse sized integer types
madsmtm Sep 19, 2022
5ee3e77
Parse typedefs that map to other typedefs
madsmtm Sep 19, 2022
39b448c
Appease clippy
madsmtm Sep 23, 2022
3bc7009
Add `const`-parsing for RustType::Id
madsmtm Oct 3, 2022
9bdc5b6
Parse Objective-C in/out/inout/bycopy/byref/oneway qualifiers
madsmtm Oct 3, 2022
0aa9211
Fix `id` being emitted when it actually specifies a protocol
madsmtm Oct 6, 2022
78cc5b8
Make AppKit work again
madsmtm Oct 6, 2022
6781ccb
Parse all qualifiers, in particular lifetime qualifiers
madsmtm Oct 6, 2022
932e364
More consistent ObjCObjectPointer parsing
madsmtm Oct 6, 2022
d59a273
Validate some lifetime attributes
madsmtm Oct 6, 2022
ce48683
Fix out parameters (except for NSError)
madsmtm Oct 6, 2022
d0ae01e
Refactor Stmt objc declaration parsing
madsmtm Oct 7, 2022
8e2719c
Clean up how return types work
madsmtm Oct 7, 2022
1be4828
Refactor property parsing
madsmtm Oct 7, 2022
f05e4cb
Add support for functions taking NSError as an out parameter
madsmtm Oct 8, 2022
7ae7089
Change icrate directory layout
madsmtm Dec 8, 2022
eb96988
Refactor slightly
madsmtm Oct 8, 2022
baf2918
Refactor file handling to allow for multiple frameworks simultaneously
madsmtm Oct 8, 2022
7243dba
Put method output inside an extern_methods! call
madsmtm Oct 8, 2022
b7179a7
Use extern_methods! functionality
madsmtm Oct 8, 2022
d197f00
Manually fix the formatting of attribute macros in extern_methods!
madsmtm Oct 9, 2022
e6163d0
Add AppKit bindings
madsmtm Oct 9, 2022
f2585f1
Speed things up by optionally formatting at the end instead
madsmtm Oct 9, 2022
9cbb09e
Prepare for parsing more than one SDK
madsmtm Oct 9, 2022
2d12042
Specify a minimum deployment target
madsmtm Oct 10, 2022
5b2cf14
Document SDK situation
madsmtm Oct 10, 2022
1bf1966
Parse headers on iOS as well
madsmtm Oct 10, 2022
e59d24a
Refactor stmt parsing a bit
madsmtm Oct 24, 2022
7dc5107
Remove Stmt::FileImport and Stmt::ItemImport
madsmtm Oct 29, 2022
74a3615
Do preprocessing step explicitly as the first thing
madsmtm Oct 29, 2022
b5321fb
Refactor so that file writing is done using plain Display
madsmtm Oct 29, 2022
55887dd
Improve whitespace in generated files and add warning header
madsmtm Oct 29, 2022
e31a840
Don't crash on unions
madsmtm Oct 30, 2022
bed5cae
Add initial enum parsing
madsmtm Oct 31, 2022
a901658
Add initial enum expr parsing
madsmtm Oct 31, 2022
73622ef
Add very simple enum output
madsmtm Oct 31, 2022
5233fe9
Fix duplicate enum check
madsmtm Oct 31, 2022
44d568b
Improve enum expr parsing
madsmtm Oct 31, 2022
605a57e
Add static variable parsing
madsmtm Oct 31, 2022
83a5edd
Add a bit of WIP code
madsmtm Oct 31, 2022
b79667a
Add function parsing
madsmtm Oct 31, 2022
533ae24
Fix generic struct generation
madsmtm Nov 1, 2022
75e3082
Make &Class as return type static
madsmtm Nov 1, 2022
13d6f1c
Trim unnecessary parentheses
madsmtm Nov 1, 2022
615c5b2
Fix generics default parameter
madsmtm Nov 1, 2022
a013cd8
Remove methods that are both instance and class methods
madsmtm Nov 1, 2022
f877cf7
Skip protocols that are also classes
madsmtm Nov 1, 2022
c3e10d0
Improve imports setups
madsmtm Nov 1, 2022
10c863b
Bump recursion limit
madsmtm Nov 1, 2022
fb65380
Add MacTypes.h type translation
madsmtm Nov 1, 2022
b95b357
Fix int64_t type translation
madsmtm Nov 1, 2022
4afcce1
Make statics public
madsmtm Nov 1, 2022
639ebdc
Fix init methods
madsmtm Nov 1, 2022
c44ebee
Make __inner_extern_class allowing trailing comma in generics
madsmtm Nov 1, 2022
ecb690f
Attempt to improve Rust's parsing speed of icrate
madsmtm Nov 1, 2022
797a00d
Custom NSObject
madsmtm Nov 1, 2022
e051dd5
TMP import
madsmtm Nov 1, 2022
79f4692
Remove NSProxy
madsmtm Nov 1, 2022
e7d6ab7
Temporarily remove out parameter setup
madsmtm Nov 1, 2022
da25fc0
Add struct support
madsmtm Nov 2, 2022
6afde3a
Add partial support for "related result types"
madsmtm Nov 2, 2022
dee50de
Refactor typedef parsing a bit
madsmtm Nov 2, 2022
3c3c3c4
Output remaining typedefs
madsmtm Nov 2, 2022
67f7efd
Fix Option<Sel> and *mut bool
madsmtm Nov 2, 2022
7885cb3
Fix almost all remaining type errors in Foundation
madsmtm Nov 2, 2022
be5916b
Skip statics whoose value we cannot find
madsmtm Nov 2, 2022
c18ce67
Fix anonymous enum types
madsmtm Nov 2, 2022
d5ff384
Fix AppKit duplicate methods
madsmtm Nov 2, 2022
ff3012f
Add CoreData
madsmtm Dec 8, 2022
8694beb
Properly fix imports
madsmtm Nov 2, 2022
588e17f
Add `abstract` keyword
madsmtm Nov 2, 2022
f495d75
Put enum and static declarations behind a macro
madsmtm Nov 2, 2022
98d8dd8
Add proper IncompleteArray parsing
madsmtm Nov 3, 2022
4e692fe
Refactor type parsing
madsmtm Nov 3, 2022
b2815b4
Make NSError** handling happen in all the places that it does with Swift
madsmtm Nov 3, 2022
7f61929
Refactor Ty a bit more
madsmtm Nov 3, 2022
78fcdd1
Make Display for RustType always sound
madsmtm Nov 3, 2022
d78b975
Add support for function pointers
madsmtm Nov 3, 2022
2d25da2
Add support for block pointers
madsmtm Nov 3, 2022
0bcf7d0
Add extern functions
madsmtm Nov 3, 2022
35988ba
Emit protocol information
madsmtm Nov 3, 2022
2080c5e
Make CoreData compile
madsmtm Nov 4, 2022
baff198
Make AppKit compile
madsmtm Nov 4, 2022
cb00d95
Add support for the AuthenticationServices framework
madsmtm Dec 8, 2022
d1ae521
Do clang < v13 workarounds without modifying sources
madsmtm Nov 24, 2022
1c4c875
Refactor Foundation fixes
madsmtm Dec 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 14 additions & 0 deletions crates/header-translator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "header-translator"
version = "0.1.0"
edition = "2021"
publish = false

repository = "https://github.com/madsmtm/objc2"
license = "Zlib OR Apache-2.0 OR MIT"

[dependencies]
clang = { version = "2.0", features = ["runtime", "clang_10_0"] }
toml = "0.5.9"
serde = { version = "1.0.144", features = ["derive"] }
apple-sdk = { version = "0.2.0", default-features = false }
11 changes: 11 additions & 0 deletions crates/header-translator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Objective-C header translator

For use in making `icrate`.

```console
cargo run --bin header-translator -- /Applications/Xcode.app/Contents/Developer
```

## SDKs

We do not redistribute the relevant SDKs, to hopefully avoid a license violation. You can download the SDKs yourself (they're bundled in XCode) from [Apple's website](https://developer.apple.com/download/all/?q=xcode) (requires an Apple ID).
17 changes: 17 additions & 0 deletions crates/header-translator/framework-includes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Workaround for clang < 13, only used in NSBundle.h
#define NS_FORMAT_ARGUMENT(A)

// Workaround for clang < 13
#define _Nullable_result _Nullable

#include <TargetConditionals.h>

#import <Foundation/Foundation.h>

#import <CoreData/CoreData.h>

#if TARGET_OS_OSX
#import <AppKit/AppKit.h>
#endif

#import <AuthenticationServices/AuthenticationServices.h>
15 changes: 15 additions & 0 deletions crates/header-translator/src/availability.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use clang::PlatformAvailability;

#[derive(Debug, Clone)]
pub struct Availability {
#[allow(dead_code)]
inner: Vec<PlatformAvailability>,
}

impl Availability {
pub fn parse(availability: Vec<PlatformAvailability>) -> Self {
Self {
inner: availability,
}
}
}
108 changes: 108 additions & 0 deletions crates/header-translator/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use std::collections::HashMap;
use std::fs;
use std::io::Result;
use std::path::Path;

use serde::Deserialize;

#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct Config {
#[serde(rename = "class")]
#[serde(default)]
pub class_data: HashMap<String, ClassData>,
#[serde(rename = "protocol")]
#[serde(default)]
pub protocol_data: HashMap<String, ClassData>,
#[serde(rename = "struct")]
#[serde(default)]
pub struct_data: HashMap<String, StructData>,
#[serde(rename = "enum")]
#[serde(default)]
pub enum_data: HashMap<String, EnumData>,
#[serde(rename = "fn")]
#[serde(default)]
pub fns: HashMap<String, FnData>,
#[serde(rename = "static")]
#[serde(default)]
pub statics: HashMap<String, StaticData>,
#[serde(rename = "typedef")]
#[serde(default)]
pub typedef_data: HashMap<String, TypedefData>,
#[serde(default)]
pub imports: Vec<String>,
}

#[derive(Deserialize, Debug, Default, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct ClassData {
#[serde(default)]
pub skipped: bool,
#[serde(rename = "superclass-name")]
#[serde(default)]
pub new_superclass_name: Option<String>,
#[serde(default)]
pub methods: HashMap<String, MethodData>,
#[serde(default)]
pub properties: HashMap<String, MethodData>,
}

#[derive(Deserialize, Debug, Default, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct StructData {
#[serde(default)]
pub skipped: bool,
}

#[derive(Deserialize, Debug, Default, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct EnumData {
#[serde(default)]
pub skipped: bool,
#[serde(rename = "use-value")]
#[serde(default)]
pub use_value: bool,
#[serde(default)]
pub constants: HashMap<String, StructData>,
}

#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct MethodData {
#[serde(rename = "unsafe")]
#[serde(default = "unsafe_default")]
pub unsafe_: bool,
#[serde(default = "skipped_default")]
pub skipped: bool,
// TODO: mutating
}

// TODO
pub type FnData = StructData;
pub type StaticData = StructData;
pub type TypedefData = StructData;

fn unsafe_default() -> bool {
true
}

fn skipped_default() -> bool {
false
}

impl Default for MethodData {
fn default() -> Self {
Self {
unsafe_: unsafe_default(),
skipped: skipped_default(),
}
}
}

impl Config {
pub fn from_file(file: &Path) -> Result<Self> {
let s = fs::read_to_string(file)?;

Ok(toml::from_str(&s)?)
}
}
130 changes: 130 additions & 0 deletions crates/header-translator/src/expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::fmt;
use std::fmt::Write;

use clang::token::TokenKind;
use clang::{Entity, EntityKind, EntityVisitResult};

use crate::unexposed_macro::UnexposedMacro;

#[derive(Clone, Debug, PartialEq)]
pub struct Expr {
s: String,
}

impl Expr {
pub fn from_val((signed, unsigned): (i64, u64), is_signed: bool) -> Self {
let s = if is_signed {
format!("{}", signed)
} else {
format!("{}", unsigned)
};
Expr { s }
}

pub fn parse_enum_constant(entity: &Entity<'_>) -> Option<Self> {
let mut declaration_references = Vec::new();

entity.visit_children(|entity, _parent| {
if let EntityKind::DeclRefExpr = entity.get_kind() {
let name = entity.get_name().expect("expr decl ref name");
declaration_references.push(name);
}
EntityVisitResult::Recurse
});

let mut res = None;

entity.visit_children(|entity, _parent| {
match entity.get_kind() {
EntityKind::UnexposedAttr => {
if let Some(macro_) = UnexposedMacro::parse(&entity) {
panic!("parsed macro in expr: {macro_:?}, {entity:?}");
}
}
_ => {
if res.is_none() {
res = Self::parse(&entity, &declaration_references);
} else {
panic!("found multiple expressions where one was expected");
}
}
}
EntityVisitResult::Continue
});

res
}

pub fn parse_var(entity: &Entity<'_>) -> Option<Self> {
Self::parse(entity, &[])
}

fn parse(entity: &Entity<'_>, declaration_references: &[String]) -> Option<Self> {
let range = entity.get_range().expect("expr range");
let tokens = range.tokenize();

if tokens.is_empty() {
// TODO: Find a better way to parse macros
return None;
}

let mut s = String::new();

for token in &tokens {
match (token.get_kind(), token.get_spelling()) {
(TokenKind::Identifier, ident) => {
if declaration_references.contains(&ident) {
// TODO: Handle these specially when we need to
}
write!(s, "{}", ident).unwrap();
}
(TokenKind::Literal, lit) => {
let lit = lit
.trim_end_matches("UL")
.trim_end_matches("L")
.trim_end_matches("u")
.trim_end_matches("U");
let lit = lit.replace("0X", "0x");
write!(s, "{}", lit).unwrap();
}
(TokenKind::Punctuation, punct) => {
match &*punct {
// These have the same semantics in C and Rust
"(" | ")" | "<<" | "-" | "+" | "|" | "&" | "^" => {
write!(s, "{}", punct).unwrap()
}
// Bitwise not
"~" => write!(s, "!").unwrap(),
punct => panic!("unknown expr punctuation {punct}"),
}
}
(kind, spelling) => panic!("unknown expr token {kind:?}/{spelling}"),
}
}

// Trim casts
s = s
.trim_start_matches("(NSBoxType)")
.trim_start_matches("(NSBezelStyle)")
.trim_start_matches("(NSEventSubtype)")
.trim_start_matches("(NSWindowButton)")
.trim_start_matches("(NSExpressionType)")
.to_string();

// Trim unnecessary parentheses
if s.starts_with('(')
&& s.ends_with(')')
&& s.chars().filter(|&c| c == '(' || c == ')').count() == 2
{
s = s.trim_start_matches("(").trim_end_matches(")").to_string();
}

Some(Self { s })
}
}

impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.s)
}
}