diff --git a/.github/workflows/ffigenpad.yml b/.github/workflows/ffigenpad.yml new file mode 100644 index 0000000000..b8fe761839 --- /dev/null +++ b/.github/workflows/ffigenpad.yml @@ -0,0 +1,73 @@ +name: ffigenpad + +on: + pull_request: + branches: [main] + paths: + - ".github/workflows/ffigenpad.yaml" + - "pkgs/ffigenpad/**" + push: + branches: [main] + paths: + - ".github/workflows/ffigenpad.yaml" + - "pkgs/ffigenpad/**" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 + + - uses: dart-lang/setup-dart@e9a814f39d5452701455a47847735e0f482026c8 + with: + sdk: dev + + - run: dart pub get + working-directory: pkgs/ffigenpad + + - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 + with: + version: 3.1.61 + + - name: setup ffigenpad + working-directory: pkgs/ffigenpad + run: dart run tool/setup.dart + + - name: build libclang.wasm + working-directory: pkgs/ffigenpad + run: dart run tool/build_libclang.dart --optimize + + - name: build ffigenpad + working-directory: pkgs/ffigenpad + run: | + dart compile wasm ./lib/ffigenpad.dart -o ./bin/ffigenpad.wasm -O3 \ + --extra-compiler-option=--enable-experimental-ffi \ + --extra-compiler-option=--enable-experimental-wasm-interop + + - uses: pnpm/action-setup@ac5bf11548bf5e19b8aadb8182072616590fa4a6 + with: + version: 9.7.0 + run_install: | + - cwd: pkgs/ffigenpad/web + + - uses: actions/configure-pages@aabcbc432d6b06d1fd5e8bf3cf756880c35e014d + + - name: build website + working-directory: pkgs/ffigenpad/web + run: pnpm build + + - uses: actions/upload-pages-artifact@1780dfc2cece65a782cc86fa133f96aef8ad0345 + with: + path: pkgs/ffigenpad/web/dist + + deploy: + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/deploy-pages@b74272834adc04f971da4b0b055c49fa8d7f90c9 diff --git a/pkgs/ffigenpad/CHANGELOG.md b/pkgs/ffigenpad/CHANGELOG.md new file mode 100644 index 0000000000..a0712a79e7 --- /dev/null +++ b/pkgs/ffigenpad/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.1.0 + +- Initial version. diff --git a/pkgs/ffigenpad/README.md b/pkgs/ffigenpad/README.md new file mode 100644 index 0000000000..6db336197f --- /dev/null +++ b/pkgs/ffigenpad/README.md @@ -0,0 +1,63 @@ +# FFIgenPad + +A web interface in which you paste a C header in a textbox on the left, and it outputs `dart:ffi` bindings generated by `package:ffigen` in a textbox on the right. (Inspiration is https://godbolt.org/ which does this for a C file on the left and assembly on the right.) + +It doesn't need a server cause it compiles the Dart code in `package:ffigen` and libclang to WASM. That way everything can run in the browser. + +------ + +## Project Structure + +Most of the files in `lib/src/` are copied from the source of *ffigen* with modifications to make it compatible with dart2wasm (many of the workarounds are listed in [this blog article](https://thecomputerm.hashnode.dev/dirty-deeds-done-dart-cheap-experiments-with-dart2wasm)). + +However the files listed do not have an ffigen counterpart: +- [./lib/ffigenpad.dart](./lib/ffigenpad.dart) +- [./lib/memfs.dart](./lib/memfs.dart) +- [./lib/src/header_parser/calloc.dart](./lib/src/header_parser/calloc.dart) +- [./lib/src/header_parser/clang_bindings/clang_types.dart](./lib/src/header_parser/clang_bindings/clang_types.dart) +- [./lib/src/header_parser/clang_bindings/clang_wrapper.dart](./lib/src/header_parser/clang_bindings/clang_wrapper.dart) + +## Building + +### Prerequisites + +- dart +- emscripten (>= 3.1.61) +- for website + - nodejs (>= ^20.17.0) + - pnpm (optional but recommended) + +### Steps + +- Run `tool/setup.dart` to download LLVM archive files to build *libclang.wasm* + +```sh +# in project root +dart run tool/setup.dart +``` + +- Run `tool/build_libclang.dart` to build *libclang.wasm* using functions exported from *third_party/libclang/libclang.exports* + +```sh +# in project root +dart run tool/build_libclang.dart +``` + +- Build FFIgenPad using the experimental dart2wasm compiler + +```sh +# in project root +dart compile wasm ./lib/ffigenpad.dart -o ./bin/ffigenpad.wasm \ + --extra-compiler-option=--enable-experimental-ffi \ + --extra-compiler-option=--enable-experimental-wasm-interop +``` + +- To build the website + +```sh +# in project root +cd web +npm i # install dependencies +npm run build +# preview with: npm run preview +``` diff --git a/pkgs/ffigenpad/analysis_options.yaml b/pkgs/ffigenpad/analysis_options.yaml new file mode 100644 index 0000000000..558786eefd --- /dev/null +++ b/pkgs/ffigenpad/analysis_options.yaml @@ -0,0 +1,33 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:dart_flutter_team_lints/analysis_options.yaml + +# Uncomment the following section to specify additional rules. + +linter: + rules: + implementation_imports: false + +analyzer: + errors: + todo: ignore + language: + strict-casts: true + strict-inference: true + strict-raw-types: true +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/pkgs/ffigenpad/bin/.gitignore b/pkgs/ffigenpad/bin/.gitignore new file mode 100644 index 0000000000..dcc2bd5c07 --- /dev/null +++ b/pkgs/ffigenpad/bin/.gitignore @@ -0,0 +1,3 @@ +*.wasm +*.mjs +*.wasm.map diff --git a/pkgs/ffigenpad/bin/README.md b/pkgs/ffigenpad/bin/README.md new file mode 100644 index 0000000000..e7686af554 --- /dev/null +++ b/pkgs/ffigenpad/bin/README.md @@ -0,0 +1,3 @@ +# Overview + +Contains build outputs for *libclang.wasm* and *ffigenpad.wasm*. diff --git a/pkgs/ffigenpad/lib/ffigenpad.dart b/pkgs/ffigenpad/lib/ffigenpad.dart new file mode 100644 index 0000000000..8f0a6c5482 --- /dev/null +++ b/pkgs/ffigenpad/lib/ffigenpad.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; + +import 'package:logging/logging.dart'; +import 'package:yaml/yaml.dart'; + +import 'memfs.dart'; +import 'src/config_provider.dart'; +import 'src/ffigen.dart'; + +@JS() +external void setLogs(JSObject logs); + +void generate(String yaml) { + final ffigen = FfiGen(logLevel: Level.ALL); + final config = YamlConfig.fromYaml(loadYaml(yaml) as YamlMap); + ffigen.run(config); +} + +void main(List args) { + final logs = []; + Logger.root.onRecord.listen((record) { + final log = JSObject(); + log.setProperty('level'.toJS, (record.level.value / 100).toJS); + log.setProperty('message'.toJS, record.message.toJS); + + logs.add(log); + }); + IOOverrides.runWithIOOverrides(() { + generate(args.first); + }, MemFSIOOverrides()); + setLogs(logs.toJS); +} diff --git a/pkgs/ffigenpad/lib/memfs.dart b/pkgs/ffigenpad/lib/memfs.dart new file mode 100644 index 0000000000..8b876aeaa9 --- /dev/null +++ b/pkgs/ffigenpad/lib/memfs.dart @@ -0,0 +1,122 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert' as convert; +import 'dart:io'; +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; +import 'dart:typed_data'; + +// adapted functions from https://emscripten.org/docs/api_reference/Filesystem-API.html#id2 +extension type MemFS(JSObject _) implements JSObject { + external JSArray readdir(String path); + external JSUint8Array readFile(String path, [JSObject? opts]); + external void writeFile(String path, String data); + external void unlink(String path); + external void mkdir(String path); + external void rmdir(String path); + external void rename(String oldpath, String newpath); + external String cwd(); + external void chdir(String path); + external JSObject analyzePath(String path, bool dontResolveLastLink); +} + +@JS('FS') +external MemFS get memfs; + +class MemFSDirectory implements Directory { + @override + String path; + + MemFSDirectory(this.path); + + @override + void createSync({bool recursive = false}) { + memfs.mkdir(path); + } + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MemFSFile implements File { + @override + String path; + + MemFSFile(this.path); + + @override + MemFSFile get absolute => MemFSFile(path); + + @override + void createSync({bool recursive = false, bool exclusive = false}) { + memfs.writeFile(path, ''); + } + + @override + void deleteSync({bool recursive = false}) { + memfs.unlink(path); + } + + @override + bool existsSync() { + return memfs + .analyzePath(path, false) + .getProperty('exists'.toJS) + .toDart; + } + + @override + void writeAsStringSync(String contents, + {FileMode mode = FileMode.write, + convert.Encoding encoding = convert.utf8, + bool flush = false}) { + memfs.writeFile(path, contents); + } + + @override + Uint8List readAsBytesSync() { + return memfs.readFile(path).toDart; + } + + @override + String readAsStringSync({convert.Encoding encoding = convert.utf8}) { + return encoding.decode(readAsBytesSync()); + } + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MemFSIOOverrides extends IOOverrides { + @override + MemFSDirectory createDirectory(String path) { + return MemFSDirectory(path); + } + + @override + MemFSFile createFile(String path) { + return MemFSFile(path); + } + + @override + bool fsWatchIsSupported() { + return false; + } + + @override + void setCurrentDirectory(String path) { + memfs.chdir(path); + } + + @override + MemFSDirectory getCurrentDirectory() { + return MemFSDirectory(memfs.cwd()); + } + + @override + MemFSDirectory getSystemTempDirectory() { + return MemFSDirectory('/tmp'); + } +} diff --git a/pkgs/ffigenpad/lib/src/code_generator.dart b/pkgs/ffigenpad/lib/src/code_generator.dart new file mode 100644 index 0000000000..033c0ef336 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Generates FFI bindings for a given Library. +library; + +export 'code_generator/binding.dart'; +export 'code_generator/compound.dart'; +export 'code_generator/constant.dart'; +export 'code_generator/enum_class.dart'; +export 'code_generator/func.dart'; +export 'code_generator/func_type.dart'; +export 'code_generator/global.dart'; +export 'code_generator/handle.dart'; +export 'code_generator/imports.dart'; +export 'code_generator/library.dart'; +export 'code_generator/native_type.dart'; +export 'code_generator/objc_block.dart'; +export 'code_generator/objc_built_in_functions.dart'; +export 'code_generator/objc_interface.dart'; +export 'code_generator/objc_methods.dart'; +export 'code_generator/objc_nullable.dart'; +export 'code_generator/objc_protocol.dart'; +export 'code_generator/pointer.dart'; +export 'code_generator/struct.dart'; +export 'code_generator/type.dart'; +export 'code_generator/typealias.dart'; +export 'code_generator/union.dart'; diff --git a/pkgs/ffigenpad/lib/src/code_generator/binding.dart b/pkgs/ffigenpad/lib/src/code_generator/binding.dart new file mode 100644 index 0000000000..810ba1251d --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/binding.dart @@ -0,0 +1,71 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'binding_string.dart'; +import 'writer.dart'; + +/// Base class for all Bindings. +/// +/// Do not extend directly, use [LookUpBinding] or [NoLookUpBinding]. +abstract class Binding { + /// Holds the Unified Symbol Resolution string obtained from libclang. + final String usr; + + /// The name as it was in C. + final String originalName; + + /// Binding name to generate, may get changed to resolve name conflicts. + String name; + + final String? dartDoc; + final bool isInternal; + + Binding({ + required this.usr, + required this.originalName, + required this.name, + this.dartDoc, + this.isInternal = false, + }); + + /// Get all dependencies, including itself and save them in [dependencies]. + void addDependencies(Set dependencies); + + /// Converts a Binding to its actual string representation. + /// + /// Note: This does not print the typedef dependencies. + /// Must call getTypedefDependencies first. + BindingString toBindingString(Writer w); + + /// Returns the Objective C bindings, if any. + BindingString? toObjCBindingString(Writer w) => null; +} + +/// Base class for bindings which look up symbols in dynamic library. +abstract class LookUpBinding extends Binding { + LookUpBinding({ + String? usr, + String? originalName, + required super.name, + super.dartDoc, + super.isInternal, + }) : super( + usr: usr ?? name, + originalName: originalName ?? name, + ); +} + +/// Base class for bindings which don't look up symbols in dynamic library. +abstract class NoLookUpBinding extends Binding { + NoLookUpBinding({ + String? usr, + String? originalName, + required super.name, + super.dartDoc, + super.isInternal, + }) : super( + usr: usr ?? name, + originalName: originalName ?? name, + ); +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/binding_string.dart b/pkgs/ffigenpad/lib/src/code_generator/binding_string.dart new file mode 100644 index 0000000000..58b2b276a6 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/binding_string.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'package:ffigen/src/code_generator/binding_string.dart'; diff --git a/pkgs/ffigenpad/lib/src/code_generator/compound.dart b/pkgs/ffigenpad/lib/src/code_generator/compound.dart new file mode 100644 index 0000000000..7eda0281de --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/compound.dart @@ -0,0 +1,201 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'binding_string.dart'; +import 'utils.dart'; +import 'writer.dart'; + +enum CompoundType { struct, union } + +/// A binding for Compound type - Struct/Union. +abstract class Compound extends BindingType { + /// Marker for if a struct definition is complete. + /// + /// A function can be safely pass this struct by value if it's complete. + bool isIncomplete; + + List members; + + bool get isOpaque => members.isEmpty; + + /// Value for `@Packed(X)` annotation. Can be null (no packing), 1, 2, 4, 8, + /// or 16. + /// + /// Only supported for [CompoundType.struct]. + int? pack; + + /// Marker for checking if the dependencies are parsed. + bool parsedDependencies = false; + + CompoundType compoundType; + bool get isStruct => compoundType == CompoundType.struct; + bool get isUnion => compoundType == CompoundType.union; + + ObjCBuiltInFunctions? objCBuiltInFunctions; + + /// The way the native type is written in C source code. This isn't always the + /// same as the originalName, because the type may need to be prefixed with + /// `struct` or `union`, depending on whether the declaration is a typedef. + final String nativeType; + + Compound({ + super.usr, + super.originalName, + required super.name, + required this.compoundType, + this.isIncomplete = false, + this.pack, + super.dartDoc, + List? members, + super.isInternal, + this.objCBuiltInFunctions, + String? nativeType, + }) : members = members ?? [], + nativeType = nativeType ?? originalName ?? name; + + factory Compound.fromType({ + required CompoundType type, + String? usr, + String? originalName, + required String name, + bool isIncomplete = false, + int? pack, + String? dartDoc, + List? members, + ObjCBuiltInFunctions? objCBuiltInFunctions, + String? nativeType, + }) { + switch (type) { + case CompoundType.struct: + return Struct( + usr: usr, + originalName: originalName, + name: name, + isIncomplete: isIncomplete, + pack: pack, + dartDoc: dartDoc, + members: members, + objCBuiltInFunctions: objCBuiltInFunctions, + nativeType: nativeType, + ); + case CompoundType.union: + return Union( + usr: usr, + originalName: originalName, + name: name, + isIncomplete: isIncomplete, + pack: pack, + dartDoc: dartDoc, + members: members, + objCBuiltInFunctions: objCBuiltInFunctions, + nativeType: nativeType, + ); + } + } + + String _getInlineArrayTypeString(Type type, Writer w) { + if (type is ConstantArray) { + return '${w.ffiLibraryPrefix}.Array<' + '${_getInlineArrayTypeString(type.child, w)}>'; + } + return type.getCType(w); + } + + bool get _isBuiltIn => + objCBuiltInFunctions?.isBuiltInCompound(originalName) ?? false; + + @override + BindingString toBindingString(Writer w) { + final bindingType = + isStruct ? BindingStringType.struct : BindingStringType.union; + if (_isBuiltIn) { + return BindingString(type: bindingType, string: ''); + } + + final s = StringBuffer(); + final enclosingClassName = name; + if (dartDoc != null) { + s.write(makeDartDoc(dartDoc!)); + } + + /// Adding [enclosingClassName] because dart doesn't allow class member + /// to have the same name as the class. + final localUniqueNamer = UniqueNamer({enclosingClassName}); + + /// Marking type names because dart doesn't allow class member to have the + /// same name as a type name used internally. + for (final m in members) { + localUniqueNamer.markUsed(m.type.getFfiDartType(w)); + } + + /// Write @Packed(X) annotation if struct is packed. + if (isStruct && pack != null) { + s.write('@${w.ffiLibraryPrefix}.Packed($pack)\n'); + } + final dartClassName = isStruct ? 'Struct' : 'Union'; + // Write class declaration. + s.write('final class $enclosingClassName extends '); + s.write('${w.ffiLibraryPrefix}.${isOpaque ? 'Opaque' : dartClassName}{\n'); + const depth = ' '; + for (final m in members) { + m.name = localUniqueNamer.makeUnique(m.name); + if (m.dartDoc != null) { + s.write('$depth/// '); + s.writeAll(m.dartDoc!.split('\n'), '\n$depth/// '); + s.write('\n'); + } + if (m.type case final ConstantArray arrayType) { + s.writeln(makeArrayAnnotation(w, arrayType)); + s.write('${depth}external ${_getInlineArrayTypeString(m.type, w)} '); + s.write('${m.name};\n\n'); + } else { + if (!m.type.sameFfiDartAndCType) { + s.write('$depth@${m.type.getCType(w)}()\n'); + } + s.write('${depth}external ${m.type.getFfiDartType(w)} ${m.name};\n\n'); + } + } + s.write('}\n\n'); + + return BindingString(type: bindingType, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this) || _isBuiltIn) return; + + dependencies.add(this); + for (final m in members) { + m.type.addDependencies(dependencies); + } + } + + @override + bool get isIncompleteCompound => isIncomplete; + + @override + String getCType(Writer w) => _isBuiltIn ? '${w.objcPkgPrefix}.$name' : name; + + @override + String getNativeType({String varName = ''}) => '$nativeType $varName'; + + @override + bool get sameFfiDartAndCType => true; +} + +class Member { + final String? dartDoc; + final String originalName; + String name; + final Type type; + + Member({ + String? originalName, + required this.name, + required this.type, + this.dartDoc, + }) : originalName = originalName ?? name; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/constant.dart b/pkgs/ffigenpad/lib/src/code_generator/constant.dart new file mode 100644 index 0000000000..0bef022491 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/constant.dart @@ -0,0 +1,60 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'binding.dart'; +import 'binding_string.dart'; +import 'utils.dart'; +import 'writer.dart'; + +/// A simple Constant. +/// +/// Expands to - +/// ```dart +/// const = ; +/// ``` +/// +/// Example - +/// ```dart +/// const int name = 10; +/// ``` +class Constant extends NoLookUpBinding { + /// The rawType is pasted as it is. E.g 'int', 'String', 'double' + final String rawType; + + /// The rawValue is pasted as it is. + /// + /// Put quotes if type is a string. + final String rawValue; + + Constant({ + super.usr, + super.originalName, + required super.name, + super.dartDoc, + required this.rawType, + required this.rawValue, + }); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + final constantName = name; + + if (dartDoc != null) { + s.write(makeDartDoc(dartDoc!)); + } + + s.write('\nconst $rawType $constantName = $rawValue;\n\n'); + + return BindingString( + type: BindingStringType.constant, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + + dependencies.add(this); + } +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/dart_keywords.dart b/pkgs/ffigenpad/lib/src/code_generator/dart_keywords.dart new file mode 100644 index 0000000000..ff778c178a --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/dart_keywords.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'package:ffigen/src/code_generator/dart_keywords.dart'; diff --git a/pkgs/ffigenpad/lib/src/code_generator/enum_class.dart b/pkgs/ffigenpad/lib/src/code_generator/enum_class.dart new file mode 100644 index 0000000000..105c15f395 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/enum_class.dart @@ -0,0 +1,332 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:collection/collection.dart'; + +import 'binding.dart'; +import 'binding_string.dart'; +import 'imports.dart'; +import 'objc_built_in_functions.dart'; +import 'type.dart'; +import 'utils.dart'; +import 'writer.dart'; + +/// A binding for enums in C. +/// +/// For a C enum - +/// ```c +/// enum Fruits {apple, banana = 10, yellow_fruit = 10}; +/// ``` +/// The generated dart code is +/// +/// ```dart +/// enum Fruits { +/// apple(0), +/// banana(10); +/// +/// static const yellow_fruit = banana; +/// +/// final int value; +/// const Fruit(this.value); +/// +/// @override +/// String toString() { +/// if (this == banana) return "Fruits.banana, Fruits.yellow_fruit"; +/// return super.toString(); +/// } +/// } +/// ``` +class EnumClass extends BindingType { + /// Backing integer type for this enum. + Type nativeType; + + /// The amount of indentation in every line. + static const depth = ' '; + + /// A list of all the members of the native enum. + final List enumConstants; + + /// Generates new names for all members that don't equal [name]. + final UniqueNamer namer; + + ObjCBuiltInFunctions? objCBuiltInFunctions; + + /// Whether this enum should be generated as a collection of integers. + bool generateAsInt; + + EnumClass({ + super.usr, + super.originalName, + required super.name, + super.dartDoc, + Type? nativeType, + List? enumConstants, + this.objCBuiltInFunctions, + this.generateAsInt = false, + }) : nativeType = nativeType ?? intType, + enumConstants = enumConstants ?? [], + namer = UniqueNamer({name}); + + /// The names of all the enum members generated by [namer]. + final Map enumNames = {}; + + /// Maps all unique enum values to a list of their duplicates or aliases. + /// + /// See [scanForDuplicates] and [writeToStringOverride]. + final Map> uniqueToDuplicates = {}; + + /// Maps all duplicate enum members to the member who first had that value. + /// + /// See [scanForDuplicates] and [writeDuplicateMembers]. + final Map duplicateToOriginal = {}; + + /// A collection of all the enum members with unique values. + /// + /// See [scanForDuplicates] and [writeUniqueMembers]. + final Set uniqueMembers = {}; + + /// Returns a string to declare the enum member and any documentation it may + /// have had. + String formatValue(EnumConstant ec, {bool asInt = false}) { + final buffer = StringBuffer(); + final enumValueName = namer.makeUnique(ec.name); + enumNames[ec] = enumValueName; + if (ec.dartDoc != null) { + buffer.write('$depth/// '); + buffer.writeAll(ec.dartDoc!.split('\n'), '\n$depth/// '); + buffer.write('\n'); + } + if (asInt) { + buffer.write('${depth}static const $enumValueName = ${ec.value};'); + } else { + buffer.write('$depth$enumValueName(${ec.value})'); + } + return buffer.toString(); + } + + /// Finds enum values that are duplicates of previous enum values. + /// + /// Since all enum values in Dart are distinct, these duplicates do not + /// get their own values in Dart. Rather, they are aliases of the original + /// value. For example, if a native enum has 2 constants with a value of 10, + /// only one enum value will be generated in Dart, and the other will be set + /// equal to it. + void scanForDuplicates() { + uniqueMembers.clear(); + uniqueToDuplicates.clear(); + duplicateToOriginal.clear(); + for (final ec in enumConstants) { + final original = uniqueMembers.firstWhereOrNull( + (other) => other.value == ec.value, + ); + if (original == null) { + // This is a unique entry + uniqueMembers.add(ec); + uniqueToDuplicates[ec] = []; + } else { + // This is a duplicate of a previous entry + duplicateToOriginal[ec] = original; + uniqueToDuplicates[original]!.add(ec); + } + } + } + + void writeIntegerConstants(StringBuffer s) { + s.writeAll(enumConstants.map((c) => formatValue(c, asInt: true)), '\n'); + } + + /// Writes the enum declarations for all unique members. + /// + /// Eg, C: `apple = 1`, Dart: `apple(1)` + void writeUniqueMembers(StringBuffer s) { + s.writeAll(uniqueMembers.map(formatValue), ',\n'); + if (uniqueMembers.isNotEmpty) s.write(';\n'); + } + + /// Writes alias declarations for all members with duplicate values. + /// + /// Eg, C: `banana = 10, yellow_fruit = 10`. + /// Dart: `static const yellow_fruit = banana`. + void writeDuplicateMembers(StringBuffer s) { + if (duplicateToOriginal.isEmpty) return; + for (final entry in duplicateToOriginal.entries) { + final duplicate = entry.key; + final original = entry.value; + final duplicateName = namer.makeUnique(duplicate.name); + // [!] Each original enum value was given a name in [writeUniqueMembers]. + final originalName = enumNames[original]!; + enumNames[duplicate] = duplicateName; + if (duplicate.dartDoc != null) { + s.write('$depth/// '); + s.writeAll(duplicate.dartDoc!.split('\n'), '\n$depth/// '); + s.write('\n'); + } + s.write('${depth}static const $duplicateName = $originalName;\n'); + } + } + + /// Writes the constructor for the enum. + /// + /// Always accepts an integer value to match the native value. + void writeConstructor(StringBuffer s) { + s.write('${depth}final int value;\n'); + s.write('${depth}const $name(this.value);\n'); + } + + /// Overrides [Enum.toString] so all aliases are included, if any. + /// + /// If a native enum has two members with the same value, they are + /// functionally identical, and should be represented as such. This method + /// overrides [toString] to include all duplicate members in the same message. + void writeToStringOverride(StringBuffer s) { + if (duplicateToOriginal.isEmpty) return; + s.write('$depth@override\n'); + s.write('${depth}String toString() {\n'); + for (final entry in uniqueToDuplicates.entries) { + // [!] All enum values were given a name when their declarations were + // generated. + final unique = entry.key; + final originalName = enumNames[unique]!; + final duplicates = entry.value; + if (duplicates.isEmpty) continue; + final allDuplicates = [ + for (final duplicate in [unique] + duplicates) + '$name.${enumNames[duplicate]!}', + ].join(', '); + s.write( + '$depth$depth' + 'if (this == $originalName) return "$allDuplicates";\n', + ); + } + s.write('${depth * 2}return super.toString();\n'); + s.write('$depth}'); + } + + /// Writes the DartDoc string for this enum. + void writeDartDoc(StringBuffer s) { + if (dartDoc != null) { + s.write(makeDartDoc(dartDoc!)); + } + } + + /// Writes a sealed class when no members exist, because Dart enums cannot be + /// empty. + void writeEmptyEnum(StringBuffer s) { + s.write('sealed class $name { }\n'); + } + + /// Writes a static function that maps integers to enum values. + void writeFromValue(StringBuffer s) { + s.write('${depth}static $name fromValue(int value) => switch (value) {\n'); + for (final member in uniqueMembers) { + final memberName = enumNames[member]!; + s.write('$depth$depth${member.value} => $memberName,\n'); + } + s.write( + '$depth${depth}_ => ' + 'throw ArgumentError("Unknown value for $name: \$value"),\n', + ); + s.write('$depth};\n'); + } + + bool get _isBuiltIn => + objCBuiltInFunctions?.isBuiltInEnum(originalName) ?? false; + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + if (_isBuiltIn) { + return const BindingString(type: BindingStringType.enum_, string: ''); + } + scanForDuplicates(); + + writeDartDoc(s); + if (enumConstants.isEmpty) { + writeEmptyEnum(s); + } else if (generateAsInt) { + s.write('abstract class $name {\n'); + writeIntegerConstants(s); + s.write('}\n\n'); + } else { + s.write('enum $name {\n'); + writeUniqueMembers(s); + s.write('\n'); + writeDuplicateMembers(s); + s.write('\n'); + writeConstructor(s); + s.write('\n'); + writeFromValue(s); + s.write('\n'); + writeToStringOverride(s); + s.write('}\n\n'); + } + + return BindingString( + type: BindingStringType.enum_, + string: s.toString(), + ); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this) || _isBuiltIn) return; + dependencies.add(this); + } + + @override + String getCType(Writer w) { + w.usedEnumCType = true; + return nativeType.getCType(w); + } + + @override + String getFfiDartType(Writer w) => nativeType.getFfiDartType(w); + + @override + String getDartType(Writer w) => + _isBuiltIn ? '${w.objcPkgPrefix}.$name' : name; + + @override + String getNativeType({String varName = ''}) => '$originalName $varName'; + + @override + bool get sameFfiDartAndCType => nativeType.sameFfiDartAndCType; + + @override + bool get sameDartAndFfiDartType => generateAsInt; + + @override + String? getDefaultValue(Writer w) => '0'; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + '$value.value'; + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + '${getDartType(w)}.fromValue($value)'; +} + +/// Represents a single value in an enum. +class EnumConstant { + final String? originalName; + final String? dartDoc; + final String name; + final int value; + const EnumConstant({ + String? originalName, + required this.name, + required this.value, + this.dartDoc, + }) : originalName = originalName ?? name; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/func.dart b/pkgs/ffigenpad/lib/src/code_generator/func.dart new file mode 100644 index 0000000000..3f5fcce1a4 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/func.dart @@ -0,0 +1,237 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; +import '../config_provider/config_types.dart'; + +import 'binding_string.dart'; +import 'utils.dart'; +import 'writer.dart'; + +/// A binding for C function. +/// +/// For example, take the following C function. +/// +/// ```c +/// int sum(int a, int b); +/// ``` +/// +/// The generated Dart code for this function (without `FfiNative`) is as +/// follows. +/// +/// ```dart +/// int sum(int a, int b) { +/// return _sum(a, b); +/// } +/// +/// final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum'); +/// +/// typedef _c_sum = ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b); +/// +/// typedef _dart_sum = int Function(int a, int b); +/// ``` +/// +/// When using `Native`, the code is as follows. +/// +/// ```dart +/// @ffi.Native('sum') +/// external int sum(int a, int b); +/// ``` +class Func extends LookUpBinding { + final FunctionType functionType; + final bool exposeSymbolAddress; + final bool exposeFunctionTypedefs; + final bool isLeaf; + final bool objCReturnsRetained; + final bool useNameForLookup; + final FfiNativeConfig ffiNativeConfig; + late final String funcPointerName; + + /// Contains typealias for function type if [exposeFunctionTypedefs] is true. + Typealias? _exposedFunctionTypealias; + + /// [originalName] is looked up in dynamic library, if not + /// provided, takes the value of [name]. + Func({ + super.usr, + required String name, + super.originalName, + super.dartDoc, + required Type returnType, + List? parameters, + List? varArgParameters, + this.exposeSymbolAddress = false, + this.exposeFunctionTypedefs = false, + this.isLeaf = false, + this.objCReturnsRetained = false, + this.useNameForLookup = false, + super.isInternal, + this.ffiNativeConfig = const FfiNativeConfig(enabled: false), + }) : functionType = FunctionType( + returnType: returnType, + parameters: parameters ?? const [], + varArgParameters: varArgParameters ?? const [], + ), + super( + name: name, + ) { + for (var i = 0; i < functionType.parameters.length; i++) { + if (functionType.parameters[i].name.trim() == '') { + functionType.parameters[i].name = 'arg$i'; + } + } + + // Get function name with first letter in upper case. + final upperCaseName = name[0].toUpperCase() + name.substring(1); + if (exposeFunctionTypedefs) { + _exposedFunctionTypealias = Typealias( + name: upperCaseName, + type: functionType, + genFfiDartType: true, + isInternal: true, + ); + } + } + + String get _lookupName => useNameForLookup ? name : originalName; + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + final enclosingFuncName = name; + + if (dartDoc != null) { + s.write(makeDartDoc(dartDoc!)); + } + // Resolve name conflicts in function parameter names. + final paramNamer = UniqueNamer({}); + for (final p in functionType.dartTypeParameters) { + p.name = paramNamer.makeUnique(p.name); + } + + final cType = _exposedFunctionTypealias?.getCType(w) ?? + functionType.getCType(w, writeArgumentNames: false); + final dartType = _exposedFunctionTypealias?.getFfiDartType(w) ?? + functionType.getFfiDartType(w, writeArgumentNames: false); + final needsWrapper = !functionType.sameDartAndFfiDartType && !isInternal; + + final funcVarName = w.wrapperLevelUniqueNamer.makeUnique('_$name'); + final ffiReturnType = functionType.returnType.getFfiDartType(w); + final ffiArgDeclString = functionType.dartTypeParameters + .map((p) => '${p.type.getFfiDartType(w)} ${p.name},\n') + .join(''); + + late final String dartReturnType; + late final String dartArgDeclString; + late final String funcImplCall; + if (needsWrapper) { + dartReturnType = functionType.returnType.getDartType(w); + dartArgDeclString = functionType.dartTypeParameters + .map((p) => '${p.type.getDartType(w)} ${p.name},\n') + .join(''); + + final argString = functionType.dartTypeParameters.map((p) { + final type = + p.type.convertDartTypeToFfiDartType(w, p.name, objCRetain: false); + return '$type,\n'; + }).join(''); + funcImplCall = functionType.returnType.convertFfiDartTypeToDartType( + w, + '$funcVarName($argString)', + objCRetain: !objCReturnsRetained, + ); + } else { + dartReturnType = ffiReturnType; + dartArgDeclString = ffiArgDeclString; + final argString = + functionType.dartTypeParameters.map((p) => '${p.name},\n').join(''); + funcImplCall = '$funcVarName($argString)'; + } + + if (ffiNativeConfig.enabled) { + final nativeFuncName = needsWrapper ? funcVarName : enclosingFuncName; + s.write(''' +${makeNativeAnnotation( + w, + nativeType: cType, + dartName: nativeFuncName, + nativeSymbolName: _lookupName, + isLeaf: isLeaf, + )} +external $ffiReturnType $nativeFuncName($ffiArgDeclString); + +'''); + if (needsWrapper) { + s.write(''' +$dartReturnType $enclosingFuncName($dartArgDeclString) => $funcImplCall; + +'''); + } + + if (exposeSymbolAddress) { + // Add to SymbolAddress in writer. + w.symbolAddressWriter.addNativeSymbol( + type: '${w.ffiLibraryPrefix}.Pointer<' + '${w.ffiLibraryPrefix}.NativeFunction<$cType>>', + name: name, + ); + } + } else { + funcPointerName = w.wrapperLevelUniqueNamer.makeUnique('_${name}Ptr'); + final isLeafString = isLeaf ? 'isLeaf:true' : ''; + + // Write enclosing function. + s.write(''' +$dartReturnType $enclosingFuncName($dartArgDeclString) { + return $funcImplCall; +} + +'''); + + if (exposeSymbolAddress) { + // Add to SymbolAddress in writer. + w.symbolAddressWriter.addSymbol( + type: '${w.ffiLibraryPrefix}.Pointer<' + '${w.ffiLibraryPrefix}.NativeFunction<$cType>>', + name: name, + ptrName: funcPointerName, + ); + } + + // Write function pointer. + s.write(''' +late final $funcPointerName = ${w.lookupFuncIdentifier}< + ${w.ffiLibraryPrefix}.NativeFunction<$cType>>('$_lookupName'); +late final $funcVarName = $funcPointerName.asFunction<$dartType>($isLeafString); + +'''); + } + + return BindingString(type: BindingStringType.func, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + + dependencies.add(this); + functionType.addDependencies(dependencies); + if (exposeFunctionTypedefs) { + _exposedFunctionTypealias!.addDependencies(dependencies); + } + } +} + +/// Represents a Parameter, used in [Func] and [Typealias]. +class Parameter { + final String? originalName; + String name; + final Type type; + + Parameter({String? originalName, this.name = '', required Type type}) + : originalName = originalName ?? name, + // A [NativeFunc] is wrapped with a pointer because this is a shorthand + // used in C for Pointer to function. + type = type.typealiasType is NativeFunc ? PointerType(type) : type; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/func_type.dart b/pkgs/ffigenpad/lib/src/code_generator/func_type.dart new file mode 100644 index 0000000000..a7f00e5354 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/func_type.dart @@ -0,0 +1,160 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; +import 'utils.dart'; + +import 'writer.dart'; + +/// Represents a function type. +class FunctionType extends Type { + final Type returnType; + final List parameters; + final List varArgParameters; + + /// Get all the parameters for generating the dart type. This includes both + /// [parameters] and [varArgParameters]. + List get dartTypeParameters => parameters + varArgParameters; + + FunctionType({ + required this.returnType, + required this.parameters, + this.varArgParameters = const [], + }); + + String _getTypeImpl( + bool writeArgumentNames, String Function(Type) typeToString, + {String? varArgWrapper}) { + final params = varArgWrapper != null ? parameters : dartTypeParameters; + String? varArgPack; + if (varArgWrapper != null && varArgParameters.isNotEmpty) { + final varArgPackBuf = StringBuffer(); + varArgPackBuf.write('$varArgWrapper<('); + varArgPackBuf.write(varArgParameters.map((p) { + return '${typeToString(p.type)} ${writeArgumentNames ? p.name : ""}'; + }).join(', ')); + varArgPackBuf.write(',)>'); + varArgPack = varArgPackBuf.toString(); + } + + // Write return Type. + final sb = StringBuffer(); + sb.write(typeToString(returnType)); + + // Write Function. + sb.write(' Function('); + sb.write([ + ...params.map((p) { + return '${typeToString(p.type)} ${writeArgumentNames ? p.name : ""}'; + }), + if (varArgPack != null) varArgPack, + ].join(', ')); + sb.write(')'); + + return sb.toString(); + } + + @override + String getCType(Writer w, {bool writeArgumentNames = true}) => + _getTypeImpl(writeArgumentNames, (Type t) => t.getCType(w), + varArgWrapper: '${w.ffiLibraryPrefix}.VarArgs'); + + @override + String getFfiDartType(Writer w, {bool writeArgumentNames = true}) => + _getTypeImpl(writeArgumentNames, (Type t) => t.getFfiDartType(w)); + + @override + String getDartType(Writer w, {bool writeArgumentNames = true}) => + _getTypeImpl(writeArgumentNames, (Type t) => t.getDartType(w)); + + @override + String getNativeType({String varName = ''}) { + final arg = dartTypeParameters.map((p) => p.type.getNativeType()); + return '${returnType.getNativeType()} (*$varName)(${arg.join(', ')})'; + } + + @override + bool get sameFfiDartAndCType => + returnType.sameFfiDartAndCType && + dartTypeParameters.every((p) => p.type.sameFfiDartAndCType); + + @override + bool get sameDartAndCType => + returnType.sameDartAndCType && + dartTypeParameters.every((p) => p.type.sameDartAndCType); + + @override + bool get sameDartAndFfiDartType => + returnType.sameDartAndFfiDartType && + dartTypeParameters.every((p) => p.type.sameDartAndFfiDartType); + + @override + String toString() => _getTypeImpl(false, (Type t) => t.toString()); + + @override + String cacheKey() => _getTypeImpl(false, (Type t) => t.cacheKey()); + + @override + void addDependencies(Set dependencies) { + returnType.addDependencies(dependencies); + for (final p in parameters) { + p.type.addDependencies(dependencies); + } + } + + void addParameterNames(List names) { + if (names.length != parameters.length) { + return; + } + final paramNamer = UniqueNamer({}); + for (var i = 0; i < parameters.length; i++) { + final finalName = paramNamer.makeUnique(names[i]); + parameters[i] = Parameter( + type: parameters[i].type, + originalName: names[i], + name: finalName, + ); + } + } +} + +/// Represents a NativeFunction<Function>. +class NativeFunc extends Type { + // Either a FunctionType or a Typealias of a FunctionType. + final Type _type; + + NativeFunc(this._type) : assert(_type is FunctionType || _type is Typealias); + + FunctionType get type { + if (_type is Typealias) { + return _type.typealiasType as FunctionType; + } + return _type as FunctionType; + } + + @override + void addDependencies(Set dependencies) { + _type.addDependencies(dependencies); + } + + @override + String getCType(Writer w) => + '${w.ffiLibraryPrefix}.NativeFunction<${_type.getCType(w)}>'; + + @override + String getFfiDartType(Writer w) => getCType(w); + + @override + String getNativeType({String varName = ''}) => + _type.getNativeType(varName: varName); + + @override + bool get sameFfiDartAndCType => true; + + @override + String toString() => 'NativeFunction<${_type.toString()}>'; + + @override + String cacheKey() => 'NatFn(${_type.cacheKey()})'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/global.dart b/pkgs/ffigenpad/lib/src/code_generator/global.dart new file mode 100644 index 0000000000..6bb1504010 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/global.dart @@ -0,0 +1,117 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../config_provider/config_types.dart'; +import 'binding.dart'; +import 'binding_string.dart'; +import 'compound.dart'; +import 'pointer.dart'; +import 'type.dart'; +import 'utils.dart'; +import 'writer.dart'; + +/// A binding to a global variable +/// +/// For a C global variable - +/// ```c +/// int a; +/// ``` +/// The generated dart code is - +/// ```dart +/// final int a = _dylib.lookup('a').value; +/// ``` +class Global extends LookUpBinding { + final Type type; + final bool exposeSymbolAddress; + final FfiNativeConfig nativeConfig; + final bool constant; + + Global({ + super.usr, + super.originalName, + required super.name, + required this.type, + super.dartDoc, + this.exposeSymbolAddress = false, + this.constant = false, + this.nativeConfig = const FfiNativeConfig(enabled: false), + }); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + final globalVarName = name; + if (dartDoc != null) { + s.write(makeDartDoc(dartDoc!)); + } + final dartType = type.getFfiDartType(w); + final cType = type.getCType(w); + + if (nativeConfig.enabled) { + if (type case final ConstantArray arr) { + s.writeln(makeArrayAnnotation(w, arr)); + } + + s + ..writeln(makeNativeAnnotation( + w, + nativeType: cType, + dartName: globalVarName, + nativeSymbolName: originalName, + isLeaf: false, + )) + ..write('external '); + if (constant) { + s.write('final '); + } + + s.writeln('$dartType $globalVarName;\n'); + + if (exposeSymbolAddress) { + w.symbolAddressWriter.addNativeSymbol( + type: '${w.ffiLibraryPrefix}.Pointer<$cType>', name: name); + } + } else { + final pointerName = + w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName'); + + s.write('late final ${w.ffiLibraryPrefix}.Pointer<$cType> $pointerName = ' + "${w.lookupFuncIdentifier}<$cType>('$originalName');\n\n"); + final baseTypealiasType = type.typealiasType; + if (baseTypealiasType is Compound) { + if (baseTypealiasType.isOpaque) { + s.write('${w.ffiLibraryPrefix}.Pointer<$cType> get $globalVarName =>' + ' $pointerName;\n\n'); + } else { + s.write('$dartType get $globalVarName => $pointerName.ref;\n\n'); + } + } else { + s.write('$dartType get $globalVarName => $pointerName.value;\n\n'); + if (!constant) { + s.write('set $globalVarName($dartType value) =>' + '$pointerName.value = value;\n\n'); + } + } + + if (exposeSymbolAddress) { + // Add to SymbolAddress in writer. + w.symbolAddressWriter.addSymbol( + type: '${w.ffiLibraryPrefix}.Pointer<$cType>', + name: name, + ptrName: pointerName, + ); + } + } + + return BindingString(type: BindingStringType.global, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + + dependencies.add(this); + type.addDependencies(dependencies); + } +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/handle.dart b/pkgs/ffigenpad/lib/src/code_generator/handle.dart new file mode 100644 index 0000000000..de4f30c831 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/handle.dart @@ -0,0 +1,31 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'writer.dart'; + +/// Represents a Dart_Handle. +class HandleType extends Type { + const HandleType._(); + static const _handle = HandleType._(); + factory HandleType() => _handle; + + @override + String getCType(Writer w) => '${w.ffiLibraryPrefix}.Handle'; + + @override + String getFfiDartType(Writer w) => 'Object'; + + // The real native type is Dart_Handle, but that would mean importing + // dart_api.h into the generated native code. + @override + String getNativeType({String varName = ''}) => 'void* $varName'; + + @override + bool get sameFfiDartAndCType => false; + + @override + String toString() => 'Handle'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/imports.dart b/pkgs/ffigenpad/lib/src/code_generator/imports.dart new file mode 100644 index 0000000000..9ea3936f38 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/imports.dart @@ -0,0 +1,106 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:ffigen/src/code_generator/imports.dart' show LibraryImport; + +import 'type.dart'; +import 'writer.dart'; + +export 'package:ffigen/src/code_generator/imports.dart' show LibraryImport; + +/// An imported type which will be used in the generated code. +class ImportedType extends Type { + final LibraryImport libraryImport; + final String cType; + final String dartType; + final String nativeType; + final String? defaultValue; + + ImportedType(this.libraryImport, this.cType, this.dartType, this.nativeType, + [this.defaultValue]); + + @override + String getCType(Writer w) { + w.markImportUsed(libraryImport); + return '${libraryImport.prefix}.$cType'; + } + + @override + String getFfiDartType(Writer w) => cType == dartType ? getCType(w) : dartType; + + @override + String getNativeType({String varName = ''}) => '$nativeType $varName'; + + @override + bool get sameFfiDartAndCType => cType == dartType; + + @override + String toString() => '${libraryImport.name}.$cType'; + + @override + String? getDefaultValue(Writer w) => defaultValue; +} + +/// An unchecked type similar to [ImportedType] which exists in the generated +/// binding itself. +class SelfImportedType extends Type { + final String cType; + final String dartType; + final String? defaultValue; + + SelfImportedType(this.cType, this.dartType, [this.defaultValue]); + + @override + String getCType(Writer w) => cType; + + @override + String getFfiDartType(Writer w) => dartType; + + @override + bool get sameFfiDartAndCType => cType == dartType; + + @override + String toString() => cType; +} + +final ffiImport = LibraryImport('ffi', 'dart:ffi'); +final ffiPkgImport = LibraryImport('pkg_ffi', 'package:ffi/ffi.dart'); +final objcPkgImport = LibraryImport( + 'objc', 'package:objective_c/objective_c.dart', + importPathWhenImportedByPackageObjC: '../objective_c.dart'); +final self = LibraryImport('self', ''); + +final voidType = ImportedType(ffiImport, 'Void', 'void', 'void'); + +final unsignedCharType = + ImportedType(ffiImport, 'UnsignedChar', 'int', 'unsigned char', '0'); +final signedCharType = + ImportedType(ffiImport, 'SignedChar', 'int', 'char', '0'); +final charType = ImportedType(ffiImport, 'Char', 'int', 'char', '0'); +final unsignedShortType = + ImportedType(ffiImport, 'UnsignedShort', 'int', 'unsigned short', '0'); +final shortType = ImportedType(ffiImport, 'Short', 'int', 'short', '0'); +final unsignedIntType = + ImportedType(ffiImport, 'UnsignedInt', 'int', 'unsigned', '0'); +final intType = ImportedType(ffiImport, 'Int', 'int', 'int', '0'); +final unsignedLongType = + ImportedType(ffiImport, 'UnsignedLong', 'int', 'unsigned long', '0'); +final longType = ImportedType(ffiImport, 'Long', 'int', 'long', '0'); +final unsignedLongLongType = ImportedType( + ffiImport, 'UnsignedLongLong', 'int', 'unsigned long long', '0'); +final longLongType = + ImportedType(ffiImport, 'LongLong', 'int', 'long long', '0'); + +final floatType = ImportedType(ffiImport, 'Float', 'double', 'float', '0.0'); +final doubleType = ImportedType(ffiImport, 'Double', 'double', 'double', '0.0'); + +final sizeType = ImportedType(ffiImport, 'Size', 'int', 'size_t', '0'); +final wCharType = ImportedType(ffiImport, 'WChar', 'int', 'wchar_t', '0'); + +final objCObjectType = + ImportedType(objcPkgImport, 'ObjCObject', 'ObjCObject', 'void'); +final objCSelType = + ImportedType(objcPkgImport, 'ObjCSelector', 'ObjCSelector', 'void'); +final objCBlockType = + ImportedType(objcPkgImport, 'ObjCBlock', 'ObjCBlock', 'id'); diff --git a/pkgs/ffigenpad/lib/src/code_generator/library.dart b/pkgs/ffigenpad/lib/src/code_generator/library.dart new file mode 100644 index 0000000000..7df7e9046e --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/library.dart @@ -0,0 +1,191 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:logging/logging.dart'; +import 'package:yaml_edit/yaml_edit.dart'; + +import '../code_generator.dart'; +import '../config_provider/config_types.dart'; +import 'utils.dart'; +import 'writer.dart'; + +final _logger = Logger('ffigen.code_generator.library'); +final _formatter = DartFormatter(); + +/// Container for all Bindings. +class Library { + /// List of bindings in this library. + late List bindings; + + late Writer _writer; + Writer get writer => _writer; + + Library({ + required String name, + String? description, + required List bindings, + String? header, + bool sort = false, + bool generateForPackageObjectiveC = false, + PackingValue? Function(Declaration)? packingOverride, + List? libraryImports, + bool silenceEnumWarning = false, + List nativeEntryPoints = const [], + }) { + _findBindings(bindings, sort); + + /// Handle any declaration-declaration name conflicts and emit warnings. + final declConflictHandler = UniqueNamer({}); + for (final b in this.bindings) { + _warnIfPrivateDeclaration(b); + _resolveIfNameConflicts(declConflictHandler, b); + } + + // Override pack values according to config. We do this after declaration + // conflicts have been handled so that users can target the generated names. + if (packingOverride != null) { + for (final b in this.bindings) { + if (b is Struct) { + final pack = packingOverride(Declaration( + usr: b.usr, + originalName: b.originalName, + )); + if (pack != null) { + b.pack = pack.value; + } + } + } + } + + // Seperate bindings which require lookup. + final lookupBindings = []; + final nativeBindings = []; + FfiNativeConfig? nativeConfig; + + for (final binding in this.bindings.whereType()) { + final nativeConfigForBinding = switch (binding) { + Func() => binding.ffiNativeConfig, + Global() => binding.nativeConfig, + _ => null, + }; + + // At the moment, all bindings share their native config. + nativeConfig ??= nativeConfigForBinding; + + final usesLookup = + nativeConfigForBinding == null || !nativeConfigForBinding.enabled; + (usesLookup ? lookupBindings : nativeBindings).add(binding); + } + final noLookUpBindings = + this.bindings.whereType().toList(); + + _writer = Writer( + lookUpBindings: lookupBindings, + ffiNativeBindings: nativeBindings, + nativeAssetId: nativeConfig?.assetId, + noLookUpBindings: noLookUpBindings, + className: name, + classDocComment: description, + header: header, + additionalImports: libraryImports, + generateForPackageObjectiveC: generateForPackageObjectiveC, + silenceEnumWarning: silenceEnumWarning, + nativeEntryPoints: nativeEntryPoints, + ); + } + + void _findBindings(List original, bool sort) { + /// Get all dependencies (includes itself). + final dependencies = {}; + for (final b in original) { + b.addDependencies(dependencies); + } + + /// Save bindings. + bindings = dependencies.toList(); + if (sort) { + bindings.sortBy((b) => b.name); + } + } + + /// Logs a warning if generated declaration will be private. + void _warnIfPrivateDeclaration(Binding b) { + if (b.name.startsWith('_') && !b.isInternal) { + _logger.warning("Generated declaration '${b.name}' starts with '_' " + 'and therefore will be private.'); + } + } + + /// Resolves name conflict(if any) and logs a warning. + void _resolveIfNameConflicts(UniqueNamer namer, Binding b) { + // Print warning if name was conflicting and has been changed. + if (namer.isUsed(b.name)) { + final oldName = b.name; + b.name = namer.makeUnique(b.name); + + _logger.warning("Resolved name conflict: Declaration '$oldName' " + "and has been renamed to '${b.name}'."); + } else { + namer.markUsed(b.name); + } + } + + /// Generates [file] by generating C bindings. + void generateFile(File file, {bool format = true}) { + if (!file.existsSync()) file.createSync(recursive: true); + var content = generate(); + if (format) { + content = _formatter.format(content); + } + file.writeAsStringSync(content); + } + + /// Generates [file] with the Objective C code needed for the bindings, if + /// any. + /// + /// Returns whether bindings were generated. + bool generateObjCFile(File file) { + final bindings = writer.generateObjC(file.path); + + if (bindings == null) { + // No ObjC code needed. If there's already a file (eg from an earlier + // run), delete it so it's not accidentally included in the build. + if (file.existsSync()) file.deleteSync(); + return false; + } + + if (!file.existsSync()) file.createSync(recursive: true); + file.writeAsStringSync(bindings); + return true; + } + + /// Generates [file] with symbol output yaml. + void generateSymbolOutputFile(File file, String importPath) { + if (!file.existsSync()) file.createSync(recursive: true); + final symbolFileYamlMap = writer.generateSymbolOutputYamlMap(importPath); + final yamlEditor = YamlEditor(''); + yamlEditor.update([], wrapAsYamlNode(symbolFileYamlMap)); + var yamlString = yamlEditor.toString(); + if (!yamlString.endsWith('\n')) { + yamlString += '\n'; + } + file.writeAsStringSync(yamlString); + } + + /// Generates the bindings. + String generate() { + return writer.generate(); + } + + @override + bool operator ==(Object other) => + other is Library && other.generate() == generate(); + + @override + int get hashCode => bindings.hashCode; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/native_type.dart b/pkgs/ffigenpad/lib/src/code_generator/native_type.dart new file mode 100644 index 0000000000..cb04c1a2a5 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/native_type.dart @@ -0,0 +1,89 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'writer.dart'; + +enum SupportedNativeType { + voidType, + char, + int8, + int16, + int32, + int64, + uint8, + uint16, + uint32, + uint64, + float, + double, + intPtr, + uintPtr, +} + +/// Represents a primitive native type, such as float. +class NativeType extends Type { + static const _primitives = { + SupportedNativeType.voidType: NativeType._('Void', 'void', 'void', null), + SupportedNativeType.char: NativeType._('Uint8', 'int', 'char', '0'), + SupportedNativeType.int8: NativeType._('Int8', 'int', 'int8_t', '0'), + SupportedNativeType.int16: NativeType._('Int16', 'int', 'int16_t', '0'), + SupportedNativeType.int32: NativeType._('Int32', 'int', 'int32_t', '0'), + SupportedNativeType.int64: NativeType._('Int64', 'int', 'int64_t', '0'), + SupportedNativeType.uint8: NativeType._('Uint8', 'int', 'uint8_t', '0'), + SupportedNativeType.uint16: NativeType._('Uint16', 'int', 'uint16_t', '0'), + SupportedNativeType.uint32: NativeType._('Uint32', 'int', 'uint32_t', '0'), + SupportedNativeType.uint64: NativeType._('Uint64', 'int', 'uint64_t', '0'), + SupportedNativeType.float: NativeType._('Float', 'double', 'float', '0.0'), + SupportedNativeType.double: + NativeType._('Double', 'double', 'double', '0.0'), + SupportedNativeType.intPtr: NativeType._('IntPtr', 'int', 'intptr_t', '0'), + SupportedNativeType.uintPtr: + NativeType._('UintPtr', 'int', 'uintptr_t', '0'), + }; + + final String _cType; + final String _dartType; + final String _nativeType; + final String? _defaultValue; + + const NativeType._( + this._cType, this._dartType, this._nativeType, this._defaultValue); + + factory NativeType(SupportedNativeType type) => _primitives[type]!; + + @override + String getCType(Writer w) => '${w.ffiLibraryPrefix}.$_cType'; + + @override + String getFfiDartType(Writer w) => _dartType; + + @override + String getNativeType({String varName = ''}) => '$_nativeType $varName'; + + @override + bool get sameFfiDartAndCType => _cType == _dartType; + + @override + String toString() => _cType; + + @override + String cacheKey() => _cType; + + @override + String? getDefaultValue(Writer w) => _defaultValue; +} + +class BooleanType extends NativeType { + const BooleanType._() : super._('Bool', 'bool', 'BOOL', 'false'); + static const _boolean = BooleanType._(); + factory BooleanType() => _boolean; + + @override + String toString() => 'bool'; + + @override + String cacheKey() => 'bool'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/objc_block.dart b/pkgs/ffigenpad/lib/src/code_generator/objc_block.dart new file mode 100644 index 0000000000..4841297615 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/objc_block.dart @@ -0,0 +1,327 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; +import '../config_provider/config_types.dart'; +import '../header_parser/data.dart' show bindingsIndex; + +import 'binding_string.dart'; +import 'writer.dart'; + +class ObjCBlock extends BindingType { + final Type returnType; + final List argTypes; + Func? _wrapListenerBlock; + + factory ObjCBlock({ + required Type returnType, + required List argTypes, + }) { + final usr = _getBlockUsr(returnType, argTypes); + + final oldBlock = bindingsIndex.getSeenObjCBlock(usr); + if (oldBlock != null) { + return oldBlock; + } + + final block = ObjCBlock._( + usr: usr, + name: _getBlockName(returnType, argTypes), + returnType: returnType, + argTypes: argTypes, + ); + bindingsIndex.addObjCBlockToSeen(usr, block); + + return block; + } + + ObjCBlock._({ + required String super.usr, + required super.name, + required this.returnType, + required this.argTypes, + }) : super(originalName: name); + + // Generates a human readable name for the block based on the args and return + // type. These names will be pretty verbose and unweildy, but they're at least + // sensible and stable. Users can always add their own typedef with a simpler + // name if necessary. + static String _getBlockName(Type returnType, List argTypes) => + 'ObjCBlock_${[returnType, ...argTypes].map(_typeName).join('_')}'; + static String _typeName(Type type) => + type.toString().replaceAll(_illegalNameChar, ''); + static final _illegalNameChar = RegExp(r'[^0-9a-zA-Z]'); + + static String _getBlockUsr(Type returnType, List argTypes) { + // Create a fake USR code for the block. This code is used to dedupe blocks + // with the same signature. + final usr = StringBuffer(); + usr.write('objcBlock: ${returnType.cacheKey()}'); + for (final type in argTypes) { + usr.write(' ${type.cacheKey()}'); + } + return usr.toString(); + } + + bool get hasListener => returnType == voidType; + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + + final params = []; + for (var i = 0; i < argTypes.length; ++i) { + params.add(Parameter(name: 'arg$i', type: argTypes[i])); + } + + final voidPtr = PointerType(voidType).getCType(w); + final blockPtr = PointerType(objCBlockType); + final funcType = FunctionType(returnType: returnType, parameters: params); + final natFnType = NativeFunc(funcType); + final natFnPtr = PointerType(natFnType).getCType(w); + final funcPtrTrampoline = + w.topLevelUniqueNamer.makeUnique('_${name}_fnPtrTrampoline'); + final closureTrampoline = + w.topLevelUniqueNamer.makeUnique('_${name}_closureTrampoline'); + final newPointerBlock = ObjCBuiltInFunctions.newPointerBlock.gen(w); + final newClosureBlock = ObjCBuiltInFunctions.newClosureBlock.gen(w); + final getBlockClosure = ObjCBuiltInFunctions.getBlockClosure.gen(w); + final trampFuncType = FunctionType( + returnType: returnType, + parameters: [Parameter(type: blockPtr, name: 'block'), ...params]); + final trampFuncCType = trampFuncType.getCType(w, writeArgumentNames: false); + final trampFuncFfiDartType = + trampFuncType.getFfiDartType(w, writeArgumentNames: false); + final natTrampFnType = NativeFunc(trampFuncType).getCType(w); + final nativeCallableType = + '${w.ffiLibraryPrefix}.NativeCallable<$trampFuncCType>'; + final funcDartType = funcType.getDartType(w, writeArgumentNames: false); + final funcFfiDartType = + funcType.getFfiDartType(w, writeArgumentNames: false); + final returnFfiDartType = returnType.getFfiDartType(w); + final blockCType = blockPtr.getCType(w); + + final paramsNameOnly = params.map((p) => p.name).join(', '); + final paramsFfiDartType = + params.map((p) => '${p.type.getFfiDartType(w)} ${p.name}').join(', '); + final paramsDartType = + params.map((p) => '${p.type.getDartType(w)} ${p.name}').join(', '); + + // Write the function pointer based trampoline function. + s.write(''' +$returnFfiDartType $funcPtrTrampoline($blockCType block, $paramsFfiDartType) => + block.ref.target.cast<${natFnType.getFfiDartType(w)}>() + .asFunction<$funcFfiDartType>()($paramsNameOnly); +'''); + + // Write the closure based trampoline function. + s.write(''' +$returnFfiDartType $closureTrampoline($blockCType block, $paramsFfiDartType) => + ($getBlockClosure(block) as $funcFfiDartType)($paramsNameOnly); +'''); + + // Snippet that converts a Dart typed closure to FfiDart type. This snippet + // is used below. Note that the closure being converted is called `fn`. + final convertedFnArgs = params + .map((p) => + p.type.convertFfiDartTypeToDartType(w, p.name, objCRetain: true)) + .join(', '); + final convFnInvocation = returnType.convertDartTypeToFfiDartType( + w, 'fn($convertedFnArgs)', + objCRetain: true); + final convFn = '($paramsFfiDartType) => $convFnInvocation'; + + // Write the wrapper class. + final defaultValue = returnType.getDefaultValue(w); + final exceptionalReturn = defaultValue == null ? '' : ', $defaultValue'; + s.write(''' +class $name extends ${ObjCBuiltInFunctions.blockBase.gen(w)} { + $name._($blockCType pointer, + {bool retain = false, bool release = true}) : + super(pointer, retain: retain, release: release); + + /// Returns a block that wraps the given raw block pointer. + static $name castFromPointer($blockCType pointer, + {bool retain = false, bool release = false}) { + return $name._(pointer, retain: retain, release: release); + } + + /// Creates a block from a C function pointer. + /// + /// This block must be invoked by native code running on the same thread as + /// the isolate that registered it. Invoking the block on the wrong thread + /// will result in a crash. + $name.fromFunctionPointer($natFnPtr ptr) : + this._($newPointerBlock( + _cFuncTrampoline ??= ${w.ffiLibraryPrefix}.Pointer.fromFunction< + $trampFuncCType>($funcPtrTrampoline + $exceptionalReturn).cast(), ptr.cast())); + static $voidPtr? _cFuncTrampoline; + + /// Creates a block from a Dart function. + /// + /// This block must be invoked by native code running on the same thread as + /// the isolate that registered it. Invoking the block on the wrong thread + /// will result in a crash. + $name.fromFunction($funcDartType fn) : + this._($newClosureBlock( + _dartFuncTrampoline ??= ${w.ffiLibraryPrefix}.Pointer.fromFunction< + $trampFuncCType>($closureTrampoline $exceptionalReturn).cast(), + $convFn)); + static $voidPtr? _dartFuncTrampoline; + +'''); + + // Listener block constructor is only available for void blocks. + if (hasListener) { + // This snippet is the same as the convFn above, except that the args + // don't need to be retained because they've already been retained by + // _wrapListenerBlock. + final listenerConvertedFnArgs = params + .map((p) => + p.type.convertFfiDartTypeToDartType(w, p.name, objCRetain: false)) + .join(', '); + final listenerConvFnInvocation = returnType.convertDartTypeToFfiDartType( + w, 'fn($listenerConvertedFnArgs)', + objCRetain: true); + final listenerConvFn = + '($paramsFfiDartType) => $listenerConvFnInvocation'; + + s.write(''' + /// Creates a listener block from a Dart function. + /// + /// This is based on FFI's NativeCallable.listener, and has the same + /// capabilities and limitations. This block can be invoked from any thread, + /// but only supports void functions, and is not run synchronously. See + /// NativeCallable.listener for more details. + /// + /// Note that unlike the default behavior of NativeCallable.listener, listener + /// blocks do not keep the isolate alive. + $name.listener($funcDartType fn) : + this._(${_wrapListenerBlock?.name ?? ''}($newClosureBlock( + (_dartFuncListenerTrampoline ??= $nativeCallableType.listener( + $closureTrampoline $exceptionalReturn)..keepIsolateAlive = + false).nativeFunction.cast(), $listenerConvFn))); + static $nativeCallableType? _dartFuncListenerTrampoline; + +'''); + } + + // Call method. + s.write(' ${returnType.getDartType(w)} call($paramsDartType) =>'); + final callMethodArgs = params + .map((p) => + p.type.convertDartTypeToFfiDartType(w, p.name, objCRetain: false)) + .join(', '); + final callMethodInvocation = ''' +pointer.ref.invoke.cast<$natTrampFnType>().asFunction<$trampFuncFfiDartType>()( + pointer, $callMethodArgs)'''; + s.write(returnType.convertFfiDartTypeToDartType(w, callMethodInvocation, + objCRetain: false)); + s.write(';\n'); + + s.write('}\n'); + return BindingString( + type: BindingStringType.objcBlock, string: s.toString()); + } + + @override + BindingString? toObjCBindingString(Writer w) { + if (_wrapListenerBlock == null) return null; + + final argsReceived = []; + final retains = []; + for (var i = 0; i < argTypes.length; ++i) { + final t = argTypes[i]; + final argName = 'arg$i'; + argsReceived.add(t.getNativeType(varName: argName)); + retains.add(t.generateRetain(argName) ?? argName); + } + final fnName = _wrapListenerBlock!.name; + final blockTypedef = w.objCLevelUniqueNamer.makeUnique('ListenerBlock'); + + final s = StringBuffer(); + s.write(''' + +typedef ${getNativeType(varName: blockTypedef)}; +$blockTypedef $fnName($blockTypedef block) { + $blockTypedef wrapper = [^void(${argsReceived.join(', ')}) { + block(${retains.join(', ')}); + } copy]; + [block release]; + return wrapper; +} +'''); + return BindingString( + type: BindingStringType.objcBlock, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + dependencies.add(this); + + returnType.addDependencies(dependencies); + for (final t in argTypes) { + t.addDependencies(dependencies); + } + + if (hasListener && argTypes.any((t) => t.generateRetain('') != null)) { + _wrapListenerBlock = Func( + name: 'wrapListenerBlock_$name', + returnType: this, + parameters: [Parameter(name: 'block', type: this)], + objCReturnsRetained: true, + isLeaf: true, + isInternal: true, + useNameForLookup: true, + ffiNativeConfig: const FfiNativeConfig(enabled: true), + )..addDependencies(dependencies); + } + } + + @override + String getCType(Writer w) => PointerType(objCBlockType).getCType(w); + + @override + String getDartType(Writer w) => name; + + @override + String getNativeType({String varName = ''}) { + final args = argTypes.map((t) => t.getNativeType()); + return '${returnType.getNativeType()} (^$varName)(${args.join(', ')})'; + } + + @override + bool get sameFfiDartAndCType => true; + + @override + bool get sameDartAndCType => false; + + @override + bool get sameDartAndFfiDartType => false; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + ObjCInterface.generateGetId(value, objCRetain); + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + ObjCInterface.generateConstructor(name, value, objCRetain); + + @override + String? generateRetain(String value) => '[$value copy]'; + + @override + String toString() => '($returnType (^)(${argTypes.join(', ')}))'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/objc_built_in_functions.dart b/pkgs/ffigenpad/lib/src/code_generator/objc_built_in_functions.dart new file mode 100644 index 0000000000..6245d670d3 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/objc_built_in_functions.dart @@ -0,0 +1,334 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'binding_string.dart'; +import 'writer.dart'; + +/// Built in functions used by the Objective C bindings. +class ObjCBuiltInFunctions { + ObjCBuiltInFunctions(this.generateForPackageObjectiveC); + + final bool generateForPackageObjectiveC; + + static const registerName = ObjCImport('registerName'); + static const getClass = ObjCImport('getClass'); + static const msgSendPointer = ObjCImport('msgSendPointer'); + static const msgSendFpretPointer = ObjCImport('msgSendFpretPointer'); + static const msgSendStretPointer = ObjCImport('msgSendStretPointer'); + static const useMsgSendVariants = ObjCImport('useMsgSendVariants'); + static const newPointerBlock = ObjCImport('newPointerBlock'); + static const newClosureBlock = ObjCImport('newClosureBlock'); + static const getBlockClosure = ObjCImport('getBlockClosure'); + static const getProtocolMethodSignature = + ObjCImport('getProtocolMethodSignature'); + static const getProtocol = ObjCImport('getProtocol'); + static const objectBase = ObjCImport('ObjCObjectBase'); + static const blockBase = ObjCImport('ObjCBlockBase'); + static const protocolMethod = ObjCImport('ObjCProtocolMethod'); + static const protocolListenableMethod = + ObjCImport('ObjCProtocolListenableMethod'); + static const protocolBuilder = ObjCImport('ObjCProtocolBuilder'); + static const dartProxy = ObjCImport('DartProxy'); + + // Keep in sync with pkgs/objective_c/ffigen_objc.yaml. + static const builtInInterfaces = { + 'DartProxy', + 'DartProxyBuilder', + 'NSArray', + 'NSCharacterSet', + 'NSCoder', + 'NSData', + 'NSDate', + 'NSDictionary', + 'NSEnumerator', + 'NSError', + 'NSIndexSet', + 'NSInvocation', + 'NSItemProvider', + 'NSLocale', + 'NSMethodSignature', + 'NSMutableArray', + 'NSMutableData', + 'NSMutableDictionary', + 'NSMutableIndexSet', + 'NSMutableOrderedSet', + 'NSMutableSet', + 'NSMutableString', + 'NSNotification', + 'NSNumber', + 'NSObject', + 'NSOrderedSet', + 'NSProxy', + 'NSSet', + 'NSString', + 'NSURL', + 'NSURLHandle', + 'NSValue', + 'Protocol', + }; + static const builtInCompounds = { + 'NSFastEnumerationState', + 'NSRange', + }; + static const builtInEnums = { + 'NSBinarySearchingOptions', + 'NSComparisonResult', + 'NSDataBase64DecodingOptions', + 'NSDataBase64EncodingOptions', + 'NSDataCompressionAlgorithm', + 'NSDataReadingOptions', + 'NSDataSearchOptions', + 'NSDataWritingOptions', + 'NSEnumerationOptions', + 'NSItemProviderFileOptions', + 'NSItemProviderRepresentationVisibility', + 'NSKeyValueChange', + 'NSKeyValueObservingOptions', + 'NSKeyValueSetMutationKind', + 'NSOrderedCollectionDifferenceCalculationOptions', + 'NSSortOptions', + 'NSStringCompareOptions', + 'NSStringEncodingConversionOptions', + 'NSStringEnumerationOptions', + 'NSURLBookmarkCreationOptions', + 'NSURLBookmarkResolutionOptions', + 'NSURLHandleStatus', + }; + + // TODO(https://github.com/dart-lang/native/issues/1173): Ideally this check + // would be based on more than just the name. + bool isBuiltInInterface(String name) => + !generateForPackageObjectiveC && builtInInterfaces.contains(name); + bool isBuiltInCompound(String name) => + !generateForPackageObjectiveC && builtInCompounds.contains(name); + bool isBuiltInEnum(String name) => + !generateForPackageObjectiveC && builtInEnums.contains(name); + bool isNSObject(String name) => name == 'NSObject'; + + // We need to load a separate instance of objc_msgSend for each signature. If + // the return type is a struct, we need to use objc_msgSend_stret instead, and + // for float return types we need objc_msgSend_fpret. + final _msgSendFuncs = {}; + ObjCMsgSendFunc getMsgSendFunc( + Type returnType, List params) { + var key = returnType.cacheKey(); + for (final p in params) { + key += ' ${p.type.cacheKey()}'; + } + return _msgSendFuncs[key] ??= ObjCMsgSendFunc( + '_objc_msgSend_${_msgSendFuncs.length}', + returnType, + params, + useMsgSendVariants); + } + + final _selObjects = {}; + ObjCInternalGlobal getSelObject(String methodName) { + return _selObjects[methodName] ??= ObjCInternalGlobal( + '_sel_${methodName.replaceAll(":", "_")}', + (Writer w) => '${registerName.gen(w)}("$methodName")', + ); + } + + void addDependencies(Set dependencies) { + for (final msgSendFunc in _msgSendFuncs.values) { + msgSendFunc.addDependencies(dependencies); + } + for (final sel in _selObjects.values) { + sel.addDependencies(dependencies); + } + } + + static bool isInstanceType(Type type) { + if (type is ObjCInstanceType) return true; + final baseType = type.typealiasType; + return baseType is ObjCNullable && baseType.child is ObjCInstanceType; + } +} + +/// A function, global variable, or helper type defined in package:objective_c. +class ObjCImport { + final String name; + + const ObjCImport(this.name); + + String gen(Writer w) => '${w.objcPkgPrefix}.$name'; +} + +/// Globals only used internally by ObjC bindings, such as classes and SELs. +class ObjCInternalGlobal extends NoLookUpBinding { + final String Function(Writer) makeValue; + + ObjCInternalGlobal(String name, this.makeValue) + : super(originalName: name, name: name, isInternal: true); + + @override + BindingString toBindingString(Writer w) { + final s = StringBuffer(); + name = w.wrapperLevelUniqueNamer.makeUnique(name); + s.write('late final $name = ${makeValue(w)};\n'); + return BindingString(type: BindingStringType.global, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + dependencies.add(this); + } +} + +enum ObjCMsgSendVariant { + normal(ObjCBuiltInFunctions.msgSendPointer), + stret(ObjCBuiltInFunctions.msgSendStretPointer), + fpret(ObjCBuiltInFunctions.msgSendFpretPointer); + + final ObjCImport pointer; + const ObjCMsgSendVariant(this.pointer); + + static ObjCMsgSendVariant fromReturnType(Type returnType) { + if (returnType is Compound && returnType.isStruct) { + return ObjCMsgSendVariant.stret; + } else if (returnType == floatType || returnType == doubleType) { + return ObjCMsgSendVariant.fpret; + } + return ObjCMsgSendVariant.normal; + } +} + +class ObjCMsgSendVariantFunc extends NoLookUpBinding { + ObjCMsgSendVariant variant; + FunctionType type; + + ObjCMsgSendVariantFunc( + {required super.name, + required this.variant, + required Type returnType, + required List parameters}) + : type = FunctionType(returnType: returnType, parameters: parameters), + super(isInternal: true); + + @override + BindingString toBindingString(Writer w) { + final cType = NativeFunc(type).getCType(w); + final dartType = type.getFfiDartType(w, writeArgumentNames: false); + final pointer = variant.pointer.gen(w); + + final bindingString = ''' +final $name = $pointer.cast<$cType>().asFunction<$dartType>(); +'''; + + return BindingString(type: BindingStringType.func, string: bindingString); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + dependencies.add(this); + type.addDependencies(dependencies); + } +} + +/// A wrapper around the objc_msgSend function, or the stret or fpret variants. +/// +/// The [variant] is based purely on the return type of the method. +/// +/// For the stret and fpret variants, we may need to fall back to the normal +/// objc_msgSend function at runtime, depending on the ABI. So we emit both the +/// variant function and the normal function, and decide which to use at runtime +/// based on the ABI. The result of the ABI check is stored in [useVariants]. +/// +/// This runtime check is complicated by the fact that objc_msgSend_stret has +/// a different signature than objc_msgSend has for the same method. This is +/// because objc_msgSend_stret takes a pointer to the return type as its first +/// arg. +class ObjCMsgSendFunc { + final ObjCMsgSendVariant variant; + final ObjCImport useVariants; + + // [normalFunc] is always a reference to the normal objc_msgSend function. If + // the [variant] is fpret or stret, then [variantFunc] is a reference to the + // corresponding variant of the objc_msgSend function, otherwise it's null. + late final ObjCMsgSendVariantFunc normalFunc; + late final ObjCMsgSendVariantFunc? variantFunc; + + ObjCMsgSendFunc(String name, Type returnType, List params, + this.useVariants) + : variant = ObjCMsgSendVariant.fromReturnType(returnType) { + normalFunc = ObjCMsgSendVariantFunc( + name: name, + variant: ObjCMsgSendVariant.normal, + returnType: returnType, + parameters: _params(params), + ); + switch (variant) { + case ObjCMsgSendVariant.normal: + variantFunc = null; + case ObjCMsgSendVariant.fpret: + variantFunc = ObjCMsgSendVariantFunc( + name: '${name}Fpret', + variant: variant, + returnType: returnType, + parameters: _params(params), + ); + case ObjCMsgSendVariant.stret: + variantFunc = ObjCMsgSendVariantFunc( + name: '${name}Stret', + variant: variant, + returnType: voidType, + parameters: _params(params, structRetPtr: PointerType(returnType)), + ); + } + } + + static List _params(List params, + {Type? structRetPtr}) { + return [ + if (structRetPtr != null) Parameter(type: structRetPtr), + Parameter(type: PointerType(objCObjectType)), + Parameter(type: PointerType(objCSelType)), + for (final p in params) Parameter(type: p.type), + ]; + } + + bool get isStret => variant == ObjCMsgSendVariant.stret; + + void addDependencies(Set dependencies) { + normalFunc.addDependencies(dependencies); + variantFunc?.addDependencies(dependencies); + } + + String invoke(Writer w, String target, String sel, Iterable params, + {String? structRetPtr}) { + final normalCall = _invoke(normalFunc.name, target, sel, params); + switch (variant) { + case ObjCMsgSendVariant.normal: + return normalCall; + case ObjCMsgSendVariant.fpret: + final fpretCall = _invoke(variantFunc!.name, target, sel, params); + return '${useVariants.gen(w)} ? $fpretCall : $normalCall'; + case ObjCMsgSendVariant.stret: + final stretCall = _invoke(variantFunc!.name, target, sel, params, + structRetPtr: structRetPtr); + return '${useVariants.gen(w)} ? $stretCall : ' + '$structRetPtr.ref = $normalCall'; + } + } + + static String _invoke( + String name, + String target, + String sel, + Iterable params, { + String? structRetPtr, + }) { + return '''$name(${[ + if (structRetPtr != null) structRetPtr, + target, + sel, + ...params, + ].join(', ')})'''; + } +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/objc_interface.dart b/pkgs/ffigenpad/lib/src/code_generator/objc_interface.dart new file mode 100644 index 0000000000..47c711a036 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/objc_interface.dart @@ -0,0 +1,350 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'binding_string.dart'; +import 'utils.dart'; +import 'writer.dart'; + +// Class methods defined on NSObject that we don't want to copy to child objects +// by default. +const _excludedNSObjectClassMethods = { + 'allocWithZone:', + 'class', + 'conformsToProtocol:', + 'copyWithZone:', + 'debugDescription', + 'description', + 'hash', + 'initialize', + 'instanceMethodForSelector:', + 'instanceMethodSignatureForSelector:', + 'instancesRespondToSelector:', + 'isSubclassOfClass:', + 'load', + 'mutableCopyWithZone:', + 'poseAsClass:', + 'resolveClassMethod:', + 'resolveInstanceMethod:', + 'setVersion:', + 'superclass', + 'version', +}; + +class ObjCInterface extends BindingType with ObjCMethods { + ObjCInterface? superType; + bool filled = false; + + final String lookupName; + late final ObjCInternalGlobal _classObject; + late final ObjCInternalGlobal _isKindOfClass; + late final ObjCMsgSendFunc _isKindOfClassMsgSend; + + @override + final ObjCBuiltInFunctions builtInFunctions; + + ObjCInterface({ + super.usr, + required String super.originalName, + String? name, + String? lookupName, + super.dartDoc, + required this.builtInFunctions, + }) : lookupName = lookupName ?? originalName, + super(name: name ?? originalName); + + bool get _isBuiltIn => builtInFunctions.isBuiltInInterface(originalName); + + @override + BindingString toBindingString(Writer w) { + if (_isBuiltIn) { + return const BindingString( + type: BindingStringType.objcInterface, string: ''); + } + + String paramsToString(List params, + {required bool isStatic}) { + final stringParams = []; + + stringParams.addAll( + params.map((p) => '${_getConvertedType(p.type, w, name)} ${p.name}')); + return '(${stringParams.join(", ")})'; + } + + final s = StringBuffer(); + s.write(makeDartDoc(dartDoc ?? originalName)); + + final methodNamer = createMethodRenamer(w); + + final rawObjType = PointerType(objCObjectType).getCType(w); + final wrapObjType = ObjCBuiltInFunctions.objectBase.gen(w); + + final superTypeIsInPkgObjc = superType == null; + + // Class declaration. + s.write('''class $name extends ${superType?.getDartType(w) ?? wrapObjType} { + $name._($rawObjType pointer, + {bool retain = false, bool release = false}) : + ${superTypeIsInPkgObjc ? 'super' : 'super.castFromPointer'} + (pointer, retain: retain, release: release); + + /// Constructs a [$name] that points to the same underlying object as [other]. + $name.castFrom($wrapObjType other) : + this._(other.pointer, retain: true, release: true); + + /// Constructs a [$name] that wraps the given raw object pointer. + $name.castFromPointer($rawObjType other, + {bool retain = false, bool release = false}) : + this._(other, retain: retain, release: release); + + /// Returns whether [obj] is an instance of [$name]. + static bool isInstance($wrapObjType obj) { + return ${_isKindOfClassMsgSend.invoke( + w, + 'obj.pointer', + _isKindOfClass.name, + [_classObject.name], + )}; + } + +'''); + + // Methods. + for (final m in methods) { + final methodName = m.getDartMethodName(methodNamer); + final isStatic = m.isClassMethod; + final isStret = m.msgSend!.isStret; + + var returnType = m.returnType; + var params = m.params; + if (isStret) { + params = [ObjCMethodParam(PointerType(returnType), 'stret'), ...params]; + returnType = voidType; + } + + // The method declaration. + s.write(makeDartDoc(m.dartDoc ?? m.originalName)); + s.write(' '); + if (isStatic) { + s.write('static '); + s.write(_getConvertedType(returnType, w, name)); + + switch (m.kind) { + case ObjCMethodKind.method: + // static returnType methodName(...) + s.write(' $methodName'); + break; + case ObjCMethodKind.propertyGetter: + // static returnType getMethodName() + s.write(' get'); + s.write(methodName[0].toUpperCase() + methodName.substring(1)); + break; + case ObjCMethodKind.propertySetter: + // static void setMethodName(...) + s.write(' set'); + s.write(methodName[0].toUpperCase() + methodName.substring(1)); + break; + } + s.write(paramsToString(params, isStatic: true)); + } else { + switch (m.kind) { + case ObjCMethodKind.method: + // returnType methodName(...) + s.write(_getConvertedType(returnType, w, name)); + s.write(' $methodName'); + s.write(paramsToString(params, isStatic: false)); + break; + case ObjCMethodKind.propertyGetter: + s.write(_getConvertedType(returnType, w, name)); + if (isStret) { + // void getMethodName(Pointer stret) + s.write(' get'); + s.write(methodName[0].toUpperCase() + methodName.substring(1)); + s.write(paramsToString(params, isStatic: false)); + } else { + // returnType get methodName + s.write(' get $methodName'); + } + break; + case ObjCMethodKind.propertySetter: + // set methodName(...) + s.write(' set $methodName'); + s.write(paramsToString(params, isStatic: false)); + break; + } + } + + s.write(' {\n'); + + // Implementation. + final convertReturn = m.kind != ObjCMethodKind.propertySetter && + !returnType.sameDartAndFfiDartType; + + if (returnType != voidType) { + s.write(' ${convertReturn ? 'final _ret = ' : 'return '}'); + } + s.write(m.msgSend!.invoke( + w, + isStatic ? _classObject.name : 'this.pointer', + m.selObject!.name, + m.params.map((p) => p.type + .convertDartTypeToFfiDartType(w, p.name, objCRetain: false)), + structRetPtr: 'stret')); + s.write(';\n'); + if (convertReturn) { + final result = returnType.convertFfiDartTypeToDartType( + w, + '_ret', + objCRetain: !m.isOwnedReturn, + objCEnclosingClass: name, + ); + s.write(' return $result;'); + } + + s.write(' }\n\n'); + } + + s.write('}\n\n'); + + return BindingString( + type: BindingStringType.objcInterface, string: s.toString()); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this) || _isBuiltIn) return; + dependencies.add(this); + + _classObject = ObjCInternalGlobal('_class_$originalName', + (Writer w) => '${ObjCBuiltInFunctions.getClass.gen(w)}("$lookupName")') + ..addDependencies(dependencies); + _isKindOfClass = builtInFunctions.getSelObject('isKindOfClass:'); + _isKindOfClassMsgSend = builtInFunctions.getMsgSendFunc( + BooleanType(), [ObjCMethodParam(PointerType(objCObjectType), 'clazz')]); + + addMethodDependencies(dependencies, needMsgSend: true); + + if (superType != null) { + superType!.addDependencies(dependencies); + _copyMethodsFromSuperType(); + _fixNullabilityOfOverriddenMethods(); + + // Add dependencies for any methods that were added. + addMethodDependencies(dependencies, needMsgSend: true); + } + + builtInFunctions.addDependencies(dependencies); + } + + void _copyMethodsFromSuperType() { + // We need to copy certain methods from the super type: + // - Class methods, because Dart classes don't inherit static methods. + // - Methods that return instancetype, because the subclass's copy of the + // method needs to return the subclass, not the super class. + // Note: instancetype is only allowed as a return type, not an arg type. + for (final m in superType!.methods) { + if (m.isClassMethod && + !_excludedNSObjectClassMethods.contains(m.originalName)) { + addMethod(m); + } else if (ObjCBuiltInFunctions.isInstanceType(m.returnType)) { + addMethod(m); + } + } + } + + void _fixNullabilityOfOverriddenMethods() { + // ObjC ignores nullability when deciding if an override for an inherited + // method is valid. But in Dart it's invalid to override a method and change + // it's return type from non-null to nullable, or its arg type from nullable + // to non-null. So in these cases we have to make the non-null type + // nullable, to avoid Dart compile errors. + var superType_ = superType; + while (superType_ != null) { + for (final method in methods) { + final superMethod = superType_.getMethod(method.originalName); + if (superMethod != null && + !superMethod.isClassMethod && + !method.isClassMethod) { + if (superMethod.returnType.typealiasType is! ObjCNullable && + method.returnType.typealiasType is ObjCNullable) { + superMethod.returnType = ObjCNullable(superMethod.returnType); + } + final numArgs = method.params.length < superMethod.params.length + ? method.params.length + : superMethod.params.length; + for (var i = 0; i < numArgs; ++i) { + final param = method.params[i]; + final superParam = superMethod.params[i]; + if (superParam.type.typealiasType is ObjCNullable && + param.type.typealiasType is! ObjCNullable) { + param.type = ObjCNullable(param.type); + } + } + } + } + superType_ = superType_.superType; + } + } + + @override + String getCType(Writer w) => PointerType(objCObjectType).getCType(w); + + @override + String getDartType(Writer w) => + _isBuiltIn ? '${w.objcPkgPrefix}.$name' : name; + + @override + String getNativeType({String varName = ''}) => '$originalName* $varName'; + + @override + bool get sameFfiDartAndCType => true; + + @override + bool get sameDartAndCType => false; + + @override + bool get sameDartAndFfiDartType => false; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + ObjCInterface.generateGetId(value, objCRetain); + + static String generateGetId(String value, bool objCRetain) => + objCRetain ? '$value.retainAndReturnPointer()' : '$value.pointer'; + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + ObjCInterface.generateConstructor(getDartType(w), value, objCRetain); + + static String generateConstructor( + String className, + String value, + bool objCRetain, + ) { + final ownershipFlags = 'retain: $objCRetain, release: true'; + return '$className.castFromPointer($value, $ownershipFlags)'; + } + + @override + String? generateRetain(String value) => '[$value retain]'; + + String _getConvertedType(Type type, Writer w, String enclosingClass) { + if (type is ObjCInstanceType) return enclosingClass; + final baseType = type.typealiasType; + if (baseType is ObjCNullable && baseType.child is ObjCInstanceType) { + return '$enclosingClass?'; + } + return type.getDartType(w); + } +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/objc_methods.dart b/pkgs/ffigenpad/lib/src/code_generator/objc_methods.dart new file mode 100644 index 0000000000..19e9fd030b --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/objc_methods.dart @@ -0,0 +1,230 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../code_generator.dart'; +import 'utils.dart'; +import 'writer.dart'; + +final _logger = Logger('ffigen.code_generator.objc_methods'); + +mixin ObjCMethods { + final _methods = {}; + + Iterable get methods => _methods.values; + ObjCMethod? getMethod(String name) => _methods[name]; + + String get originalName; + String get name; + ObjCBuiltInFunctions get builtInFunctions; + + void addMethod(ObjCMethod method) { + if (_shouldIncludeMethod(method)) { + _methods[method.originalName] = + _maybeReplaceMethod(getMethod(method.originalName), method); + } + } + + void addMethodDependencies( + Set dependencies, { + bool needMsgSend = false, + bool needProtocolBlock = false, + }) { + for (final m in methods) { + m.addDependencies(dependencies, builtInFunctions, + needMsgSend: needMsgSend, needProtocolBlock: needProtocolBlock); + } + } + + ObjCMethod _maybeReplaceMethod(ObjCMethod? oldMethod, ObjCMethod newMethod) { + if (oldMethod == null) return newMethod; + + // Typically we ignore duplicate methods. However, property setters and + // getters are duplicated in the AST. One copy is marked with + // ObjCMethodKind.propertyGetter/Setter. The other copy is missing + // important information, and is a plain old instanceMethod. So if the + // existing method is an instanceMethod, and the new one is a property, + // override it. + if (newMethod.isProperty && !oldMethod.isProperty) { + return newMethod; + } else if (!newMethod.isProperty && oldMethod.isProperty) { + // Don't override, but also skip the same method check below. + return oldMethod; + } + + // Check the duplicate is the same method. + if (!newMethod.sameAs(oldMethod)) { + _logger.severe('Duplicate methods with different signatures: ' + '$originalName.${newMethod.originalName}'); + return newMethod; + } + + // There's a bug in some Apple APIs where an init method that should return + // instancetype has a duplicate definition that instead returns id. In that + // case, use the one that returns instancetype. Note that since instancetype + // is an alias of id, the sameAs check above passes. + if (ObjCBuiltInFunctions.isInstanceType(newMethod.returnType) && + !ObjCBuiltInFunctions.isInstanceType(oldMethod.returnType)) { + return newMethod; + } else if (!ObjCBuiltInFunctions.isInstanceType(newMethod.returnType) && + ObjCBuiltInFunctions.isInstanceType(oldMethod.returnType)) { + return oldMethod; + } + + return newMethod; + } + + bool _shouldIncludeMethod(ObjCMethod method) => + method.childTypes.every((Type t) { + t = t.typealiasType.baseType; + + // Ignore methods with variadic args. + // TODO(https://github.com/dart-lang/native/issues/1192): Remove this. + if (t is Struct && t.originalName == '__va_list_tag') { + return false; + } + + // Ignore methods with block args or rets when we're generating in + // package:objective_c. + // TODO(https://github.com/dart-lang/native/issues/1180): Remove this. + if (builtInFunctions.generateForPackageObjectiveC && t is ObjCBlock) { + return false; + } + + return true; + }); + + UniqueNamer createMethodRenamer(Writer w) => UniqueNamer( + {name, 'pointer', 'toString', 'hashCode', 'runtimeType', 'noSuchMethod'}, + parent: w.topLevelUniqueNamer); +} + +enum ObjCMethodKind { + method, + propertyGetter, + propertySetter, +} + +class ObjCProperty { + final String originalName; + String? dartName; + + ObjCProperty(this.originalName); +} + +class ObjCMethod { + final String? dartDoc; + final String originalName; + final ObjCProperty? property; + Type returnType; + final List params; + final ObjCMethodKind kind; + final bool isClassMethod; + final bool isOptional; + bool returnsRetained = false; + ObjCInternalGlobal? selObject; + ObjCMsgSendFunc? msgSend; + late ObjCBlock protocolBlock; + + ObjCMethod({ + required this.originalName, + this.property, + this.dartDoc, + required this.kind, + required this.isClassMethod, + required this.isOptional, + required this.returnType, + List? params_, + }) : params = params_ ?? []; + + bool get isProperty => + kind == ObjCMethodKind.propertyGetter || + kind == ObjCMethodKind.propertySetter; + bool get isRequired => !isOptional; + bool get isInstanceMethod => !isClassMethod; + + void addDependencies( + Set dependencies, + ObjCBuiltInFunctions builtInFunctions, { + bool needMsgSend = false, + bool needProtocolBlock = false, + }) { + returnType.addDependencies(dependencies); + for (final p in params) { + p.type.addDependencies(dependencies); + } + selObject = builtInFunctions.getSelObject(originalName) + ..addDependencies(dependencies); + if (needMsgSend) { + msgSend = builtInFunctions.getMsgSendFunc(returnType, params) + ..addDependencies(dependencies); + } + if (needProtocolBlock) { + final argTypes = [ + // First arg of the protocol block is a void pointer that we ignore. + PointerType(voidType), + ...params.map((p) => p.type), + ]; + protocolBlock = ObjCBlock( + returnType: returnType, + argTypes: argTypes, + )..addDependencies(dependencies); + } + } + + String getDartMethodName(UniqueNamer uniqueNamer) { + if (property != null) { + // A getter and a setter are allowed to have the same name, so we can't + // just run the name through uniqueNamer. Instead they need to share + // the dartName, which is run through uniqueNamer. + if (property!.dartName == null) { + property!.dartName = uniqueNamer.makeUnique(property!.originalName); + } + return property!.dartName!; + } + // Objective C methods can look like: + // foo + // foo: + // foo:someArgName: + // So replace all ':' with '_'. + return uniqueNamer.makeUnique(originalName.replaceAll(':', '_')); + } + + bool sameAs(ObjCMethod other) { + if (originalName != other.originalName) return false; + if (kind != other.kind) return false; + if (isClassMethod != other.isClassMethod) return false; + if (isOptional != other.isOptional) return false; + // msgSend is deduped by signature, so this check covers the signature. + return msgSend == other.msgSend; + } + + static final _copyRegExp = RegExp('[cC]opy'); + bool get isOwnedReturn => + returnsRetained || + originalName.startsWith('new') || + originalName.startsWith('alloc') || + originalName.contains(_copyRegExp); + + Iterable get childTypes sync* { + yield returnType; + for (final p in params) { + yield p.type; + } + } + + @override + String toString() => '${isOptional ? "@optional " : ""}$returnType ' + '$originalName(${params.join(', ')})'; +} + +class ObjCMethodParam { + Type type; + final String name; + ObjCMethodParam(this.type, this.name); + + @override + String toString() => '$type $name'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/objc_nullable.dart b/pkgs/ffigenpad/lib/src/code_generator/objc_nullable.dart new file mode 100644 index 0000000000..42b7fe3e60 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/objc_nullable.dart @@ -0,0 +1,91 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'writer.dart'; + +/// An ObjC type annotated with nullable. Eg: +/// +(nullable NSObject*) methodWithNullableResult; +class ObjCNullable extends Type { + Type child; + + ObjCNullable(this.child) : assert(isSupported(child)); + + static bool isSupported(Type type) => + type is ObjCInterface || + type is ObjCBlock || + type is ObjCObjectPointer || + type is ObjCInstanceType; + + @override + void addDependencies(Set dependencies) { + child.addDependencies(dependencies); + } + + @override + Type get baseType => child.baseType; + + @override + String getCType(Writer w) => child.getCType(w); + + @override + String getFfiDartType(Writer w) => child.getFfiDartType(w); + + @override + String getDartType(Writer w) => '${child.getDartType(w)}?'; + + @override + String getNativeType({String varName = ''}) => + child.getNativeType(varName: varName); + + @override + bool get sameFfiDartAndCType => child.sameFfiDartAndCType; + + @override + bool get sameDartAndCType => false; + + @override + bool get sameDartAndFfiDartType => false; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) { + // This is a bit of a hack, but works for all the types that are allowed to + // be a child type. If we add more allowed child types, we may have to start + // special casing each type. Turns value._id into value?._id ?? nullptr. + final convertedValue = child.convertDartTypeToFfiDartType(w, '$value?', + objCRetain: objCRetain); + return '$convertedValue ?? ${w.ffiLibraryPrefix}.nullptr'; + } + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) { + // All currently supported child types have a Pointer as their FfiDartType. + final convertedValue = child.convertFfiDartTypeToDartType( + w, + value, + objCRetain: objCRetain, + objCEnclosingClass: objCEnclosingClass, + ); + return '$value.address == 0 ? null : $convertedValue'; + } + + @override + String? generateRetain(String value) => child.generateRetain(value); + + @override + String toString() => '$child?'; + + @override + String cacheKey() => '${child.cacheKey()}?'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/objc_protocol.dart b/pkgs/ffigenpad/lib/src/code_generator/objc_protocol.dart new file mode 100644 index 0000000000..d1caa135e6 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/objc_protocol.dart @@ -0,0 +1,198 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'binding_string.dart'; +import 'utils.dart'; +import 'writer.dart'; + +class ObjCProtocol extends NoLookUpBinding with ObjCMethods { + final superProtocols = []; + final String lookupName; + late final ObjCInternalGlobal _protocolPointer; + + @override + final ObjCBuiltInFunctions builtInFunctions; + + ObjCProtocol({ + super.usr, + required String super.originalName, + String? name, + String? lookupName, + super.dartDoc, + required this.builtInFunctions, + }) : lookupName = lookupName ?? originalName, + super(name: name ?? originalName); + + @override + BindingString toBindingString(Writer w) { + final protocolMethod = ObjCBuiltInFunctions.protocolMethod.gen(w); + final protocolListenableMethod = + ObjCBuiltInFunctions.protocolListenableMethod.gen(w); + final protocolBuilder = ObjCBuiltInFunctions.protocolBuilder.gen(w); + final objectBase = ObjCBuiltInFunctions.objectBase.gen(w); + final getSignature = ObjCBuiltInFunctions.getProtocolMethodSignature.gen(w); + + final buildArgs = []; + final buildImplementations = StringBuffer(); + final buildListenerImplementations = StringBuffer(); + final methodFields = StringBuffer(); + + final methodNamer = createMethodRenamer(w); + + var anyListeners = false; + for (final method in methods) { + final methodName = method.getDartMethodName(methodNamer); + final fieldName = methodName; + final argName = methodName; + final block = method.protocolBlock; + final blockType = block.getDartType(w); + final methodClass = + block.hasListener ? protocolListenableMethod : protocolMethod; + + // The function type omits the first arg of the block, which is unused. + final func = FunctionType(returnType: block.returnType, parameters: [ + for (int i = 1; i < block.argTypes.length; ++i) + Parameter(name: 'arg$i', type: block.argTypes[i]), + ]); + final funcType = func.getDartType(w, writeArgumentNames: false); + + if (method.isOptional) { + buildArgs.add('$funcType? $argName'); + } else { + buildArgs.add('required $funcType $argName'); + } + + final blockFirstArg = block.argTypes[0].getDartType(w); + final argsReceived = func.parameters + .map((p) => '${p.type.getDartType(w)} ${p.name}') + .join(', '); + final argsPassed = func.parameters.map((p) => p.name).join(', '); + final wrapper = '($blockFirstArg _, $argsReceived) => func($argsPassed)'; + + var listenerBuilder = ''; + var maybeImplementAsListener = 'implement'; + if (block.hasListener) { + listenerBuilder = '($funcType func) => $blockType.listener($wrapper),'; + maybeImplementAsListener = 'implementAsListener'; + anyListeners = true; + } + + buildImplementations.write(''' + $name.$fieldName.implement(builder, $argName);'''); + buildListenerImplementations.write(''' + $name.$fieldName.$maybeImplementAsListener(builder, $argName);'''); + + methodFields.write(makeDartDoc(method.dartDoc ?? method.originalName)); + methodFields.write('''static final $fieldName = $methodClass<$funcType>( + ${method.selObject!.name}, + $getSignature( + ${_protocolPointer.name}, + ${method.selObject!.name}, + isRequired: ${method.isRequired}, + isInstanceMethod: ${method.isInstanceMethod}, + ), + ($funcType func) => $blockType.fromFunction($wrapper), + $listenerBuilder + ); +'''); + } + + final args = buildArgs.isEmpty ? '' : '{${buildArgs.join(', ')}}'; + final builders = ''' + /// Builds an object that implements the $originalName protocol. To implement + /// multiple protocols, use [addToBuilder] or [$protocolBuilder] directly. + static $objectBase implement($args) { + final builder = $protocolBuilder(); + $buildImplementations + return builder.build(); + } + + /// Adds the implementation of the $originalName protocol to an existing + /// [$protocolBuilder]. + static void addToBuilder($protocolBuilder builder, $args) { + $buildImplementations + } +'''; + + var listenerBuilders = ''; + if (anyListeners) { + listenerBuilders = ''' + /// Builds an object that implements the $originalName protocol. To implement + /// multiple protocols, use [addToBuilder] or [$protocolBuilder] directly. All + /// methods that can be implemented as listeners will be. + static $objectBase implementAsListener($args) { + final builder = $protocolBuilder(); + $buildListenerImplementations + return builder.build(); + } + + /// Adds the implementation of the $originalName protocol to an existing + /// [$protocolBuilder]. All methods that can be implemented as listeners will + /// be. + static void addToBuilderAsListener($protocolBuilder builder, $args) { + $buildListenerImplementations + } +'''; + } + + final mainString = ''' +${makeDartDoc(dartDoc ?? originalName)}abstract final class $name { + $builders + $listenerBuilders + $methodFields +} +'''; + + return BindingString( + type: BindingStringType.objcProtocol, string: mainString); + } + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + dependencies.add(this); + + _protocolPointer = ObjCInternalGlobal( + '_protocol_$originalName', + (Writer w) => + '${ObjCBuiltInFunctions.getProtocol.gen(w)}("$lookupName")') + ..addDependencies(dependencies); + + for (final superProtocol in superProtocols) { + superProtocol.addDependencies(dependencies); + } + + addMethodDependencies(dependencies, needProtocolBlock: true); + + for (final superProtocol in superProtocols) { + _copyMethodsFromSuperType(superProtocol); + } + + // Add dependencies for any methods that were added. + addMethodDependencies(dependencies, needProtocolBlock: true); + } + + void _copyMethodsFromSuperType(ObjCProtocol superProtocol) { + if (builtInFunctions.isNSObject(superProtocol.originalName)) { + // When writing a protocol that doesn't inherit from any other protocols, + // it's typical to have it inherit from NSObject instead. But NSObject has + // heaps of methods that users are very unlikely to want to implement, so + // ignore it. If the user really wants to implement them they can use the + // ObjCProtocolBuilder. + return; + } + + // Protocols have very different inheritance semantics than Dart classes. + // So copy across all the methods explicitly, rather than trying to use Dart + // inheritance to get them implicitly. + for (final method in superProtocol.methods) { + addMethod(method); + } + } + + @override + String toString() => originalName; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/pointer.dart b/pkgs/ffigenpad/lib/src/code_generator/pointer.dart new file mode 100644 index 0000000000..177bcab41e --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/pointer.dart @@ -0,0 +1,139 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'writer.dart'; + +/// Represents a pointer. +class PointerType extends Type { + final Type child; + + PointerType._(this.child); + + factory PointerType(Type child) { + if (child == objCObjectType) { + return ObjCObjectPointer(); + } + return PointerType._(child); + } + + @override + void addDependencies(Set dependencies) { + child.addDependencies(dependencies); + } + + @override + Type get baseType => child.baseType; + + @override + String getCType(Writer w) => + '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>'; + + @override + String getNativeType({String varName = ''}) => + '${child.getNativeType()}* $varName'; + + // Both the C type and the FFI Dart type are 'Pointer<$cType>'. + @override + bool get sameFfiDartAndCType => true; + + @override + String toString() => '$child*'; + + @override + String cacheKey() => '${child.cacheKey()}*'; +} + +/// Represents a constant array, which has a fixed size. +class ConstantArray extends PointerType { + final int length; + final bool useArrayType; + + ConstantArray(this.length, Type child, {required this.useArrayType}) + : super._(child); + + @override + Type get baseArrayType => child.baseArrayType; + + @override + bool get isIncompleteCompound => baseArrayType.isIncompleteCompound; + + @override + String getNativeType({String varName = ''}) => + '${child.getNativeType()} $varName[$length]'; + + @override + String toString() => '$child[$length]'; + + @override + String cacheKey() => '${child.cacheKey()}[$length]'; + + @override + String getCType(Writer w) { + if (useArrayType) { + return '${w.ffiLibraryPrefix}.Array<${child.getCType(w)}>'; + } + + return super.getCType(w); + } +} + +/// Represents an incomplete array, which has an unknown size. +class IncompleteArray extends PointerType { + IncompleteArray(super.child) : super._(); + + @override + Type get baseArrayType => child.baseArrayType; + + @override + String getNativeType({String varName = ''}) => + '${child.getNativeType()} $varName[]'; + + @override + String toString() => '$child[]'; + + @override + String cacheKey() => '${child.cacheKey()}[]'; +} + +/// A pointer to an Objective C object. +class ObjCObjectPointer extends PointerType { + factory ObjCObjectPointer() => _inst; + + static final _inst = ObjCObjectPointer._(); + ObjCObjectPointer._() : super._(objCObjectType); + + @override + String getDartType(Writer w) => '${w.objcPkgPrefix}.ObjCObjectBase'; + + @override + String getNativeType({String varName = ''}) => 'id $varName'; + + @override + bool get sameDartAndCType => false; + + @override + bool get sameDartAndFfiDartType => false; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + ObjCInterface.generateGetId(value, objCRetain); + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + '${getDartType(w)}($value, retain: $objCRetain, release: true)'; + + @override + String? generateRetain(String value) => '[$value retain]'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/struct.dart b/pkgs/ffigenpad/lib/src/code_generator/struct.dart new file mode 100644 index 0000000000..945261a676 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/struct.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'compound.dart'; + +/// A binding for C Struct. +/// +/// For a C structure - +/// ```c +/// struct C { +/// int a; +/// double b; +/// int c; +/// }; +/// ``` +/// The generated dart code is - +/// ```dart +/// final class Struct extends ffi.Struct { +/// @ffi.Int32() +/// int a; +/// +/// @ffi.Double() +/// double b; +/// +/// @ffi.Uint8() +/// int c; +/// +/// } +/// ``` +class Struct extends Compound { + Struct({ + super.usr, + super.originalName, + required super.name, + super.isIncomplete, + super.pack, + super.dartDoc, + super.members, + super.isInternal, + super.objCBuiltInFunctions, + super.nativeType, + }) : super(compoundType: CompoundType.struct); +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/type.dart b/pkgs/ffigenpad/lib/src/code_generator/type.dart new file mode 100644 index 0000000000..be4a97fb37 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/type.dart @@ -0,0 +1,204 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import 'writer.dart'; + +/// Type class for return types, variable types, etc. +/// +/// Implementers should extend either Type, or BindingType if the type is also a +/// binding, and override at least getCType and toString. +abstract class Type { + const Type(); + + /// Get all dependencies of this type and save them in [dependencies]. + void addDependencies(Set dependencies) {} + + /// Get base type for any type. + /// + /// E.g int** has base [Type] of int. + /// double[2][3] has base [Type] of double. + Type get baseType => this; + + /// Get base Array type. + /// + /// Returns itself if it's not an Array Type. + Type get baseArrayType => this; + + /// Get base typealias type. + /// + /// Returns itself if it's not a Typealias. + Type get typealiasType => this; + + /// Returns true if the type is a [Compound] and is incomplete. + bool get isIncompleteCompound => false; + + /// Returns the C type of the Type. This is the FFI compatible type that is + /// passed to native code. + String getCType(Writer w) => + throw UnsupportedError('No mapping for type: $this'); + + /// Returns the Dart type of the Type. This is the type that is passed from + /// FFI to Dart code. + String getFfiDartType(Writer w) => getCType(w); + + /// Returns the user type of the Type. This is the type that is presented to + /// users by the ffigened API to users. For C bindings this is always the same + /// as getFfiDartType. For ObjC bindings this refers to the wrapper object. + String getDartType(Writer w) => getFfiDartType(w); + + /// Returns the C/ObjC type of the Type. This is the type as it appears in + /// C/ObjC source code. It should not be used in Dart source code. + /// + /// This method takes a [varName] arg because some C/ObjC types embed the + /// variable name inside the type. Eg, to pass an ObjC block as a function + /// argument, the syntax is `int (^arg)(int)`, where arg is the [varName]. + String getNativeType({String varName = ''}) => + throw UnsupportedError('No native mapping for type: $this'); + + /// Returns whether the FFI dart type and C type string are same. + bool get sameFfiDartAndCType; + + /// Returns whether the dart type and C type string are same. + bool get sameDartAndCType => sameFfiDartAndCType; + + /// Returns whether the dart type and FFI dart type string are same. + bool get sameDartAndFfiDartType => true; + + /// Returns generated Dart code that converts the given value from its + /// DartType to its FfiDartType. + /// + /// [value] is the value to be converted. If [objCRetain] is true, the ObjC + /// object will be reained (ref count incremented) during conversion. + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + value; + + /// Returns generated Dart code that converts the given value from its + /// FfiDartType to its DartType. + /// + /// [value] is the value to be converted. If [objCRetain] is true, the ObjC + /// wrapper object will retain (ref count increment) the wrapped object + /// pointer. If this conversion is occuring in the context of an ObjC class, + /// then [objCEnclosingClass] should be the name of the Dart wrapper class + /// (this is used by instancetype). + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + value; + + /// Returns generated ObjC code that retains a reference to the given value. + /// Returns null if the Type does not need to be retained. + String? generateRetain(String value) => null; + + /// Returns a human readable string representation of the Type. This is mostly + /// just for debugging, but it may also be used for non-functional code (eg to + /// name a variable or type in generated code). + @override + String toString(); + + /// Cache key used in various places to dedupe Types. By default this is just + /// the hash of the Type, but in many cases this does not dedupe sufficiently. + /// So Types that may be duplicated should override this to return a more + /// specific key. Types that are already deduped don't need to override this. + /// toString() is not a valid cache key as there may be name collisions. + String cacheKey() => hashCode.toRadixString(36); + + /// Returns a string of code that creates a default value for this type. For + /// example, for int types this returns the string '0'. A null return means + /// that default values aren't supported for this type, eg void. + String? getDefaultValue(Writer w) => null; +} + +/// Base class for all Type bindings. +/// +/// Since Dart doesn't have multiple inheritance, this type exists so that we +/// don't have to reimplement the default methods in all the classes that want +/// to extend both NoLookUpBinding and Type. +abstract class BindingType extends NoLookUpBinding implements Type { + BindingType({ + super.usr, + super.originalName, + required super.name, + super.dartDoc, + super.isInternal, + }); + + @override + Type get baseType => this; + + @override + Type get baseArrayType => this; + + @override + Type get typealiasType => this; + + @override + bool get isIncompleteCompound => false; + + @override + String getFfiDartType(Writer w) => getCType(w); + + @override + String getDartType(Writer w) => getFfiDartType(w); + + @override + String getNativeType({String varName = ''}) => + throw UnsupportedError('No native mapping for type: $this'); + + @override + bool get sameDartAndCType => sameFfiDartAndCType; + + @override + bool get sameDartAndFfiDartType => true; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + value; + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + value; + + @override + String? generateRetain(String value) => null; + + @override + String toString() => originalName; + + @override + String cacheKey() => hashCode.toRadixString(36); + + @override + String? getDefaultValue(Writer w) => null; +} + +/// Represents an unimplemented type. Used as a marker, so that declarations +/// having these can exclude them. +class UnimplementedType extends Type { + String reason; + UnimplementedType(this.reason); + + @override + String toString() => '(Unimplemented: $reason)'; + + @override + bool get sameFfiDartAndCType => true; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/typealias.dart b/pkgs/ffigenpad/lib/src/code_generator/typealias.dart new file mode 100644 index 0000000000..2be2a2ec94 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/typealias.dart @@ -0,0 +1,256 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; + +import '../strings.dart' as strings; +import 'binding_string.dart'; +import 'utils.dart'; +import 'writer.dart'; + +/// A simple Typealias, Expands to - +/// +/// ```dart +/// typedef $name = $type; +/// ); +/// ``` +class Typealias extends BindingType { + final Type type; + String? _ffiDartAliasName; + String? _dartAliasName; + + /// Creates a Typealias. + /// + /// If [genFfiDartType] is true, a binding is generated for the Ffi Dart type + /// in addition to the C type. See [Type.getFfiDartType]. + factory Typealias({ + String? usr, + String? originalName, + String? dartDoc, + required String name, + required Type type, + bool genFfiDartType = false, + bool isInternal = false, + }) { + final funcType = _getFunctionTypeFromPointer(type); + if (funcType != null) { + type = PointerType(NativeFunc(Typealias._( + name: '${name}Function', + type: funcType, + genFfiDartType: genFfiDartType, + isInternal: isInternal, + ))); + } + if ((originalName ?? name) == strings.objcInstanceType && + type is ObjCObjectPointer) { + return ObjCInstanceType._( + usr: usr, + originalName: originalName, + dartDoc: dartDoc, + name: name, + type: type, + genFfiDartType: genFfiDartType, + isInternal: isInternal, + ); + } + return Typealias._( + usr: usr, + originalName: originalName, + dartDoc: dartDoc, + name: name, + type: type, + genFfiDartType: genFfiDartType, + isInternal: isInternal, + ); + } + + Typealias._({ + super.usr, + super.originalName, + super.dartDoc, + required String name, + required this.type, + bool genFfiDartType = false, + super.isInternal, + }) : _ffiDartAliasName = genFfiDartType ? 'Dart$name' : null, + _dartAliasName = + (!genFfiDartType && type is! Typealias && !type.sameDartAndCType) + ? 'Dart$name' + : null, + super( + name: genFfiDartType ? 'Native$name' : name, + ); + + @override + void addDependencies(Set dependencies) { + if (dependencies.contains(this)) return; + + dependencies.add(this); + type.addDependencies(dependencies); + } + + static FunctionType? _getFunctionTypeFromPointer(Type type) { + if (type is! PointerType) return null; + final pointee = type.child; + if (pointee is! NativeFunc) return null; + return pointee.type; + } + + @override + BindingString toBindingString(Writer w) { + if (_ffiDartAliasName != null) { + _ffiDartAliasName = w.topLevelUniqueNamer.makeUnique(_ffiDartAliasName!); + } + if (_dartAliasName != null) { + _dartAliasName = w.topLevelUniqueNamer.makeUnique(_dartAliasName!); + } + + final sb = StringBuffer(); + if (dartDoc != null) { + sb.write(makeDartDoc(dartDoc!)); + } + sb.write('typedef $name = ${type.getCType(w)};\n'); + if (_ffiDartAliasName != null) { + sb.write('typedef $_ffiDartAliasName = ${type.getFfiDartType(w)};\n'); + } + if (_dartAliasName != null) { + sb.write('typedef $_dartAliasName = ${type.getDartType(w)};\n'); + } + return BindingString( + type: BindingStringType.typeDef, string: sb.toString()); + } + + @override + Type get typealiasType => type.typealiasType; + + @override + bool get isIncompleteCompound => type.isIncompleteCompound; + + @override + String getCType(Writer w) => name; + + @override + String getNativeType({String varName = ''}) => + type.getNativeType(varName: varName); + + @override + String getFfiDartType(Writer w) { + if (_ffiDartAliasName != null) { + return _ffiDartAliasName!; + } else if (type.sameFfiDartAndCType) { + return name; + } else { + return type.getFfiDartType(w); + } + } + + @override + String getDartType(Writer w) { + if (_dartAliasName != null) { + return _dartAliasName!; + } else if (type.sameDartAndCType) { + return getFfiDartType(w); + } else { + return type.getDartType(w); + } + } + + @override + bool get sameFfiDartAndCType => type.sameFfiDartAndCType; + + @override + bool get sameDartAndCType => type.sameDartAndCType; + + @override + bool get sameDartAndFfiDartType => type.sameDartAndFfiDartType; + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + type.convertDartTypeToFfiDartType(w, value, objCRetain: objCRetain); + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + type.convertFfiDartTypeToDartType( + w, + value, + objCRetain: objCRetain, + objCEnclosingClass: objCEnclosingClass, + ); + + @override + String? generateRetain(String value) => type.generateRetain(value); + + @override + String cacheKey() => type.cacheKey(); + + @override + String? getDefaultValue(Writer w) => type.getDefaultValue(w); + + // Used to compare whether two Typealias are same symbols and ensure that they + // are unique when adding to a [Set]. + @override + bool operator ==(Object other) { + if (other is! Typealias) return false; + if (identical(this, other)) return true; + return other.usr == usr; + } + + // [usr] is unique for specific symbols. + @override + int get hashCode => usr.hashCode; +} + +/// Objective C's instancetype. +/// +/// This is an alias for an ObjC object pointer that is special cased in code +/// generation. It's only valid as the return type of a method, and always +/// appears as the enclosing class's type, even in inherited methods. +class ObjCInstanceType extends Typealias { + ObjCInstanceType._({ + super.usr, + super.originalName, + super.dartDoc, + required super.name, + required super.type, + super.genFfiDartType, + super.isInternal, + }) : super._(); + + @override + String convertDartTypeToFfiDartType( + Writer w, + String value, { + required bool objCRetain, + }) => + ObjCInterface.generateGetId(value, objCRetain); + + @override + String convertFfiDartTypeToDartType( + Writer w, + String value, { + required bool objCRetain, + String? objCEnclosingClass, + }) => + objCEnclosingClass == null + ? super.convertFfiDartTypeToDartType( + w, + value, + objCRetain: objCRetain, + objCEnclosingClass: objCEnclosingClass, + ) + : ObjCInterface.generateConstructor( + objCEnclosingClass, value, objCRetain); + + @override + String getNativeType({String varName = ''}) => 'id $varName'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/union.dart b/pkgs/ffigenpad/lib/src/code_generator/union.dart new file mode 100644 index 0000000000..3675023d74 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/union.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'compound.dart'; + +/// A binding for a C union - +/// +/// ```c +/// union C { +/// int a; +/// double b; +/// float c; +/// }; +/// ``` +/// The generated dart code is - +/// ```dart +/// final class Union extends ffi.Union{ +/// @ffi.Int32() +/// int a; +/// +/// @ffi.Double() +/// double b; +/// +/// @ffi.Float() +/// float c; +/// +/// } +/// ``` +class Union extends Compound { + Union({ + super.usr, + super.originalName, + required super.name, + super.isIncomplete, + super.pack, + super.dartDoc, + super.members, + super.objCBuiltInFunctions, + super.nativeType, + }) : super(compoundType: CompoundType.union); +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/utils.dart b/pkgs/ffigenpad/lib/src/code_generator/utils.dart new file mode 100644 index 0000000000..020a0cdb20 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/utils.dart @@ -0,0 +1,98 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart_keywords.dart'; +import 'pointer.dart'; +import 'type.dart'; +import 'writer.dart'; + +export 'package:ffigen/src/code_generator/utils.dart' + show makeDartDoc, makeDoc, parseObjCFrameworkHeader; + +class UniqueNamer { + final Set _usedUpNames; + + /// Creates a UniqueNamer with given [usedUpNames] and Dart reserved keywords. + /// + /// If [parent] is provided, also includes all the parent's names. + UniqueNamer(Set usedUpNames, {UniqueNamer? parent}) + : _usedUpNames = { + ...keywords, + ...usedUpNames, + ...parent?._usedUpNames ?? {}, + }; + + /// Creates a UniqueNamer with given [_usedUpNames] only. + UniqueNamer._raw(this._usedUpNames); + + /// Returns a unique name by appending `` to it if necessary. + /// + /// Adds the resulting name to the used names by default. + String makeUnique(String name, [bool addToUsedUpNames = true]) { + // For example, nested structures/unions may not have a name + if (name.isEmpty) { + name = 'unnamed'; + } + + var crName = name; + var i = 1; + while (_usedUpNames.contains(crName)) { + crName = '$name$i'; + i++; + } + if (addToUsedUpNames) { + _usedUpNames.add(crName); + } + return crName; + } + + /// Adds a name to used names. + /// + /// Note: [makeUnique] also adds the name by default. + void markUsed(String name) { + _usedUpNames.add(name); + } + + /// Returns true if a name has been used before. + bool isUsed(String name) { + return _usedUpNames.contains(name); + } + + /// Returns true if a name has not been used before. + bool isUnique(String name) { + return !_usedUpNames.contains(name); + } + + UniqueNamer clone() => UniqueNamer._raw({..._usedUpNames}); +} + +String makeNativeAnnotation( + Writer w, { + required String? nativeType, + required String dartName, + required String nativeSymbolName, + bool isLeaf = false, +}) { + final args = <(String, String)>[]; + if (dartName != nativeSymbolName) { + args.add(('symbol', '"$nativeSymbolName"')); + } + if (isLeaf) { + args.add(('isLeaf', 'true')); + } + + final combinedArgs = args.map((e) => '${e.$1}: ${e.$2}').join(', '); + return '@${w.ffiLibraryPrefix}.Native<$nativeType>($combinedArgs)'; +} + +String makeArrayAnnotation(Writer w, ConstantArray arrayType) { + final dimensions = []; + Type type = arrayType; + while (type is ConstantArray) { + dimensions.add(type.length); + type = type.child; + } + + return '@${w.ffiLibraryPrefix}.Array.multi([${dimensions.join(', ')}])'; +} diff --git a/pkgs/ffigenpad/lib/src/code_generator/writer.dart b/pkgs/ffigenpad/lib/src/code_generator/writer.dart new file mode 100644 index 0000000000..ff8e8e6d8f --- /dev/null +++ b/pkgs/ffigenpad/lib/src/code_generator/writer.dart @@ -0,0 +1,516 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as p; + +import '../code_generator.dart'; +import '../strings.dart' as strings; +import 'utils.dart'; + +final _logger = Logger('ffigen.code_generator.writer'); + +/// To store generated String bindings. +class Writer { + final String? header; + + /// Holds bindings, which lookup symbols. + final List lookUpBindings; + + /// Holds bindings, which lookup symbols through `FfiNative`. + final List ffiNativeBindings; + + /// Holds bindings which don't lookup symbols. + final List noLookUpBindings; + + /// The default asset id to use for [ffiNativeBindings]. + final String? nativeAssetId; + + /// Manages the `_SymbolAddress` class. + final symbolAddressWriter = SymbolAddressWriter(); + + late String _className; + String get className => _className; + + final String? classDocComment; + + final bool generateForPackageObjectiveC; + + final List nativeEntryPoints; + + /// Tracks where enumType.getCType is called. Reset everytime [generate] is + /// called. + bool usedEnumCType = false; + + String? _ffiLibraryPrefix; + String get ffiLibraryPrefix { + if (_ffiLibraryPrefix != null) { + return _ffiLibraryPrefix!; + } + + final import = _usedImports.firstWhere( + (element) => element.name == ffiImport.name, + orElse: () => ffiImport); + _usedImports.add(import); + return _ffiLibraryPrefix = import.prefix; + } + + String? _ffiPkgLibraryPrefix; + String get ffiPkgLibraryPrefix { + if (_ffiPkgLibraryPrefix != null) { + return _ffiPkgLibraryPrefix!; + } + + final import = _usedImports.firstWhere( + (element) => element.name == ffiPkgImport.name, + orElse: () => ffiPkgImport); + _usedImports.add(import); + return _ffiPkgLibraryPrefix = import.prefix; + } + + String? _objcPkgPrefix; + String get objcPkgPrefix { + if (_objcPkgPrefix != null) { + return _objcPkgPrefix!; + } + + final import = _usedImports.firstWhere( + (element) => element.name == objcPkgImport.name, + orElse: () => objcPkgImport); + _usedImports.add(import); + return _objcPkgPrefix = import.prefix; + } + + late String selfImportPrefix = () { + final import = _usedImports + .firstWhere((element) => element.name == self.name, orElse: () => self); + _usedImports.add(import); + return import.prefix; + }(); + + final Set _usedImports = {}; + + late String _lookupFuncIdentifier; + String get lookupFuncIdentifier => _lookupFuncIdentifier; + + late String _symbolAddressClassName; + late String _symbolAddressVariableName; + late String _symbolAddressLibraryVarName; + + /// Initial namers set after running constructor. Namers are reset to this + /// initial state everytime [generate] is called. + late UniqueNamer _initialTopLevelUniqueNamer, _initialWrapperLevelUniqueNamer; + + /// Used by [Binding]s for generating required code. + late UniqueNamer _topLevelUniqueNamer; + UniqueNamer get topLevelUniqueNamer => _topLevelUniqueNamer; + late UniqueNamer _wrapperLevelUniqueNamer; + UniqueNamer get wrapperLevelUniqueNamer => _wrapperLevelUniqueNamer; + late UniqueNamer _objCLevelUniqueNamer; + UniqueNamer get objCLevelUniqueNamer => _objCLevelUniqueNamer; + + late String _arrayHelperClassPrefix; + + /// Guaranteed to be a unique prefix. + String get arrayHelperClassPrefix => _arrayHelperClassPrefix; + + /// Set true after calling [generate]. Indicates if + /// [generateSymbolOutputYamlMap] can be called. + bool get canGenerateSymbolOutput => _canGenerateSymbolOutput; + bool _canGenerateSymbolOutput = false; + + final bool silenceEnumWarning; + + Writer({ + required this.lookUpBindings, + required this.ffiNativeBindings, + required this.noLookUpBindings, + required String className, + required this.nativeAssetId, + List? additionalImports, + this.classDocComment, + this.header, + required this.generateForPackageObjectiveC, + required this.silenceEnumWarning, + required this.nativeEntryPoints, + }) { + final globalLevelNameSet = noLookUpBindings.map((e) => e.name).toSet(); + final wrapperLevelNameSet = lookUpBindings.map((e) => e.name).toSet(); + final allNameSet = {} + ..addAll(globalLevelNameSet) + ..addAll(wrapperLevelNameSet); + + _initialTopLevelUniqueNamer = UniqueNamer(globalLevelNameSet); + _initialWrapperLevelUniqueNamer = UniqueNamer(wrapperLevelNameSet); + final allLevelsUniqueNamer = UniqueNamer(allNameSet); + + /// Wrapper class name must be unique among all names. + _className = _resolveNameConflict( + name: className, + makeUnique: allLevelsUniqueNamer, + markUsed: [_initialWrapperLevelUniqueNamer, _initialTopLevelUniqueNamer], + ); + + /// Library imports prefix should be unique unique among all names. + if (additionalImports != null) { + for (final lib in additionalImports) { + lib.prefix = _resolveNameConflict( + name: lib.prefix, + makeUnique: allLevelsUniqueNamer, + markUsed: [ + _initialWrapperLevelUniqueNamer, + _initialTopLevelUniqueNamer + ], + ); + } + } + + /// [_lookupFuncIdentifier] should be unique in top level. + _lookupFuncIdentifier = _resolveNameConflict( + name: '_lookup', + makeUnique: _initialTopLevelUniqueNamer, + markUsed: [_initialTopLevelUniqueNamer], + ); + + /// Resolve name conflicts of identifiers used for SymbolAddresses. + _symbolAddressClassName = _resolveNameConflict( + name: '_SymbolAddresses', + makeUnique: allLevelsUniqueNamer, + markUsed: [_initialWrapperLevelUniqueNamer, _initialTopLevelUniqueNamer], + ); + _symbolAddressVariableName = _resolveNameConflict( + name: 'addresses', + makeUnique: _initialWrapperLevelUniqueNamer, + markUsed: [_initialWrapperLevelUniqueNamer], + ); + _symbolAddressLibraryVarName = _resolveNameConflict( + name: '_library', + makeUnique: _initialWrapperLevelUniqueNamer, + markUsed: [_initialWrapperLevelUniqueNamer], + ); + + /// Finding a unique prefix for Array Helper Classes and store into + /// [_arrayHelperClassPrefix]. + final base = 'ArrayHelper'; + _arrayHelperClassPrefix = base; + var suffixInt = 0; + for (var i = 0; i < allNameSet.length; i++) { + if (allNameSet.elementAt(i).startsWith(_arrayHelperClassPrefix)) { + // Not a unique prefix, start over with a new suffix. + i = -1; + suffixInt++; + _arrayHelperClassPrefix = '$base$suffixInt'; + } + } + + _resetUniqueNamersNamers(); + } + + /// Resolved name conflict using [makeUnique] and marks the result as used in + /// all [markUsed]. + String _resolveNameConflict({ + required String name, + required UniqueNamer makeUnique, + List markUsed = const [], + }) { + final s = makeUnique.makeUnique(name); + for (final un in markUsed) { + un.markUsed(s); + } + return s; + } + + /// Resets the namers to initial state. Namers are reset before generating. + void _resetUniqueNamersNamers() { + _topLevelUniqueNamer = _initialTopLevelUniqueNamer.clone(); + _wrapperLevelUniqueNamer = _initialWrapperLevelUniqueNamer.clone(); + _objCLevelUniqueNamer = UniqueNamer({}); + } + + void markImportUsed(LibraryImport import) { + _usedImports.add(import); + } + + /// Writes all bindings to a String. + String generate() { + final s = StringBuffer(); + + // We write the source first to determine which imports are actually + // referenced. Headers and [s] are then combined into the final result. + final result = StringBuffer(); + + // Reset unique namers to initial state. + _resetUniqueNamersNamers(); + + // Reset [usedEnumCType]. + usedEnumCType = false; + + // Write file header (if any). + if (header != null) { + result.writeln(header); + } + + // Write auto generated declaration. + result.write(makeDoc( + 'AUTO GENERATED FILE, DO NOT EDIT.\n\nGenerated by `package:ffigen`.')); + + // Write lint ignore if not specified by user already. + if (!RegExp(r'ignore_for_file:\s*type\s*=\s*lint').hasMatch(header ?? '')) { + result.write(makeDoc('ignore_for_file: type=lint')); + } + + // If there are any @Native bindings, the file needs to have an + // `@DefaultAsset` annotation for the symbols to resolve properly. This + // avoids duplicating the asset on every element. + // Since the annotation goes on a `library;` directive, it needs to appear + // before other definitions in the file. + if (ffiNativeBindings.isNotEmpty && nativeAssetId != null) { + result + ..writeln("@$ffiLibraryPrefix.DefaultAsset('$nativeAssetId')") + ..writeln('library;\n'); + } + + /// Write [lookUpBindings]. + if (lookUpBindings.isNotEmpty) { + // Write doc comment for wrapper class. + if (classDocComment != null) { + s.write(makeDartDoc(classDocComment!)); + } + // Write wrapper classs. + s.write('class $_className{\n'); + // Write dylib. + s.write('/// Holds the symbol lookup function.\n'); + s.write('final $ffiLibraryPrefix.Pointer Function(String symbolName) ' + '$lookupFuncIdentifier;\n'); + s.write('\n'); + //Write doc comment for wrapper class constructor. + s.write(makeDartDoc('The symbols are looked up in [dynamicLibrary].')); + // Write wrapper class constructor. + s.write('$_className($ffiLibraryPrefix.DynamicLibrary dynamicLibrary): ' + '$lookupFuncIdentifier = dynamicLibrary.lookup;\n\n'); + //Write doc comment for wrapper class named constructor. + s.write(makeDartDoc('The symbols are looked up with [lookup].')); + // Write wrapper class named constructor. + s.write('$_className.fromLookup($ffiLibraryPrefix.Pointer ' + 'Function(' + 'String symbolName) lookup): $lookupFuncIdentifier = lookup;\n\n'); + for (final b in lookUpBindings) { + s.write(b.toBindingString(this).string); + } + if (symbolAddressWriter.shouldGenerate) { + s.write(symbolAddressWriter.writeObject(this)); + } + + s.write('}\n\n'); + } + + if (ffiNativeBindings.isNotEmpty) { + for (final b in ffiNativeBindings) { + s.write(b.toBindingString(this).string); + } + + if (symbolAddressWriter.shouldGenerate) { + s.write(symbolAddressWriter.writeObject(this)); + } + } + + if (symbolAddressWriter.shouldGenerate) { + s.write(symbolAddressWriter.writeClass(this)); + } + + /// Write [noLookUpBindings]. + for (final b in noLookUpBindings) { + s.write(b.toBindingString(this).string); + } + + // Write neccesary imports. + for (final lib in _usedImports) { + final path = lib.importPath(generateForPackageObjectiveC); + result.write("import '$path' as ${lib.prefix};\n"); + } + result.write(s); + + // Warn about Enum usage in API surface. + if (!silenceEnumWarning && usedEnumCType) { + _logger.severe('The integer type used for enums is ' + 'implementation-defined. FFIgen tries to mimic the integer sizes ' + 'chosen by the most common compilers for the various OS and ' + 'architecture combinations. To prevent any crashes, remove the ' + 'enums from your API surface. To rely on the (unsafe!) mimicking, ' + 'you can silence this warning by adding silence-enum-warning: true ' + 'to the FFIgen config.'); + } + + _canGenerateSymbolOutput = true; + return result.toString(); + } + + List get _allBindings => [ + ...noLookUpBindings, + ...ffiNativeBindings, + ...lookUpBindings, + ]; + + Map generateSymbolOutputYamlMap(String importFilePath) { + final bindings = _allBindings; + if (!canGenerateSymbolOutput) { + throw Exception('Invalid state: generateSymbolOutputYamlMap() ' + 'called before generate()'); + } + + // Warn for macros. + final hasMacroBindings = bindings.any( + (element) => element is Constant && element.usr.contains('@macro@')); + if (hasMacroBindings) { + _logger.info('Removing all Macros from symbol file since they cannot ' + 'be cross referenced reliably.'); + } + + // Remove internal bindings and macros. + bindings.removeWhere((element) { + return element.isInternal || + (element is Constant && element.usr.contains('@macro@')); + }); + + // Sort bindings alphabetically by USR. + bindings.sort((a, b) => a.usr.compareTo(b.usr)); + + final usesFfiNative = bindings + .whereType() + .any((element) => element.ffiNativeConfig.enabled); + + return { + strings.formatVersion: strings.symbolFileFormatVersion, + strings.files: { + importFilePath: { + strings.usedConfig: { + strings.ffiNative: usesFfiNative, + }, + strings.symbols: { + for (final b in bindings) b.usr: {strings.name: b.name}, + }, + }, + }, + }; + } + + static String _objcImport(String entryPoint, String outDir) { + final frameworkHeader = parseObjCFrameworkHeader(entryPoint); + + if (frameworkHeader == null) { + // If it's not a framework header, use a relative import. + return '#import "${p.relative(entryPoint, from: outDir)}"\n'; + } + + // If it's a framework header, use a <> style import. + return '#import <$frameworkHeader>'; + } + + /// Writes the Objective C code needed for the bindings, if any. Returns null + /// if there are no bindings that need generated ObjC code. This function does + /// not generate the output file, but the [outFilename] does affect the + /// generated code. + String? generateObjC(String outFilename) { + final outDir = p.dirname(outFilename); + + final s = StringBuffer(); + s.write(''' +#include + +'''); + + for (final entryPoint in nativeEntryPoints) { + s.write(_objcImport(entryPoint, outDir)); + } + + var empty = true; + for (final binding in _allBindings) { + final bindingString = binding.toObjCBindingString(this); + if (bindingString != null) { + empty = false; + s.write(bindingString.string); + } + } + return empty ? null : s.toString(); + } +} + +/// Manages the generated `_SymbolAddress` class. +class SymbolAddressWriter { + final List<_SymbolAddressUnit> _addresses = []; + + /// Used to check if we need to generate `_SymbolAddress` class. + bool get shouldGenerate => _addresses.isNotEmpty; + + bool get hasNonNativeAddress => _addresses.any((e) => !e.native); + + void addSymbol({ + required String type, + required String name, + required String ptrName, + }) { + _addresses.add(_SymbolAddressUnit(type, name, ptrName, false)); + } + + void addNativeSymbol({required String type, required String name}) { + _addresses.add(_SymbolAddressUnit(type, name, '', true)); + } + + String writeObject(Writer w) { + final className = w._symbolAddressClassName; + final fieldName = w._symbolAddressVariableName; + + if (hasNonNativeAddress) { + return 'late final $fieldName = $className(this);'; + } else { + return 'const $fieldName = $className();'; + } + } + + String writeClass(Writer w) { + final sb = StringBuffer(); + sb.write('class ${w._symbolAddressClassName} {\n'); + + if (hasNonNativeAddress) { + // Write Library object. + sb.write('final ${w._className} ${w._symbolAddressLibraryVarName};\n'); + // Write Constructor. + sb.write('${w._symbolAddressClassName}(' + 'this.${w._symbolAddressLibraryVarName});\n'); + } else { + // Native bindings are top-level, so we don't need a field here. + sb.write('const ${w._symbolAddressClassName}();'); + } + + for (final address in _addresses) { + sb.write('${address.type} get ${address.name} => '); + + if (address.native) { + // For native fields and functions, we can use Native.addressOf to look + // up their address. + // The name of address getter shadows the actual element in the library, + // so we need to use a self-import. + final arg = '${w.selfImportPrefix}.${address.name}'; + sb.writeln('${w.ffiLibraryPrefix}.Native.addressOf($arg);'); + } else { + // For other elements, the generator will write a private field of type + // Pointer which we can reference here. + sb.writeln('${w._symbolAddressLibraryVarName}.${address.ptrName};'); + } + } + sb.write('}\n'); + return sb.toString(); + } +} + +/// Holds the data for a single symbol address. +class _SymbolAddressUnit { + final String type, name, ptrName; + + /// Whether the symbol we're looking up has been declared with `@Native`. + final bool native; + + _SymbolAddressUnit(this.type, this.name, this.ptrName, this.native); +} diff --git a/pkgs/ffigenpad/lib/src/config_provider.dart b/pkgs/ffigenpad/lib/src/config_provider.dart new file mode 100644 index 0000000000..1194762728 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Creates config object used by other sub_modules. +library; + +export 'config_provider/config.dart'; +export 'config_provider/yaml_config.dart'; diff --git a/pkgs/ffigenpad/lib/src/config_provider/config.dart b/pkgs/ffigenpad/lib/src/config_provider/config.dart new file mode 100644 index 0000000000..2daa0d7ef4 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider/config.dart @@ -0,0 +1,309 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; +import 'config_impl.dart'; +import 'config_types.dart'; +// import 'spec_utils.dart'; + +/// Provides configurations to other modules. +abstract interface class Config { + /// Input config filename, if any. + Uri? get filename; + + /// Output file name. + Uri get output; + + /// Output ObjC file name. + Uri get outputObjC; + + /// Symbol file config. + SymbolFile? get symbolFile; + + /// Language that ffigen is consuming. + Language get language; + + /// Path to headers. May not contain globs. + List get entryPoints; + + /// Whether to include a specific header. This exists in addition to + /// [entryPoints] to allow filtering of transitively included headers. + bool shouldIncludeHeader(Uri header); + + /// CommandLine Arguments to pass to clang_compiler. + List get compilerOpts; + + /// VarArg function handling. + Map> get varArgFunctions; + + /// Declaration filters for Functions. + DeclarationFilters get functionDecl; + + /// Declaration filters for Structs. + DeclarationFilters get structDecl; + + /// Declaration filters for Unions. + DeclarationFilters get unionDecl; + + /// Declaration filters for Enums. + DeclarationFilters get enumClassDecl; + + /// Declaration filters for Unnamed enum constants. + DeclarationFilters get unnamedEnumConstants; + + /// Declaration filters for Globals. + DeclarationFilters get globals; + + /// Declaration filters for Macro constants. + DeclarationFilters get macroDecl; + + /// Declaration filters for Typedefs. + DeclarationFilters get typedefs; + + /// Declaration filters for Objective C interfaces. + DeclarationFilters get objcInterfaces; + + /// Declaration filters for Objective C protocols. + DeclarationFilters get objcProtocols; + + /// If enabled, unused typedefs will also be generated. + bool get includeUnusedTypedefs; + + /// Undocumented option that changes code generation for package:objective_c. + /// The main difference is whether NSObject etc are imported from + /// package:objective_c (the default) or code genned like any other class. + /// This is necessary because package:objective_c can't import NSObject from + /// itself. + bool get generateForPackageObjectiveC; + + /// If generated bindings should be sorted alphabetically. + bool get sort; + + /// If typedef of supported types(int8_t) should be directly used. + bool get useSupportedTypedefs; + + /// Stores all the library imports specified by user including those for ffi + /// and pkg_ffi. + Map get libraryImports; + + /// Stores all the symbol file maps name to ImportedType mappings specified by + /// user. + Map get usrTypeMappings; + + /// Stores typedef name to ImportedType mappings specified by user. + Map get typedefTypeMappings; + + /// Stores struct name to ImportedType mappings specified by user. + Map get structTypeMappings; + + /// Stores union name to ImportedType mappings specified by user. + Map get unionTypeMappings; + + /// Stores native int name to ImportedType mappings specified by user. + Map get nativeTypeMappings; + + /// Extracted Doc comment type. + CommentType get commentType; + + /// Whether structs that are dependencies should be included. + CompoundDependencies get structDependencies; + + /// Whether unions that are dependencies should be included. + CompoundDependencies get unionDependencies; + + /// Whether, and how, to override struct packing for the given struct. + PackingValue? structPackingOverride(Declaration declaration); + + /// The module that the ObjC interface belongs to. + String? interfaceModule(Declaration declaration); + + /// The module that the ObjC protocol belongs to. + String? protocolModule(Declaration declaration); + + /// Name of the wrapper class. + String get wrapperName; + + /// Doc comment for the wrapper class. + String? get wrapperDocComment; + + /// Header of the generated bindings. + String? get preamble; + + /// If `Dart_Handle` should be mapped with Handle/Object. + bool get useDartHandle; + + /// Whether to silence warning for enum integer type mimicking. + bool get silenceEnumWarning; + + /// Whether to expose the function typedef for a given function. + bool shouldExposeFunctionTypedef(Declaration declaration); + + /// Whether the given function is a leaf function. + bool isLeafFunction(Declaration declaration); + + /// Whether to generate the given enum as a series of int constants, rather + /// than a real Dart enum. + bool enumShouldBeInt(Declaration declaration); + + /// Whether to generate the given unnamed enum as a series of int constants, + /// rather than a real Dart enum. + bool unnamedEnumsShouldBeInt(Declaration declaration); + + /// Config options for @Native annotations. + FfiNativeConfig get ffiNativeConfig; + + /// Where to ignore compiler warnings/errors in source header files. + bool get ignoreSourceErrors; + + /// Whether to format the output file. + bool get formatOutput; + + factory Config({ + Uri? filename, + Uri? libclangDylib, + required Uri output, + Uri? outputObjC, + SymbolFile? symbolFile, + Language language = Language.c, + required List entryPoints, + bool Function(Uri header)? shouldIncludeHeaderFunc, + List compilerOpts = const [], + Map> varArgFunctions = + const >{}, + DeclarationFilters? functionDecl, + DeclarationFilters? structDecl, + DeclarationFilters? unionDecl, + DeclarationFilters? enumClassDecl, + DeclarationFilters? unnamedEnumConstants, + DeclarationFilters? globals, + DeclarationFilters? macroDecl, + DeclarationFilters? typedefs, + DeclarationFilters? objcInterfaces, + DeclarationFilters? objcProtocols, + bool includeUnusedTypedefs = false, + bool generateForPackageObjectiveC = false, + bool sort = false, + bool useSupportedTypedefs = true, + List libraryImports = const [], + List usrTypeMappings = const [], + List typedefTypeMappings = const [], + List structTypeMappings = const [], + List unionTypeMappings = const [], + List nativeTypeMappings = const [], + CommentType? commentType, + CompoundDependencies structDependencies = CompoundDependencies.full, + CompoundDependencies unionDependencies = CompoundDependencies.full, + PackingValue? Function(Declaration declaration)? structPackingOverrideFunc, + String? Function(Declaration declaration)? interfaceModuleFunc, + String? Function(Declaration declaration)? protocolModuleFunc, + String wrapperName = 'NativeLibrary', + String? wrapperDocComment, + String? preamble, + bool useDartHandle = true, + bool silenceEnumWarning = false, + bool Function(Declaration declaration)? shouldExposeFunctionTypedefFunc, + bool Function(Declaration declaration)? isLeafFunctionFunc, + bool Function(Declaration declaration)? enumShouldBeIntFunc, + bool Function(Declaration declaration)? unnamedEnumsShouldBeIntFunc, + FfiNativeConfig ffiNativeConfig = const FfiNativeConfig(enabled: false), + bool ignoreSourceErrors = false, + bool formatOutput = true, + }) => + ConfigImpl( + filename: filename == null ? null : Uri.file(filename.toFilePath()), + output: Uri.file(output.toFilePath()), + outputObjC: + Uri.file(outputObjC?.toFilePath() ?? '${output.toFilePath()}.m'), + symbolFile: symbolFile, + language: language, + entryPoints: entryPoints, + shouldIncludeHeaderFunc: shouldIncludeHeaderFunc ?? (_) => true, + compilerOpts: compilerOpts, + varArgFunctions: varArgFunctions, + functionDecl: functionDecl ?? DeclarationFilters.excludeAll, + structDecl: structDecl ?? DeclarationFilters.excludeAll, + unionDecl: unionDecl ?? DeclarationFilters.excludeAll, + enumClassDecl: enumClassDecl ?? DeclarationFilters.excludeAll, + unnamedEnumConstants: + unnamedEnumConstants ?? DeclarationFilters.excludeAll, + globals: globals ?? DeclarationFilters.excludeAll, + macroDecl: macroDecl ?? DeclarationFilters.excludeAll, + typedefs: typedefs ?? DeclarationFilters.excludeAll, + objcInterfaces: objcInterfaces ?? DeclarationFilters.excludeAll, + objcProtocols: objcProtocols ?? DeclarationFilters.excludeAll, + includeUnusedTypedefs: includeUnusedTypedefs, + generateForPackageObjectiveC: generateForPackageObjectiveC, + sort: sort, + useSupportedTypedefs: useSupportedTypedefs, + libraryImports: Map.fromEntries( + libraryImports.map((import) => + MapEntry(import.name, import))), + usrTypeMappings: Map.fromEntries( + usrTypeMappings.map((import) => + MapEntry(import.nativeType, import))), + typedefTypeMappings: Map.fromEntries( + typedefTypeMappings.map((import) => + MapEntry(import.nativeType, import))), + structTypeMappings: Map.fromEntries( + structTypeMappings.map((import) => + MapEntry(import.nativeType, import))), + unionTypeMappings: Map.fromEntries( + unionTypeMappings.map((import) => + MapEntry(import.nativeType, import))), + nativeTypeMappings: Map.fromEntries( + nativeTypeMappings.map((import) => + MapEntry(import.nativeType, import))), + commentType: commentType ?? CommentType.def(), + structDependencies: structDependencies, + unionDependencies: unionDependencies, + structPackingOverrideFunc: structPackingOverrideFunc ?? (_) => null, + interfaceModuleFunc: interfaceModuleFunc ?? (_) => null, + protocolModuleFunc: protocolModuleFunc ?? (_) => null, + wrapperName: wrapperName, + wrapperDocComment: wrapperDocComment, + preamble: preamble, + useDartHandle: useDartHandle, + silenceEnumWarning: silenceEnumWarning, + shouldExposeFunctionTypedefFunc: + shouldExposeFunctionTypedefFunc ?? (_) => false, + isLeafFunctionFunc: isLeafFunctionFunc ?? (_) => false, + enumShouldBeIntFunc: enumShouldBeIntFunc ?? (_) => false, + unnamedEnumsShouldBeIntFunc: + unnamedEnumsShouldBeIntFunc ?? (_) => false, + ffiNativeConfig: ffiNativeConfig, + ignoreSourceErrors: ignoreSourceErrors, + formatOutput: formatOutput, + ); +} + +abstract interface class DeclarationFilters { + /// Checks if a name is allowed by a filter. + bool shouldInclude(Declaration declaration); + + /// Checks if the symbol address should be included for this name. + bool shouldIncludeSymbolAddress(Declaration declaration); + + /// Applies renaming and returns the result. + String rename(Declaration declaration); + + /// Applies member renaming and returns the result. + String renameMember(Declaration declaration, String member); + + factory DeclarationFilters({ + bool Function(Declaration declaration)? shouldInclude, + bool Function(Declaration declaration)? shouldIncludeSymbolAddress, + String Function(Declaration declaration)? rename, + String Function(Declaration declaration, String member)? renameMember, + }) => + DeclarationFiltersImpl( + shouldIncludeFunc: shouldInclude ?? (_) => false, + shouldIncludeSymbolAddressFunc: + shouldIncludeSymbolAddress ?? (_) => false, + renameFunc: rename ?? (declaration) => declaration.originalName, + renameMemberFunc: renameMember ?? (_, member) => member, + ); + + static final excludeAll = DeclarationFilters(); + static final includeAll = DeclarationFilters(shouldInclude: (_) => true); +} diff --git a/pkgs/ffigenpad/lib/src/config_provider/config_impl.dart b/pkgs/ffigenpad/lib/src/config_provider/config_impl.dart new file mode 100644 index 0000000000..0098715771 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider/config_impl.dart @@ -0,0 +1,244 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart'; +import 'config.dart'; +import 'config_types.dart'; + +class ConfigImpl implements Config { + @override + final Uri? filename; + + @override + final Uri output; + + @override + final Uri outputObjC; + + @override + final SymbolFile? symbolFile; + + @override + final Language language; + + @override + final List entryPoints; + + @override + bool shouldIncludeHeader(Uri header) => shouldIncludeHeaderFunc(header); + final bool Function(Uri header) shouldIncludeHeaderFunc; + + @override + final List compilerOpts; + + @override + final Map> varArgFunctions; + + @override + final DeclarationFilters functionDecl; + + @override + final DeclarationFilters structDecl; + + @override + final DeclarationFilters unionDecl; + + @override + final DeclarationFilters enumClassDecl; + + @override + final DeclarationFilters unnamedEnumConstants; + + @override + final DeclarationFilters globals; + + @override + final DeclarationFilters macroDecl; + + @override + final DeclarationFilters typedefs; + + @override + final DeclarationFilters objcInterfaces; + + @override + final DeclarationFilters objcProtocols; + + @override + final bool includeUnusedTypedefs; + + @override + final bool generateForPackageObjectiveC; + + @override + final bool sort; + + @override + final bool useSupportedTypedefs; + + @override + final Map libraryImports; + + @override + final Map usrTypeMappings; + + @override + final Map typedefTypeMappings; + + @override + final Map structTypeMappings; + + @override + final Map unionTypeMappings; + + @override + final Map nativeTypeMappings; + + @override + final CommentType commentType; + + @override + final CompoundDependencies structDependencies; + + @override + final CompoundDependencies unionDependencies; + + @override + PackingValue? structPackingOverride(Declaration declaration) => + structPackingOverrideFunc(declaration); + final PackingValue? Function(Declaration declaration) + structPackingOverrideFunc; + + @override + String? interfaceModule(Declaration declaration) => + interfaceModuleFunc(declaration); + final String? Function(Declaration declaration) interfaceModuleFunc; + + @override + String? protocolModule(Declaration declaration) => + protocolModuleFunc(declaration); + final String? Function(Declaration declaration) protocolModuleFunc; + + @override + final String wrapperName; + + @override + final String? wrapperDocComment; + + @override + final String? preamble; + + @override + final bool useDartHandle; + + @override + final bool silenceEnumWarning; + + @override + bool shouldExposeFunctionTypedef(Declaration declaration) => + shouldExposeFunctionTypedefFunc(declaration); + final bool Function(Declaration declaration) shouldExposeFunctionTypedefFunc; + + @override + bool isLeafFunction(Declaration declaration) => + isLeafFunctionFunc(declaration); + final bool Function(Declaration declaration) isLeafFunctionFunc; + + @override + bool enumShouldBeInt(Declaration declaration) => + enumShouldBeIntFunc(declaration); + final bool Function(Declaration declaration) enumShouldBeIntFunc; + + @override + bool unnamedEnumsShouldBeInt(Declaration declaration) => + unnamedEnumsShouldBeIntFunc(declaration); + final bool Function(Declaration declaration) unnamedEnumsShouldBeIntFunc; + + @override + final FfiNativeConfig ffiNativeConfig; + + @override + final bool ignoreSourceErrors; + + @override + final bool formatOutput; + + ConfigImpl({ + required this.filename, + required this.output, + required this.outputObjC, + required this.symbolFile, + required this.language, + required this.entryPoints, + required this.shouldIncludeHeaderFunc, + required this.compilerOpts, + required this.varArgFunctions, + required this.functionDecl, + required this.structDecl, + required this.unionDecl, + required this.enumClassDecl, + required this.unnamedEnumConstants, + required this.globals, + required this.macroDecl, + required this.typedefs, + required this.objcInterfaces, + required this.objcProtocols, + required this.includeUnusedTypedefs, + required this.generateForPackageObjectiveC, + required this.sort, + required this.useSupportedTypedefs, + required this.libraryImports, + required this.usrTypeMappings, + required this.typedefTypeMappings, + required this.structTypeMappings, + required this.unionTypeMappings, + required this.nativeTypeMappings, + required this.commentType, + required this.structDependencies, + required this.unionDependencies, + required this.structPackingOverrideFunc, + required this.interfaceModuleFunc, + required this.protocolModuleFunc, + required this.wrapperName, + required this.wrapperDocComment, + required this.preamble, + required this.useDartHandle, + required this.silenceEnumWarning, + required this.shouldExposeFunctionTypedefFunc, + required this.isLeafFunctionFunc, + required this.enumShouldBeIntFunc, + required this.unnamedEnumsShouldBeIntFunc, + required this.ffiNativeConfig, + required this.ignoreSourceErrors, + required this.formatOutput, + }); +} + +class DeclarationFiltersImpl implements DeclarationFilters { + @override + String rename(Declaration declaration) => renameFunc(declaration); + final String Function(Declaration declaration) renameFunc; + + @override + String renameMember(Declaration declaration, String member) => + renameMemberFunc(declaration, member); + final String Function(Declaration declaration, String member) + renameMemberFunc; + + @override + bool shouldInclude(Declaration declaration) => shouldIncludeFunc(declaration); + final bool Function(Declaration declaration) shouldIncludeFunc; + + @override + bool shouldIncludeSymbolAddress(Declaration declaration) => + shouldIncludeSymbolAddressFunc(declaration); + final bool Function(Declaration declaration) shouldIncludeSymbolAddressFunc; + + DeclarationFiltersImpl({ + required this.renameFunc, + required this.renameMemberFunc, + required this.shouldIncludeFunc, + required this.shouldIncludeSymbolAddressFunc, + }); +} diff --git a/pkgs/ffigenpad/lib/src/config_provider/config_spec.dart b/pkgs/ffigenpad/lib/src/config_provider/config_spec.dart new file mode 100644 index 0000000000..4486b61d09 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider/config_spec.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'package:ffigen/src/config_provider/config_spec.dart'; diff --git a/pkgs/ffigenpad/lib/src/config_provider/config_types.dart b/pkgs/ffigenpad/lib/src/config_provider/config_types.dart new file mode 100644 index 0000000000..c5e0a91f5f --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider/config_types.dart @@ -0,0 +1,427 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Contains all the neccesary classes required by config. +library; + +import 'package:quiver/pattern.dart' as quiver; + +import '../code_generator.dart'; +import 'config.dart'; + +enum Language { c, objc } + +class CommentType { + CommentStyle style; + CommentLength length; + CommentType(this.style, this.length); + + /// Sets default style as [CommentStyle.doxygen], default length as + /// [CommentLength.full]. + CommentType.def() + : style = CommentStyle.doxygen, + length = CommentLength.full; + + /// Disables any comments. + CommentType.none() + : style = CommentStyle.doxygen, + length = CommentLength.none; +} + +enum CommentStyle { doxygen, any } + +enum CommentLength { none, brief, full } + +enum CompoundDependencies { full, opaque } + +/// Holds config for how Structs Packing will be overriden. +class StructPackingOverride { + final List<(RegExp, int?)> _matchers; + + StructPackingOverride(this._matchers); + + /// Returns pack value for [name]. + PackingValue? getOverridenPackValue(String name) { + for (final (regex, value) in _matchers) { + if (quiver.matchesFull(regex, name)) { + return PackingValue(value); + } + } + return null; + } +} + +// Holds headers and filters for header. +class YamlHeaders { + /// Path to headers. + /// + /// This contains all the headers, after extraction from Globs. + final List entryPoints; + + /// Include filter for headers. + final HeaderIncludeFilter includeFilter; + + YamlHeaders({List? entryPoints, HeaderIncludeFilter? includeFilter}) + : entryPoints = entryPoints?.map(Uri.file).toList() ?? [], + includeFilter = includeFilter ?? GlobHeaderFilter(); +} + +abstract class HeaderIncludeFilter { + bool shouldInclude(Uri headerSourceFile); +} + +class GlobHeaderFilter extends HeaderIncludeFilter { + List? includeGlobs = []; + + GlobHeaderFilter({ + this.includeGlobs, + }); + + @override + bool shouldInclude(Uri headerSourceFile) { + // Return true if header was included. + for (final globPattern in includeGlobs!) { + if (quiver.matchesFull(globPattern, headerSourceFile.toFilePath())) { + return true; + } + } + + // If any includedInclusionHeaders is provided, return false. + if (includeGlobs!.isNotEmpty) { + return false; + } else { + return true; + } + } +} + +/// A generic declaration config, used for Functions, Structs, Enums, Macros, +/// unnamed Enums and Globals. +class YamlDeclarationFilters implements DeclarationFilters { + final YamlIncluder _includer; + final YamlRenamer _renamer; + final YamlMemberRenamer _memberRenamer; + final YamlIncluder _symbolAddressIncluder; + final bool excludeAllByDefault; + + YamlDeclarationFilters({ + YamlIncluder? includer, + YamlRenamer? renamer, + YamlMemberRenamer? memberRenamer, + YamlIncluder? symbolAddressIncluder, + required this.excludeAllByDefault, + }) : _includer = includer ?? YamlIncluder(), + _renamer = renamer ?? YamlRenamer(), + _memberRenamer = memberRenamer ?? YamlMemberRenamer(), + _symbolAddressIncluder = + symbolAddressIncluder ?? YamlIncluder.excludeByDefault(); + + /// Applies renaming and returns the result. + @override + String rename(Declaration declaration) => + _renamer.rename(declaration.originalName); + + /// Applies member renaming and returns the result. + @override + String renameMember(Declaration declaration, String member) => + _memberRenamer.rename(declaration.originalName, member); + + /// Checks if a name is allowed by a filter. + @override + bool shouldInclude(Declaration declaration) => + _includer.shouldInclude(declaration.originalName, excludeAllByDefault); + + /// Checks if the symbol address should be included for this name. + @override + bool shouldIncludeSymbolAddress(Declaration declaration) => + _symbolAddressIncluder.shouldInclude(declaration.originalName); +} + +/// Matches `$`, value can be accessed in group 1 of match. +final replaceGroupRegexp = RegExp(r'\$([0-9])'); + +/// Match/rename using [regExp]. +class RegExpRenamer { + final RegExp regExp; + final String replacementPattern; + + RegExpRenamer(this.regExp, this.replacementPattern); + + /// Returns true if [str] has a full match with [regExp]. + bool matches(String str) => quiver.matchesFull(regExp, str); + + /// Renames [str] according to [replacementPattern]. + /// + /// Returns [str] if [regExp] doesn't have a full match. + String rename(String str) { + if (matches(str)) { + // Get match. + final regExpMatch = regExp.firstMatch(str)!; + + /// Get group values. + /// E.g for `str`: `clang_dispose` and `regExp`: `clang_(.*)` + /// groups will be `0`: `clang_disponse`, `1`: `dispose`. + final groups = regExpMatch.groups( + List.generate(regExpMatch.groupCount, (index) => index) + + [regExpMatch.groupCount]); + + /// Replace all `$` symbols with respective groups (if any). + final result = + replacementPattern.replaceAllMapped(replaceGroupRegexp, (match) { + final groupInt = int.parse(match.group(1)!); + return groups[groupInt]!; + }); + return result; + } else { + return str; + } + } + + @override + String toString() { + return 'Regexp: $regExp, ReplacementPattern: $replacementPattern'; + } +} + +/// Handles `include/exclude` logic for a declaration. +class YamlIncluder { + final List _includeMatchers; + final Set _includeFull; + final List _excludeMatchers; + final Set _excludeFull; + + YamlIncluder({ + List? includeMatchers, + Set? includeFull, + List? excludeMatchers, + Set? excludeFull, + }) : _includeMatchers = includeMatchers ?? [], + _includeFull = includeFull ?? {}, + _excludeMatchers = excludeMatchers ?? [], + _excludeFull = excludeFull ?? {}; + + YamlIncluder.excludeByDefault() + : _includeMatchers = [], + _includeFull = {}, + _excludeMatchers = [RegExp('.*', dotAll: true)], + _excludeFull = {}; + + /// Returns true if [name] is allowed. + /// + /// Exclude overrides include. + bool shouldInclude(String name, [bool excludeAllByDefault = false]) { + if (_excludeFull.contains(name)) { + return false; + } + + for (final em in _excludeMatchers) { + if (quiver.matchesFull(em, name)) { + return false; + } + } + + if (_includeFull.contains(name)) { + return true; + } + + for (final im in _includeMatchers) { + if (quiver.matchesFull(im, name)) { + return true; + } + } + + // If user has provided 'include' field in the filter, then default + // matching is false. + if (_includeMatchers.isNotEmpty || _includeFull.isNotEmpty) { + return false; + } else { + // Otherwise, fall back to the default behavior for empty filters. + return !excludeAllByDefault; + } + } +} + +/// Handles `full/regexp` renaming logic. +class YamlRenamer { + final Map _renameFull; + final List _renameMatchers; + + YamlRenamer({ + List? renamePatterns, + Map? renameFull, + }) : _renameMatchers = renamePatterns ?? [], + _renameFull = renameFull ?? {}; + + YamlRenamer.noRename() + : _renameMatchers = [], + _renameFull = {}; + + String rename(String name) { + // Apply full rename (if any). + if (_renameFull.containsKey(name)) { + return _renameFull[name]!; + } + + // Apply rename regexp (if matches). + for (final renamer in _renameMatchers) { + if (renamer.matches(name)) { + return renamer.rename(name); + } + } + + // No renaming is provided for this declaration, return unchanged. + return name; + } +} + +/// Match declaration name using [declarationRegExp]. +class RegExpMemberRenamer { + final RegExp declarationRegExp; + final YamlRenamer memberRenamer; + + RegExpMemberRenamer(this.declarationRegExp, this.memberRenamer); + + /// Returns true if [declaration] has a full match with [declarationRegExp]. + bool matchesDeclarationName(String declaration) => + quiver.matchesFull(declarationRegExp, declaration); + + @override + String toString() { + return 'DeclarationRegExp: $declarationRegExp, ' + 'YamlMemberRenamer: $memberRenamer'; + } +} + +/// Handles `full/regexp` member renaming. +class YamlMemberRenamer { + final Map _memberRenameFull; + final List _memberRenameMatchers; + + final Map _cache = {}; + + YamlMemberRenamer({ + Map? memberRenameFull, + List? memberRenamePattern, + }) : _memberRenameFull = memberRenameFull ?? {}, + _memberRenameMatchers = memberRenamePattern ?? []; + + String rename(String declaration, String member) { + if (_cache.containsKey(declaration)) { + return _cache[declaration]!.rename(member); + } + + // Apply full rename (if any). + if (_memberRenameFull.containsKey(declaration)) { + // Add to cache. + _cache[declaration] = _memberRenameFull[declaration]!; + return _cache[declaration]!.rename(member); + } + + // Apply rename regexp (if matches). + for (final renamer in _memberRenameMatchers) { + if (renamer.matchesDeclarationName(declaration)) { + // Add to cache. + _cache[declaration] = renamer.memberRenamer; + return _cache[declaration]!.rename(member); + } + } + + // No renaming is provided for this declaration, return unchanged. + return member; + } +} + +List defaultCompilerOpts({bool macIncludeStdLib = true}) => []; + +/// Handles config for automatically added compiler options. +class CompilerOptsAuto { + final bool macIncludeStdLib; + + CompilerOptsAuto({bool? macIncludeStdLib}) + : macIncludeStdLib = macIncludeStdLib ?? true; + + /// Extracts compiler options based on OS and config. + List extractCompilerOpts() { + return defaultCompilerOpts(macIncludeStdLib: macIncludeStdLib); + } +} + +class _ObjCModuleEntry { + final RegExp pattern; + final String moduleName; + + _ObjCModuleEntry(this.pattern, this.moduleName); +} + +/// Handles applying module prefixes to ObjC classes. +class ObjCModules { + final _prefixes = <_ObjCModuleEntry>[]; + + ObjCModules(Map prefixes) { + for (final entry in prefixes.entries) { + _prefixes.add(_ObjCModuleEntry(RegExp(entry.key), entry.value)); + } + } + + /// If any of the prefixing patterns match, returns the corresponding module. + /// Otherwise returns null. + String? getModule(String className) { + for (final entry in _prefixes) { + if (quiver.matchesFull(entry.pattern, className)) { + return entry.moduleName; + } + } + return null; + } +} + +class FfiNativeConfig { + final bool enabled; + final String? assetId; + + const FfiNativeConfig({required this.enabled, this.assetId}); +} + +class SymbolFile { + final Uri importPath; + final Uri output; + + SymbolFile(this.importPath, this.output); +} + +class OutputConfig { + final String output; + final String? outputObjC; + final SymbolFile? symbolFile; + + OutputConfig(this.output, this.outputObjC, this.symbolFile); +} + +class RawVarArgFunction { + String? postfix; + final List rawTypeStrings; + + RawVarArgFunction(this.postfix, this.rawTypeStrings); +} + +class VarArgFunction { + final String postfix; + final List types; + + VarArgFunction(this.postfix, this.types); +} + +class PackingValue { + int? value; + PackingValue(this.value); +} + +class Declaration { + String usr; + String originalName; + Declaration({ + required this.usr, + required this.originalName, + }); +} diff --git a/pkgs/ffigenpad/lib/src/config_provider/spec_utils.dart b/pkgs/ffigenpad/lib/src/config_provider/spec_utils.dart new file mode 100644 index 0000000000..c9a83e56de --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider/spec_utils.dart @@ -0,0 +1,629 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:file/local.dart'; +import 'package:glob/glob.dart'; +import 'package:logging/logging.dart'; +import 'package:package_config/package_config.dart'; +import 'package:path/path.dart' as p; +import 'package:quiver/pattern.dart' as quiver; +import 'package:yaml/yaml.dart'; + +import '../code_generator.dart'; +import '../code_generator/utils.dart'; +import '../header_parser/type_extractor/cxtypekindmap.dart'; +import '../strings.dart' as strings; +import 'config_types.dart'; + +final _logger = Logger('ffigen.config_provider.spec_utils'); + +/// Replaces the path separators according to current platform. +String _replaceSeparators(String path) { + return path.replaceAll(p.windows.separator, p.posix.separator); +} + +/// Replaces the path separators according to current platform. If a relative +/// path is passed in, it is resolved relative to the config path, and the +/// absolute path is returned. +String _normalizePath(String path, String? configFilename) { + final skipNormalization = + (configFilename == null) || p.isAbsolute(path) || path.startsWith('**'); + return _replaceSeparators(skipNormalization + ? path + : p.absolute(p.join(p.dirname(configFilename), path))); +} + +Map libraryImportsExtractor( + Map? typeMap) { + final resultMap = {}; + if (typeMap != null) { + for (final kv in typeMap.entries) { + resultMap[kv.key] = LibraryImport(kv.key, kv.value); + } + } + return resultMap; +} + +void loadImportedTypes(YamlMap fileConfig, + Map usrTypeMappings, LibraryImport libraryImport) { + final symbols = fileConfig['symbols'] as YamlMap; + for (final key in symbols.keys) { + final usr = key as String; + final value = symbols[usr]! as YamlMap; + final name = value['name'] as String; + usrTypeMappings[usr] = ImportedType(libraryImport, name, name, name); + } +} + +YamlMap loadSymbolFile(String symbolFilePath, String? configFileName, + PackageConfig? packageConfig) { + final path = symbolFilePath.startsWith('package:') + ? packageConfig!.resolve(Uri.parse(symbolFilePath))!.toFilePath() + : _normalizePath(symbolFilePath, configFileName); + + return loadYaml(File(path).readAsStringSync()) as YamlMap; +} + +Map symbolFileImportExtractor( + List yamlConfig, + Map libraryImports, + String? configFileName, + PackageConfig? packageConfig) { + final resultMap = {}; + for (final item in yamlConfig) { + String symbolFilePath; + symbolFilePath = item; + final symbolFile = + loadSymbolFile(symbolFilePath, configFileName, packageConfig); + final formatVersion = symbolFile[strings.formatVersion] as String; + if (formatVersion.split('.')[0] != + strings.symbolFileFormatVersion.split('.')[0]) { + _logger.severe('Incompatible format versions for file $symbolFilePath: ' + '${strings.symbolFileFormatVersion}(ours), $formatVersion(theirs).'); + exit(1); + } + final uniqueNamer = UniqueNamer(libraryImports.keys + .followedBy([strings.defaultSymbolFileImportPrefix]).toSet()); + final files = symbolFile[strings.files] as YamlMap; + for (final file in files.keys) { + final existingImports = libraryImports.values + .where((element) => element.importPath(false) == file); + if (existingImports.isEmpty) { + final name = + uniqueNamer.makeUnique(strings.defaultSymbolFileImportPrefix); + libraryImports[name] = LibraryImport(name, file as String); + } + final libraryImport = libraryImports.values.firstWhere( + (element) => element.importPath(false) == file, + ); + loadImportedTypes(files[file] as YamlMap, resultMap, libraryImport); + } + } + return resultMap; +} + +Map> typeMapExtractor(Map? yamlConfig) { + // Key - type_name, Value - [lib, cType, dartType]. + final resultMap = >{}; + final typeMap = yamlConfig; + if (typeMap != null) { + for (final typeName in typeMap.keys) { + final typeConfigItem = typeMap[typeName] as Map; + resultMap[typeName as String] = [ + typeConfigItem[strings.lib] as String, + typeConfigItem[strings.cType] as String, + typeConfigItem[strings.dartType] as String, + ]; + } + } + return resultMap; +} + +Map makeImportTypeMapping( + Map> rawTypeMappings, + Map libraryImportsMap) { + final typeMappings = {}; + for (final key in rawTypeMappings.keys) { + final lib = rawTypeMappings[key]![0]; + final cType = rawTypeMappings[key]![1]; + final dartType = rawTypeMappings[key]![2]; + final nativeType = key; + if (strings.predefinedLibraryImports.containsKey(lib)) { + typeMappings[key] = ImportedType( + strings.predefinedLibraryImports[lib]!, cType, dartType, nativeType); + } else if (libraryImportsMap.containsKey(lib)) { + typeMappings[key] = + ImportedType(libraryImportsMap[lib]!, cType, dartType, nativeType); + } else { + throw Exception('Please declare $lib under library-imports.'); + } + } + return typeMappings; +} + +Type makePointerToType(Type type, int pointerCount) { + for (var i = 0; i < pointerCount; i++) { + type = PointerType(type); + } + return type; +} + +String makePostfixFromRawVarArgType(List rawVarArgType) { + return rawVarArgType + .map((e) => e + .replaceAll('*', 'Ptr') + .replaceAll(RegExp(r'_t$'), '') + .replaceAll(' ', '') + .replaceAll(RegExp('[^A-Za-z0-9_]'), '')) + .map((e) => e.length > 1 ? '${e[0].toUpperCase()}${e.substring(1)}' : e) + .join(''); +} + +Type makeTypeFromRawVarArgType( + String rawVarArgType, Map libraryImportsMap) { + Type baseType; + var rawBaseType = rawVarArgType.trim(); + // Split the raw type based on pointer usage. E.g - + // int => [int] + // char* => [char,*] + // ffi.Hello ** => [ffi.Hello,**] + final typeStringRegexp = RegExp(r'([a-zA-Z0-9_\s\.]+)(\**)$'); + if (!typeStringRegexp.hasMatch(rawBaseType)) { + throw Exception('Cannot parse variadic argument type - $rawVarArgType.'); + } + final regExpMatch = typeStringRegexp.firstMatch(rawBaseType)!; + final groups = regExpMatch.groups([1, 2]); + rawBaseType = groups[0]!; + // Handle basic supported types. + if (cxTypeKindToImportedTypes.containsKey(rawBaseType)) { + baseType = cxTypeKindToImportedTypes[rawBaseType]!; + } else if (supportedTypedefToImportedType.containsKey(rawBaseType)) { + baseType = supportedTypedefToImportedType[rawBaseType]!; + } else if (suportedTypedefToSuportedNativeType.containsKey(rawBaseType)) { + baseType = NativeType(suportedTypedefToSuportedNativeType[rawBaseType]!); + } else { + // Use library import if specified (E.g - ffi.UintPtr or custom.MyStruct) + final rawVarArgTypeSplit = rawBaseType.split('.'); + if (rawVarArgTypeSplit.length == 1) { + final typeName = rawVarArgTypeSplit[0].replaceAll(' ', ''); + baseType = SelfImportedType(typeName, typeName); + } else if (rawVarArgTypeSplit.length == 2) { + final lib = rawVarArgTypeSplit[0]; + final libraryImport = strings.predefinedLibraryImports[lib] ?? + libraryImportsMap[rawVarArgTypeSplit[0]]; + if (libraryImport == null) { + throw Exception('Please declare $lib in library-imports.'); + } + final typeName = rawVarArgTypeSplit[1].replaceAll(' ', ''); + baseType = ImportedType(libraryImport, typeName, typeName, typeName); + } else { + throw Exception( + 'Invalid type $rawVarArgType : Expected 0 or 1 .(dot) separators.'); + } + } + + // Handle pointers + final pointerCount = groups[1]!.length; + return makePointerToType(baseType, pointerCount); +} + +Map> makeVarArgFunctionsMapping( + Map> rawVarArgMappings, + Map libraryImportsMap) { + final mappings = >{}; + for (final key in rawVarArgMappings.keys) { + final varArgList = []; + for (final rawVarArg in rawVarArgMappings[key]!) { + var postfix = rawVarArg.postfix ?? ''; + final types = []; + for (final rva in rawVarArg.rawTypeStrings) { + types.add(makeTypeFromRawVarArgType(rva, libraryImportsMap)); + } + if (postfix.isEmpty) { + if (rawVarArgMappings[key]!.length == 1) { + postfix = ''; + } else { + postfix = makePostfixFromRawVarArgType(rawVarArg.rawTypeStrings); + } + } + // Extract postfix from config and/or deduce from var names. + varArgList.add(VarArgFunction(postfix, types)); + } + mappings[key] = varArgList; + } + return mappings; +} + +final _quoteMatcher = RegExp(r'''^["'](.*)["']$''', dotAll: true); +final _cmdlineArgMatcher = RegExp(r'''['"](\\"|[^"])*?['"]|[^ ]+'''); +List compilerOptsToList(String compilerOpts) { + final list = []; + _cmdlineArgMatcher.allMatches(compilerOpts).forEach((element) { + var match = element.group(0); + if (match != null) { + if (quiver.matchesFull(_quoteMatcher, match)) { + match = _quoteMatcher.allMatches(match).first.group(1)!; + } + list.add(match); + } + }); + + return list; +} + +List compilerOptsExtractor(List value) { + final list = []; + for (final el in value) { + list.addAll(compilerOptsToList(el)); + } + return list; +} + +YamlHeaders headersExtractor( + Map> yamlConfig, String? configFilename) { + final entryPoints = []; + final includeGlobs = []; + for (final key in yamlConfig.keys) { + if (key == strings.entryPoints) { + for (final h in yamlConfig[key]!) { + final headerGlob = _normalizePath(h, configFilename); + // Add file directly to header if it's not a Glob but a File. + if (File(headerGlob).existsSync()) { + final osSpecificPath = headerGlob; + entryPoints.add(osSpecificPath); + _logger.fine('Adding header/file: $headerGlob'); + } else { + final glob = Glob(headerGlob); + for (final file in glob.listFileSystemSync(const LocalFileSystem(), + followLinks: true)) { + final fixedPath = file.path; + entryPoints.add(fixedPath); + _logger.fine('Adding header/file: $fixedPath'); + } + } + } + } + if (key == strings.includeDirectives) { + for (final h in yamlConfig[key]!) { + final headerGlob = h; + final fixedGlob = _normalizePath(headerGlob, configFilename); + includeGlobs.add(quiver.Glob(fixedGlob)); + } + } + } + return YamlHeaders( + entryPoints: entryPoints, + includeFilter: GlobHeaderFilter( + includeGlobs: includeGlobs, + ), + ); +} + +String? _findLibInConda() { + final condaEnvPath = Platform.environment['CONDA_PREFIX'] ?? ''; + if (condaEnvPath.isNotEmpty) { + final locations = [ + p.join(condaEnvPath, 'lib'), + p.join(p.dirname(p.dirname(condaEnvPath)), 'lib'), + ]; + for (final l in locations) { + final k = findLibclangDylib(l); + if (k != null) return k; + } + } + return null; +} + +/// Returns location of dynamic library by searching default locations. Logs +/// error and throws an Exception if not found. +String findDylibAtDefaultLocations() { + // Assume clang in conda has a higher priority. + var k = _findLibInConda(); + if (k != null) return k; + if (Platform.isLinux) { + for (final l in strings.linuxDylibLocations) { + k = findLibclangDylib(l); + if (k != null) return k; + } + Process.runSync('ldconfig', ['-p']); + final ldConfigResult = Process.runSync('ldconfig', ['-p']); + if (ldConfigResult.exitCode == 0) { + final lines = (ldConfigResult.stdout as String).split('\n'); + final paths = [ + for (final line in lines) + if (line.contains('libclang')) line.split(' => ')[1], + ]; + for (final location in paths) { + if (File(location).existsSync()) { + return location; + } + } + } + } else if (Platform.isWindows) { + final dylibLocations = strings.windowsDylibLocations.toList(); + final userHome = Platform.environment['USERPROFILE']; + if (userHome != null) { + dylibLocations + .add(p.join(userHome, 'scoop', 'apps', 'llvm', 'current', 'bin')); + } + for (final l in dylibLocations) { + k = findLibclangDylib(l); + if (k != null) return k; + } + } else if (Platform.isMacOS) { + for (final l in strings.macOsDylibLocations) { + k = findLibclangDylib(l); + if (k != null) return k; + } + final findLibraryResult = + Process.runSync('xcodebuild', ['-find-library', 'libclang.dylib']); + if (findLibraryResult.exitCode == 0) { + final location = (findLibraryResult.stdout as String).split('\n').first; + if (File(location).existsSync()) { + return location; + } + } + final xcodePathResult = Process.runSync('xcode-select', ['-print-path']); + if (xcodePathResult.exitCode == 0) { + final xcodePath = (xcodePathResult.stdout as String).split('\n').first; + final location = + p.join(xcodePath, strings.xcodeDylibLocation, strings.dylibFileName); + if (File(location).existsSync()) { + return location; + } + } + } else { + throw Exception('Unsupported Platform.'); + } + + _logger.severe("Couldn't find dynamic library in default locations."); + _logger.severe( + "Please supply one or more path/to/llvm in ffigen's config under the key '${strings.llvmPath}'."); + throw Exception("Couldn't find dynamic library in default locations."); +} + +String? findLibclangDylib(String parentFolder) { + final location = p.join(parentFolder, strings.dylibFileName); + if (File(location).existsSync()) { + return location; + } else { + return null; + } +} + +String llvmPathExtractor(List value) { + // Extract libclang's dylib from user specified paths. + for (final path in value) { + final dylibPath = + findLibclangDylib(p.join(path, strings.dynamicLibParentName)); + if (dylibPath != null) { + _logger.fine('Found dynamic library at: $dylibPath'); + return dylibPath; + } + // Check if user has specified complete path to dylib. + final completeDylibPath = path; + if (p.extension(completeDylibPath).isNotEmpty && + File(completeDylibPath).existsSync()) { + _logger.info( + 'Using complete dylib path: $completeDylibPath from llvm-path.'); + return completeDylibPath; + } + } + _logger.fine("Couldn't find dynamic library under paths specified by " + '${strings.llvmPath}.'); + // Extract path from default locations. + try { + final res = findDylibAtDefaultLocations(); + return res; + } catch (e) { + final path = p.join(strings.dynamicLibParentName, strings.dylibFileName); + _logger.severe("Couldn't find $path in specified locations."); + exit(1); + } +} + +OutputConfig outputExtractor( + dynamic value, String? configFilename, PackageConfig? packageConfig) { + if (value is String) { + return OutputConfig(_normalizePath(value, configFilename), null, null); + } + value = value as Map; + return OutputConfig( + _normalizePath(value[strings.bindings] as String, configFilename), + value.containsKey(strings.objCBindings) + ? _normalizePath(value[strings.objCBindings] as String, configFilename) + : null, + value.containsKey(strings.symbolFile) + ? symbolFileOutputExtractor( + value[strings.symbolFile], configFilename, packageConfig) + : null, + ); +} + +SymbolFile symbolFileOutputExtractor( + dynamic value, String? configFilename, PackageConfig? packageConfig) { + value = value as Map; + var output = Uri.parse(value[strings.output] as String); + if (output.scheme != 'package') { + _logger.warning('Consider using a Package Uri for ${strings.symbolFile} -> ' + '${strings.output}: $output so that external packages can use it.'); + output = Uri.file(_normalizePath(output.toFilePath(), configFilename)); + } else { + output = packageConfig!.resolve(output)!; + } + final importPath = Uri.parse(value[strings.importPath] as String); + if (importPath.scheme != 'package') { + _logger.warning('Consider using a Package Uri for ${strings.symbolFile} -> ' + '${strings.importPath}: $importPath so that external packages ' + 'can use it.'); + } + return SymbolFile(importPath, output); +} + +/// Returns true if [str] is not a full name. +/// +/// E.g `abc` is a full name, `abc.*` is not. +bool isFullDeclarationName(String str) => + quiver.matchesFull(RegExp('[a-zA-Z_0-9]*'), str); + +YamlIncluder extractIncluderFromYaml(Map yamlMap) { + final includeMatchers = [], + includeFull = {}, + excludeMatchers = [], + excludeFull = {}; + + final include = yamlMap[strings.include] as List?; + if (include != null) { + if (include.isEmpty) { + return YamlIncluder.excludeByDefault(); + } + for (final str in include) { + if (isFullDeclarationName(str)) { + includeFull.add(str); + } else { + includeMatchers.add(RegExp(str, dotAll: true)); + } + } + } + + final exclude = yamlMap[strings.exclude] as List?; + if (exclude != null) { + for (final str in exclude) { + if (isFullDeclarationName(str)) { + excludeFull.add(str); + } else { + excludeMatchers.add(RegExp(str, dotAll: true)); + } + } + } + + return YamlIncluder( + includeMatchers: includeMatchers, + includeFull: includeFull, + excludeMatchers: excludeMatchers, + excludeFull: excludeFull, + ); +} + +Map> varArgFunctionConfigExtractor( + Map yamlMap) { + final result = >{}; + final configMap = yamlMap; + for (final key in configMap.keys) { + final vafuncs = []; + for (final rawVaFunc in configMap[key] as List) { + if (rawVaFunc is List) { + vafuncs.add(RawVarArgFunction(null, rawVaFunc.cast())); + } else if (rawVaFunc is Map) { + vafuncs.add(RawVarArgFunction(rawVaFunc[strings.postfix] as String?, + (rawVaFunc[strings.types] as List).cast())); + } else { + throw Exception('Unexpected type in variadic-argument config.'); + } + } + result[key as String] = vafuncs; + } + + return result; +} + +YamlDeclarationFilters declarationConfigExtractor( + Map yamlMap, bool excludeAllByDefault) { + final renamePatterns = []; + final renameFull = {}; + final memberRenamePatterns = []; + final memberRenamerFull = {}; + + final includer = extractIncluderFromYaml(yamlMap); + + final symbolIncluder = yamlMap[strings.symbolAddress] as YamlIncluder?; + + final rename = yamlMap[strings.rename] as Map?; + + if (rename != null) { + for (final key in rename.keys) { + final str = key.toString(); + if (isFullDeclarationName(str)) { + renameFull[str] = rename[str]!; + } else { + renamePatterns + .add(RegExpRenamer(RegExp(str, dotAll: true), rename[str]!)); + } + } + } + + final memberRename = + yamlMap[strings.memberRename] as Map>?; + + if (memberRename != null) { + for (final key in memberRename.keys) { + final decl = key.toString(); + final renamePatterns = []; + final renameFull = {}; + + final memberRenameMap = memberRename[decl]!; + for (final member in memberRenameMap.keys) { + final memberStr = member.toString(); + if (isFullDeclarationName(memberStr)) { + renameFull[memberStr] = memberRenameMap[member]!; + } else { + renamePatterns.add(RegExpRenamer( + RegExp(memberStr, dotAll: true), memberRenameMap[member]!)); + } + } + if (isFullDeclarationName(decl)) { + memberRenamerFull[decl] = YamlRenamer( + renameFull: renameFull, + renamePatterns: renamePatterns, + ); + } else { + memberRenamePatterns.add( + RegExpMemberRenamer( + RegExp(decl, dotAll: true), + YamlRenamer( + renameFull: renameFull, + renamePatterns: renamePatterns, + ), + ), + ); + } + } + } + + return YamlDeclarationFilters( + includer: includer, + renamer: YamlRenamer( + renameFull: renameFull, + renamePatterns: renamePatterns, + ), + memberRenamer: YamlMemberRenamer( + memberRenameFull: memberRenamerFull, + memberRenamePattern: memberRenamePatterns, + ), + symbolAddressIncluder: symbolIncluder, + excludeAllByDefault: excludeAllByDefault, + ); +} + +StructPackingOverride structPackingOverrideExtractor( + Map value) { + final matcherMap = <(RegExp, int?)>[]; + for (final key in value.keys) { + matcherMap.add(( + RegExp(key as String, dotAll: true), + strings.packingValuesMap[value[key]] + )); + } + return StructPackingOverride(matcherMap); +} + +FfiNativeConfig ffiNativeExtractor(dynamic yamlConfig) { + final yamlMap = yamlConfig as Map?; + return FfiNativeConfig( + enabled: true, + assetId: yamlMap?[strings.ffiNativeAsset] as String?, + ); +} diff --git a/pkgs/ffigenpad/lib/src/config_provider/yaml_config.dart b/pkgs/ffigenpad/lib/src/config_provider/yaml_config.dart new file mode 100644 index 0000000000..3ee1416233 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/config_provider/yaml_config.dart @@ -0,0 +1,1083 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Validates the yaml input by the user, prints useful info for the user. +library; + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:package_config/package_config_types.dart'; +import 'package:yaml/yaml.dart'; + +import '../code_generator.dart'; +import '../strings.dart' as strings; +import 'config.dart'; +import 'config_spec.dart'; +import 'config_types.dart'; +import 'spec_utils.dart'; + +final _logger = Logger('ffigen.config_provider.config'); + +/// Provides configurations to other modules. +/// +/// Handles validation, extraction of configurations from a yaml file. +class YamlConfig implements Config { + /// Input config filename, if any. + @override + final Uri? filename; + + /// Package config. + final PackageConfig? packageConfig; + + /// Output file name. + @override + Uri get output => Uri.file(_output); + late String _output; + + /// Output ObjC file name. + @override + Uri get outputObjC => Uri.file(_outputObjC ?? '$_output.m'); + String? _outputObjC; + + /// Symbol file config. + @override + SymbolFile? get symbolFile => _symbolFile; + late SymbolFile? _symbolFile; + + /// Language that ffigen is consuming. + @override + Language get language => _language; + late Language _language; + + /// Path to headers. May not contain globs. + @override + List get entryPoints => _headers.entryPoints; + + /// Whether to include a specific header. This exists in addition to + /// [entryPoints] to allow filtering of transitively included headers. + @override + bool shouldIncludeHeader(Uri header) => + _headers.includeFilter.shouldInclude(header); + late YamlHeaders _headers; + + /// CommandLine Arguments to pass to clang_compiler. + @override + List get compilerOpts => _compilerOpts; + late List _compilerOpts; + + /// VarArg function handling. + @override + Map> get varArgFunctions => _varArgFunctions; + late Map> _varArgFunctions = {}; + + /// Declaration config for Functions. + @override + DeclarationFilters get functionDecl => _functionDecl; + late DeclarationFilters _functionDecl; + + /// Declaration config for Structs. + @override + DeclarationFilters get structDecl => _structDecl; + late DeclarationFilters _structDecl; + + /// Declaration config for Unions. + @override + DeclarationFilters get unionDecl => _unionDecl; + late DeclarationFilters _unionDecl; + + /// Declaration config for Enums. + @override + DeclarationFilters get enumClassDecl => _enumClassDecl; + late DeclarationFilters _enumClassDecl; + + /// Declaration config for Unnamed enum constants. + @override + DeclarationFilters get unnamedEnumConstants => _unnamedEnumConstants; + late DeclarationFilters _unnamedEnumConstants; + + /// Declaration config for Globals. + @override + DeclarationFilters get globals => _globals; + late DeclarationFilters _globals; + + /// Declaration config for Macro constants. + @override + DeclarationFilters get macroDecl => _macroDecl; + late DeclarationFilters _macroDecl; + + /// Declaration config for Typedefs. + @override + DeclarationFilters get typedefs => _typedefs; + late DeclarationFilters _typedefs; + + /// Declaration config for Objective C interfaces. + @override + DeclarationFilters get objcInterfaces => _objcInterfaces; + late DeclarationFilters _objcInterfaces; + + /// Declaration config for Objective C protocols. + @override + DeclarationFilters get objcProtocols => _objcProtocols; + late DeclarationFilters _objcProtocols; + + /// If enabled, the default behavior of all declaration filters is to exclude + /// everything, rather than include everything. + late bool _excludeAllByDefault; + + /// If enabled, unused typedefs will also be generated. + @override + bool get includeUnusedTypedefs => _includeUnusedTypedefs; + late bool _includeUnusedTypedefs; + + /// Undocumented option that changes code generation for package:objective_c. + /// The main difference is whether NSObject etc are imported from + /// package:objective_c (the default) or code genned like any other class. + /// This is necessary because package:objective_c can't import NSObject from + /// itself. + @override + bool get generateForPackageObjectiveC => _generateForPackageObjectiveC; + late bool _generateForPackageObjectiveC; + + /// If generated bindings should be sorted alphabetically. + @override + bool get sort => _sort; + late bool _sort; + + /// If typedef of supported types(int8_t) should be directly used. + @override + bool get useSupportedTypedefs => _useSupportedTypedefs; + late bool _useSupportedTypedefs; + + /// Stores all the library imports specified by user including those for ffi + /// and pkg_ffi. + @override + Map get libraryImports => _libraryImports; + late Map _libraryImports; + + /// Stores all the symbol file maps name to ImportedType mappings specified by + /// user. + @override + Map get usrTypeMappings => _usrTypeMappings; + late Map _usrTypeMappings; + + /// Stores typedef name to ImportedType mappings specified by user. + @override + Map get typedefTypeMappings => _typedefTypeMappings; + late Map _typedefTypeMappings; + + /// Stores struct name to ImportedType mappings specified by user. + @override + Map get structTypeMappings => _structTypeMappings; + late Map _structTypeMappings; + + /// Stores union name to ImportedType mappings specified by user. + @override + Map get unionTypeMappings => _unionTypeMappings; + late Map _unionTypeMappings; + + /// Stores native int name to ImportedType mappings specified by user. + @override + Map get nativeTypeMappings => _nativeTypeMappings; + late Map _nativeTypeMappings; + + /// Extracted Doc comment type. + @override + CommentType get commentType => _commentType; + late CommentType _commentType; + + /// Whether structs that are dependencies should be included. + @override + CompoundDependencies get structDependencies => _structDependencies; + late CompoundDependencies _structDependencies; + + /// Whether unions that are dependencies should be included. + @override + CompoundDependencies get unionDependencies => _unionDependencies; + late CompoundDependencies _unionDependencies; + + /// Holds config for how struct packing should be overriden. + @override + PackingValue? structPackingOverride(Declaration declaration) => + _structPackingOverride.getOverridenPackValue(declaration.originalName); + late StructPackingOverride _structPackingOverride; + + /// The module that the ObjC interface belongs to. + @override + String? interfaceModule(Declaration declaration) => + _objcInterfaceModules.getModule(declaration.originalName); + late ObjCModules _objcInterfaceModules; + + /// The module that the ObjC protocols belongs to. + @override + String? protocolModule(Declaration declaration) => + _objcProtocolModules.getModule(declaration.originalName); + late ObjCModules _objcProtocolModules; + + /// Name of the wrapper class. + @override + String get wrapperName => _wrapperName; + late String _wrapperName; + + /// Doc comment for the wrapper class. + @override + String? get wrapperDocComment => _wrapperDocComment; + String? _wrapperDocComment; + + /// Header of the generated bindings. + @override + String? get preamble => _preamble; + String? _preamble; + + /// If `Dart_Handle` should be mapped with Handle/Object. + @override + bool get useDartHandle => _useDartHandle; + late bool _useDartHandle; + + /// Where to silence warning for enum integer type mimicking. + @override + bool get silenceEnumWarning => _silenceEnumWarning; + late bool _silenceEnumWarning; + + /// Whether to expose the function typedef for a given function. + @override + bool shouldExposeFunctionTypedef(Declaration declaration) => + _exposeFunctionTypedefs.shouldInclude(declaration.originalName); + late YamlIncluder _exposeFunctionTypedefs; + + /// Whether the given function is a leaf function. + @override + bool isLeafFunction(Declaration declaration) => + _leafFunctions.shouldInclude(declaration.originalName); + late YamlIncluder _leafFunctions; + + /// Whether to generate the given enum as a series of int constants, rather + /// than a real Dart enum. + @override + bool enumShouldBeInt(Declaration declaration) => + _enumsAsInt.shouldInclude(declaration.originalName); + late YamlIncluder _enumsAsInt; + + /// Whether to generate the given unnamed enum as a series of int constants, + /// rather than a real Dart enum. + @override + bool unnamedEnumsShouldBeInt(Declaration declaration) => + _unnamedEnumsAsInt.shouldInclude(declaration.originalName); + late YamlIncluder _unnamedEnumsAsInt; + + @override + FfiNativeConfig get ffiNativeConfig => _ffiNativeConfig; + late FfiNativeConfig _ffiNativeConfig; + + /// Where to ignore compiler warnings/errors in source header files. + @override + bool ignoreSourceErrors = false; + + /// Whether to format the output file. + @override + bool formatOutput = true; + + YamlConfig._({required this.filename, required this.packageConfig}); + + /// Create config from Yaml map. + factory YamlConfig.fromYaml(YamlMap map, + {String? filename, PackageConfig? packageConfig}) { + final config = YamlConfig._( + filename: filename == null ? null : Uri.file(filename), + packageConfig: packageConfig); + _logger.finest('Config Map: $map'); + + final ffigenConfigSpec = config._getRootConfigSpec(); + final result = ffigenConfigSpec.validate(map); + if (!result) { + throw const FormatException('Invalid configurations provided.'); + } + + ffigenConfigSpec.extract(map); + return config; + } + + /// Create config from a file. + factory YamlConfig.fromFile(File file, {PackageConfig? packageConfig}) { + // Throws a [YamlException] if it's unable to parse the Yaml. + final configYaml = loadYaml(file.readAsStringSync()) as YamlMap; + + return YamlConfig.fromYaml(configYaml, + filename: file.path, packageConfig: packageConfig); + } + + /// Returns the root ConfigSpec object. + static ConfigSpec getsRootConfigSpec() { + final configspecs = YamlConfig._(filename: null, packageConfig: null); + return configspecs._getRootConfigSpec(); + } + + /// Add compiler options for clang. If [highPriority] is true these are added + /// to the front of the list. + void addCompilerOpts(String compilerOpts, {bool highPriority = false}) { + if (highPriority) { + _compilerOpts.insertAll( + 0, compilerOptsToList(compilerOpts)); // Inserts at the front. + } else { + _compilerOpts.addAll(compilerOptsToList(compilerOpts)); + } + } + + ConfigSpec _getRootConfigSpec() { + return HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.excludeAllByDefault, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => false, + resultOrDefault: (node) => _excludeAllByDefault = node.value as bool, + ), + HeterogeneousMapEntry( + key: strings.output, + required: true, + valueConfigSpec: OneOfConfigSpec( + childConfigSpecs: [ + _filePathStringConfigSpec(), + _outputFullConfigSpec(), + ], + transform: (node) => outputExtractor( + node.value, filename?.toFilePath(), packageConfig), + result: (node) { + _output = (node.value as OutputConfig).output; + _outputObjC = (node.value as OutputConfig).outputObjC; + _symbolFile = (node.value as OutputConfig).symbolFile; + }, + )), + HeterogeneousMapEntry( + key: strings.language, + valueConfigSpec: EnumConfigSpec( + allowedValues: {strings.langC, strings.langObjC}, + transform: (node) { + if (node.value == strings.langObjC) { + _logger.severe( + 'Objective C support is EXPERIMENTAL. The API may change ' + 'in a breaking way without notice.'); + return Language.objc; + } else { + return Language.c; + } + }, + ), + defaultValue: (node) => Language.c, + resultOrDefault: (node) => _language = node.value as Language, + ), + HeterogeneousMapEntry( + key: strings.headers, + required: true, + valueConfigSpec: + HeterogeneousMapConfigSpec, YamlHeaders>( + entries: [ + HeterogeneousMapEntry( + key: strings.entryPoints, + valueConfigSpec: ListConfigSpec>( + childConfigSpec: StringConfigSpec()), + required: true, + ), + HeterogeneousMapEntry( + key: strings.includeDirectives, + valueConfigSpec: ListConfigSpec>( + childConfigSpec: StringConfigSpec()), + ), + ], + transform: (node) => + headersExtractor(node.value, filename?.toFilePath()), + result: (node) => _headers = node.value, + )), + HeterogeneousMapEntry( + key: strings.ignoreSourceErrors, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => false, + resultOrDefault: (node) { + // Set value to true if not already. + ignoreSourceErrors = ignoreSourceErrors || node.value as bool; + }, + ), + HeterogeneousMapEntry( + key: strings.compilerOpts, + valueConfigSpec: OneOfConfigSpec, List>( + childConfigSpecs: [ + StringConfigSpec( + transform: (node) => [node.value], + ), + ListConfigSpec>( + childConfigSpec: StringConfigSpec()) + ], + transform: (node) => compilerOptsExtractor(node.value), + ), + defaultValue: (node) => [], + resultOrDefault: (node) => _compilerOpts = node.value as List, + ), + HeterogeneousMapEntry( + key: strings.compilerOptsAuto, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.macos, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.includeCStdLib, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => true, + ) + ], + ), + ) + ], + transform: (node) => CompilerOptsAuto( + macIncludeStdLib: (node.value[strings.macos] + as Map?)?[strings.includeCStdLib] as bool, + ), + result: (node) => _compilerOpts.addAll( + (node.value as CompilerOptsAuto).extractCompilerOpts()), + )), + HeterogeneousMapEntry( + key: strings.libraryImports, + valueConfigSpec: MapConfigSpec>( + keyValueConfigSpecs: [ + (keyRegexp: '.*', valueConfigSpec: StringConfigSpec()), + ], + customValidation: _libraryImportsPredefinedValidation, + transform: (node) => libraryImportsExtractor(node.value.cast()), + ), + defaultValue: (node) => {}, + resultOrDefault: (node) => + _libraryImports = (node.value) as Map, + ), + HeterogeneousMapEntry( + key: strings.functions, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._memberRenameProperties(), + HeterogeneousMapEntry( + key: strings.symbolAddress, + valueConfigSpec: _includeExcludeObject(), + defaultValue: (node) => YamlIncluder.excludeByDefault(), + ), + HeterogeneousMapEntry( + key: strings.exposeFunctionTypedefs, + valueConfigSpec: _includeExcludeObject(), + defaultValue: (node) => YamlIncluder.excludeByDefault(), + ), + HeterogeneousMapEntry( + key: strings.leafFunctions, + valueConfigSpec: _includeExcludeObject(), + defaultValue: (node) => YamlIncluder.excludeByDefault(), + ), + HeterogeneousMapEntry( + key: strings.varArgFunctions, + valueConfigSpec: _functionVarArgsConfigSpec(), + defaultValue: (node) => >{}, + resultOrDefault: (node) { + _varArgFunctions = makeVarArgFunctionsMapping( + node.value as Map>, + _libraryImports); + }, + ), + ], + result: (node) { + _functionDecl = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _exposeFunctionTypedefs = (node.value + as Map)[strings.exposeFunctionTypedefs] as YamlIncluder; + _leafFunctions = + (node.value as Map)[strings.leafFunctions] as YamlIncluder; + }, + )), + HeterogeneousMapEntry( + key: strings.structs, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._memberRenameProperties(), + _dependencyOnlyHeterogeneousMapKey(), + HeterogeneousMapEntry( + key: strings.structPack, + valueConfigSpec: MapConfigSpec( + keyValueConfigSpecs: [ + ( + keyRegexp: '.*', + valueConfigSpec: EnumConfigSpec( + allowedValues: {'none', 1, 2, 4, 8, 16}, + transform: (node) => + node.value == 'none' ? null : node.value, + ), + ) + ], + transform: (node) => + structPackingOverrideExtractor(node.value), + ), + defaultValue: (node) => StructPackingOverride([]), + resultOrDefault: (node) => _structPackingOverride = + node.value as StructPackingOverride, + ), + ], + result: (node) { + _structDecl = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _structDependencies = (node.value + as Map)[strings.dependencyOnly] as CompoundDependencies; + }, + )), + HeterogeneousMapEntry( + key: strings.unions, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._memberRenameProperties(), + _dependencyOnlyHeterogeneousMapKey(), + ], + result: (node) { + _unionDecl = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _unionDependencies = (node.value as Map)[strings.dependencyOnly] + as CompoundDependencies; + }, + )), + HeterogeneousMapEntry( + key: strings.enums, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._memberRenameProperties(), + ..._enumIntProperties(), + ], + result: (node) { + _enumClassDecl = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _enumsAsInt = + (node.value as Map)[strings.enumAsInt] as YamlIncluder; + }, + )), + HeterogeneousMapEntry( + key: strings.unnamedEnums, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._enumIntProperties(), + ], + result: (node) { + _unnamedEnumConstants = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _unnamedEnumsAsInt = + (node.value as Map)[strings.enumAsInt] as YamlIncluder; + }, + )), + HeterogeneousMapEntry( + key: strings.globals, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + HeterogeneousMapEntry( + key: strings.symbolAddress, + valueConfigSpec: _includeExcludeObject(), + defaultValue: (node) => YamlIncluder.excludeByDefault(), + ) + ], + result: (node) { + _globals = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + }, + )), + HeterogeneousMapEntry( + key: strings.macros, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ], + result: (node) { + _macroDecl = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + }, + )), + HeterogeneousMapEntry( + key: strings.typedefs, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ], + result: (node) { + _typedefs = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + }, + )), + HeterogeneousMapEntry( + key: strings.objcInterfaces, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._memberRenameProperties(), + HeterogeneousMapEntry( + key: strings.objcModule, + valueConfigSpec: _objcModuleObject(), + defaultValue: (node) => ObjCModules({}), + ) + ], + result: (node) { + _objcInterfaces = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _objcInterfaceModules = + (node.value as Map)[strings.objcModule] as ObjCModules; + }, + )), + HeterogeneousMapEntry( + key: strings.objcProtocols, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + ..._includeExcludeProperties(), + ..._renameProperties(), + ..._memberRenameProperties(), + HeterogeneousMapEntry( + key: strings.objcModule, + valueConfigSpec: _objcModuleObject(), + defaultValue: (node) => ObjCModules({}), + ) + ], + result: (node) { + _objcProtocols = declarationConfigExtractor( + node.value as Map, _excludeAllByDefault); + _objcProtocolModules = + (node.value as Map)[strings.objcModule] as ObjCModules; + }, + )), + HeterogeneousMapEntry( + key: strings.import, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.symbolFilesImport, + valueConfigSpec: + ListConfigSpec>( + childConfigSpec: StringConfigSpec(), + transform: (node) => symbolFileImportExtractor(node.value, + _libraryImports, filename?.toFilePath(), packageConfig), + ), + defaultValue: (node) => {}, + resultOrDefault: (node) => _usrTypeMappings = + node.value as Map, + ) + ], + )), + HeterogeneousMapEntry( + key: strings.typeMap, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.typeMapTypedefs, + valueConfigSpec: _mappedTypeObject(), + defaultValue: (node) => >{}, + ), + HeterogeneousMapEntry( + key: strings.typeMapStructs, + valueConfigSpec: _mappedTypeObject(), + defaultValue: (node) => >{}, + ), + HeterogeneousMapEntry( + key: strings.typeMapUnions, + valueConfigSpec: _mappedTypeObject(), + defaultValue: (node) => >{}, + ), + HeterogeneousMapEntry( + key: strings.typeMapNativeTypes, + valueConfigSpec: _mappedTypeObject(), + defaultValue: (node) => >{}, + ), + ], + result: (node) { + final nodeValue = node.value as Map; + _typedefTypeMappings = makeImportTypeMapping( + (nodeValue[strings.typeMapTypedefs]) + as Map>, + _libraryImports, + ); + _structTypeMappings = makeImportTypeMapping( + (nodeValue[strings.typeMapStructs]) + as Map>, + _libraryImports, + ); + _unionTypeMappings = makeImportTypeMapping( + (nodeValue[strings.typeMapUnions]) + as Map>, + _libraryImports, + ); + _nativeTypeMappings = makeImportTypeMapping( + (nodeValue[strings.typeMapNativeTypes]) + as Map>, + _libraryImports, + ); + }, + )), + HeterogeneousMapEntry( + key: strings.includeUnusedTypedefs, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => false, + resultOrDefault: (node) => + _includeUnusedTypedefs = node.value as bool, + ), + HeterogeneousMapEntry( + key: strings.generateForPackageObjectiveC, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => false, + resultOrDefault: (node) => + _generateForPackageObjectiveC = node.value as bool, + ), + HeterogeneousMapEntry( + key: strings.sort, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => false, + resultOrDefault: (node) => _sort = node.value as bool, + ), + HeterogeneousMapEntry( + key: strings.useSupportedTypedefs, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => true, + resultOrDefault: (node) => _useSupportedTypedefs = node.value as bool, + ), + HeterogeneousMapEntry( + key: strings.comments, + valueConfigSpec: _commentConfigSpec(), + defaultValue: (node) => CommentType.def(), + resultOrDefault: (node) => _commentType = node.value as CommentType, + ), + HeterogeneousMapEntry( + key: strings.name, + valueConfigSpec: _dartClassNameStringConfigSpec(), + defaultValue: (node) { + _logger.warning( + "Prefer adding Key '${node.pathString}' to your config."); + return 'NativeLibrary'; + }, + resultOrDefault: (node) => _wrapperName = node.value as String, + ), + HeterogeneousMapEntry( + key: strings.description, + valueConfigSpec: _nonEmptyStringConfigSpec(), + defaultValue: (node) { + _logger.warning( + "Prefer adding Key '${node.pathString}' to your config."); + return null; + }, + resultOrDefault: (node) => _wrapperDocComment = node.value as String?, + ), + HeterogeneousMapEntry( + key: strings.preamble, + valueConfigSpec: StringConfigSpec( + result: (node) => _preamble = node.value as String?, + )), + HeterogeneousMapEntry( + key: strings.useDartHandle, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => true, + resultOrDefault: (node) => _useDartHandle = node.value as bool, + ), + HeterogeneousMapEntry( + key: strings.ffiNative, + valueConfigSpec: OneOfConfigSpec( + childConfigSpecs: [ + EnumConfigSpec(allowedValues: {null}), + HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.ffiNativeAsset, + valueConfigSpec: StringConfigSpec(), + required: true, + ) + ], + ) + ], + transform: (node) => ffiNativeExtractor(node.value), + ), + defaultValue: (node) => const FfiNativeConfig(enabled: false), + resultOrDefault: (node) => + _ffiNativeConfig = (node.value) as FfiNativeConfig, + ), + HeterogeneousMapEntry( + key: strings.silenceEnumWarning, + valueConfigSpec: BoolConfigSpec(), + defaultValue: (node) => false, + resultOrDefault: (node) => _silenceEnumWarning = node.value as bool, + ), + ], + ); + } + + bool _libraryImportsPredefinedValidation(ConfigValue node) { + if (node.value is YamlMap) { + return (node.value as YamlMap).keys.where((key) { + if (strings.predefinedLibraryImports.containsKey(key)) { + _logger.severe( + '${node.pathString} -> $key should not collide with any ' + 'predefined imports - ${strings.predefinedLibraryImports.keys}.'); + return true; + } + return false; + }).isEmpty; + } + return true; + } + + OneOfConfigSpec _commentConfigSpec() { + return OneOfConfigSpec( + childConfigSpecs: [ + BoolConfigSpec( + transform: (node) => + (node.value == true) ? CommentType.def() : CommentType.none(), + ), + HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.style, + valueConfigSpec: EnumConfigSpec( + allowedValues: {strings.doxygen, strings.any}, + transform: (node) => node.value == strings.doxygen + ? CommentStyle.doxygen + : CommentStyle.any, + ), + defaultValue: (node) => CommentStyle.doxygen, + ), + HeterogeneousMapEntry( + key: strings.length, + valueConfigSpec: EnumConfigSpec( + allowedValues: {strings.brief, strings.full}, + transform: (node) => node.value == strings.brief + ? CommentLength.brief + : CommentLength.full, + ), + defaultValue: (node) => CommentLength.full, + ), + ], + transform: (node) => CommentType( + node.value[strings.style] as CommentStyle, + node.value[strings.length] as CommentLength, + ), + ), + ], + ); + } + + MapConfigSpec _functionVarArgsConfigSpec() { + return MapConfigSpec( + keyValueConfigSpecs: [ + ( + keyRegexp: '.*', + valueConfigSpec: ListConfigSpec( + childConfigSpec: OneOfConfigSpec( + childConfigSpecs: [ + ListConfigSpec(childConfigSpec: StringConfigSpec()), + HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.types, + valueConfigSpec: ListConfigSpec>( + childConfigSpec: StringConfigSpec()), + required: true, + ), + HeterogeneousMapEntry( + key: strings.postfix, + valueConfigSpec: StringConfigSpec(), + ), + ], + ) + ], + ), + ) + ) + ], + transform: (node) => varArgFunctionConfigExtractor(node.value), + ); + } + + HeterogeneousMapConfigSpec _outputFullConfigSpec() { + return HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.bindings, + valueConfigSpec: _filePathStringConfigSpec(), + required: true, + ), + HeterogeneousMapEntry( + key: strings.objCBindings, + valueConfigSpec: _filePathStringConfigSpec(), + ), + HeterogeneousMapEntry( + key: strings.symbolFile, + valueConfigSpec: HeterogeneousMapConfigSpec( + entries: [ + HeterogeneousMapEntry( + key: strings.output, + valueConfigSpec: _filePathStringConfigSpec(), + required: true, + ), + HeterogeneousMapEntry( + key: strings.importPath, + valueConfigSpec: StringConfigSpec(), + required: true, + ), + ], + ), + ), + ], + ); + } + + StringConfigSpec _filePathStringConfigSpec() { + return StringConfigSpec( + schemaDefName: 'filePath', + schemaDescription: 'A file path', + ); + } + + StringConfigSpec _nonEmptyStringConfigSpec() { + return StringConfigSpec( + schemaDefName: 'nonEmptyString', + pattern: r'.+', + ); + } + + StringConfigSpec _dartClassNameStringConfigSpec() { + return StringConfigSpec( + schemaDefName: 'publicDartClass', + schemaDescription: 'A public dart class name.', + pattern: r'^[a-zA-Z]+[_a-zA-Z0-9]*$', + ); + } + + List _includeExcludeProperties() { + return [ + HeterogeneousMapEntry( + key: strings.include, + valueConfigSpec: _fullMatchOrRegexpList(), + ), + HeterogeneousMapEntry( + key: strings.exclude, + valueConfigSpec: _fullMatchOrRegexpList(), + defaultValue: (node) => [], + ), + ]; + } + + ListConfigSpec> _fullMatchOrRegexpList() { + return ListConfigSpec( + schemaDefName: 'fullMatchOrRegexpList', + childConfigSpec: StringConfigSpec(), + ); + } + + List _renameProperties() { + return [ + HeterogeneousMapEntry( + key: strings.rename, + valueConfigSpec: MapConfigSpec( + schemaDefName: 'rename', + keyValueConfigSpecs: [ + (keyRegexp: '.*', valueConfigSpec: StringConfigSpec()), + ], + ), + ), + ]; + } + + List _memberRenameProperties() { + return [ + HeterogeneousMapEntry( + key: strings.memberRename, + valueConfigSpec: MapConfigSpec, + Map>>( + schemaDefName: 'memberRename', + keyValueConfigSpecs: [ + ( + keyRegexp: '.*', + valueConfigSpec: MapConfigSpec>( + keyValueConfigSpecs: [ + (keyRegexp: '.*', valueConfigSpec: StringConfigSpec()) + ], + ), + ), + ], + ), + ), + ]; + } + + List _enumIntProperties() => [ + HeterogeneousMapEntry( + key: strings.enumAsInt, + defaultValue: (node) => YamlIncluder.excludeByDefault(), + valueConfigSpec: _includeExcludeObject(), + ), + ]; + + HeterogeneousMapConfigSpec, YamlIncluder> + _includeExcludeObject() { + return HeterogeneousMapConfigSpec( + schemaDefName: 'includeExclude', + entries: [ + ..._includeExcludeProperties(), + ], + transform: (node) => extractIncluderFromYaml(node.value), + ); + } + + HeterogeneousMapEntry _dependencyOnlyHeterogeneousMapKey() { + return HeterogeneousMapEntry( + key: strings.dependencyOnly, + valueConfigSpec: EnumConfigSpec( + schemaDefName: 'dependencyOnly', + allowedValues: { + strings.fullCompoundDependencies, + strings.opaqueCompoundDependencies, + }, + transform: (node) => node.value == strings.opaqueCompoundDependencies + ? CompoundDependencies.opaque + : CompoundDependencies.full, + ), + defaultValue: (node) => CompoundDependencies.full, + ); + } + + MapConfigSpec _mappedTypeObject() { + return MapConfigSpec( + schemaDefName: 'mappedTypes', + keyValueConfigSpecs: [ + ( + keyRegexp: '.*', + valueConfigSpec: HeterogeneousMapConfigSpec(entries: [ + HeterogeneousMapEntry( + key: strings.lib, valueConfigSpec: StringConfigSpec()), + HeterogeneousMapEntry( + key: strings.cType, valueConfigSpec: StringConfigSpec()), + HeterogeneousMapEntry( + key: strings.dartType, valueConfigSpec: StringConfigSpec()), + ]), + ) + ], + transform: (node) => typeMapExtractor(node.value), + ); + } + + MapConfigSpec _objcModuleObject() { + return MapConfigSpec( + schemaDefName: 'objcModule', + keyValueConfigSpecs: [ + (keyRegexp: '.*', valueConfigSpec: StringConfigSpec()), + ], + transform: (node) => ObjCModules(node.value.cast()), + ); + } +} diff --git a/pkgs/ffigenpad/lib/src/ffigen.dart b/pkgs/ffigenpad/lib/src/ffigen.dart new file mode 100644 index 0000000000..ef39c360f8 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/ffigen.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:logging/logging.dart'; + +import 'config_provider.dart' show Config; +import 'header_parser.dart' show parse; + +final _logger = Logger('ffigen.ffigen'); + +class FfiGen { + FfiGen({Level logLevel = Level.INFO}) { + Logger.root.level = logLevel; + Logger.root.onRecord.listen((record) { + final levelStr = '[${record.level.name}]'.padRight(9); + _printLog('$levelStr: ${record.message}', record.level); + }); + } + + /// Runs the entire generation pipeline for the given config. + void run(Config config) { + // Parse the bindings according to config object provided. + final library = parse(config); + + // Generate files for the parsed bindings. + final gen = File(config.output.toFilePath()); + library.generateFile(gen, format: config.formatOutput); + _logger.info( + _successPen('Finished, Bindings generated in ${gen.absolute.path}')); + + final objCGen = File(config.outputObjC.toFilePath()); + if (library.generateObjCFile(objCGen)) { + _logger.info(_successPen('Finished, Objective C bindings generated ' + 'in ${objCGen.absolute.path}')); + } + + if (config.symbolFile != null) { + final symbolFileGen = File(config.symbolFile!.output.toFilePath()); + library.generateSymbolOutputFile( + symbolFileGen, config.symbolFile!.importPath.toString()); + _logger.info(_successPen('Finished, Symbol Output generated in ' + '${symbolFileGen.absolute.path}')); + } + } + + static void _printLog(String log, Level level) { + // Prints text in red for Severe logs only. + if (level < Level.SEVERE) { + print(log); + } else { + print(_errorPen(log)); + } + } + + // TODO: look into better color formatting + static String _successPen(String str) => '${"SUCCESS/"}$str${"/SUCCESS"}'; + static String _errorPen(String str) => '${"ERROR/"}$str${"/ERROR"}'; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser.dart b/pkgs/ffigenpad/lib/src/header_parser.dart new file mode 100644 index 0000000000..a64b135e45 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser.dart @@ -0,0 +1,10 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Generates a Library (code_generator) +/// +/// Parses the header files AST using clang_bindings. +library; + +export 'header_parser/parser.dart' show parse; diff --git a/pkgs/ffigenpad/lib/src/header_parser/calloc.dart b/pkgs/ffigenpad/lib/src/header_parser/calloc.dart new file mode 100644 index 0000000000..61a99f28d6 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/calloc.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Provides an allocator for malloc and free functions exported by emscripten. +library; + +import 'dart:ffi' as ffi; +import 'dart:js_interop'; + +@ffi.Native Function(ffi.Int)>(symbol: 'malloc') +external ffi.Pointer _wasmAllocate( + int size, +); + +@ffi.Native)>(symbol: 'free') +external void _wasmDeallocate( + ffi.Pointer ptr, +); + +class _WasmAllocator implements ffi.Allocator { + @override + ffi.Pointer allocate( + int byteCount, { + int? alignment, + }) { + return _wasmAllocate(byteCount).cast(); + } + + @override + void free(ffi.Pointer pointer) { + _wasmDeallocate(pointer.cast()); + } +} + +final calloc = _WasmAllocator(); + +@JS() +external int addFunction(JSExportedDartFunction fp, String signature); + +@JS() +external void removeFunction(int index); diff --git a/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_bindings.dart b/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_bindings.dart new file mode 100644 index 0000000000..8bb0918a8e --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_bindings.dart @@ -0,0 +1,1860 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM +// Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// ignore_for_file: camel_case_types, non_constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint +@ffi.DefaultAsset('libclang') +library; + +import 'dart:ffi' as ffi; + +/// Destroy a diagnostic. +@ffi.Native() +external void clang_disposeDiagnostic( + CXDiagnostic Diagnostic, +); + +/// Determine the severity of the given diagnostic. +@ffi.Native() +external int clang_getDiagnosticSeverity( + CXDiagnostic arg0, +); + +/// Provides a shared context for creating translation units. +/// +/// It provides two options: +/// +/// - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" +/// declarations (when loading any new translation units). A "local" declaration +/// is one that belongs in the translation unit itself and not in a precompiled +/// header that was used by the translation unit. If zero, all declarations +/// will be enumerated. +/// +/// Here is an example: +/// +/// \code +/// // excludeDeclsFromPCH = 1, displayDiagnostics=1 +/// Idx = clang_createIndex(1, 1); +/// +/// // IndexTest.pch was produced with the following command: +/// // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch" +/// TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); +/// +/// // This will load all the symbols from 'IndexTest.pch' +/// clang_visitChildren(clang_getTranslationUnitCursor(TU), +/// TranslationUnitVisitor, 0); +/// clang_disposeTranslationUnit(TU); +/// +/// // This will load all the symbols from 'IndexTest.c', excluding symbols +/// // from 'IndexTest.pch'. +/// char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" }; +/// TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args, +/// 0, 0); +/// clang_visitChildren(clang_getTranslationUnitCursor(TU), +/// TranslationUnitVisitor, 0); +/// clang_disposeTranslationUnit(TU); +/// \endcode +/// +/// This process of creating the 'pch', loading it separately, and using it (via +/// -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks +/// (which gives the indexer the same performance benefit as the compiler). +@ffi.Native() +external CXIndex clang_createIndex( + int excludeDeclarationsFromPCH, + int displayDiagnostics, +); + +/// Destroy the given index. +/// +/// The index must not be destroyed until all of the translation units created +/// within that index have been destroyed. +@ffi.Native() +external void clang_disposeIndex( + CXIndex index, +); + +/// Determine the number of diagnostics produced for the given +/// translation unit. +@ffi.Native() +external int clang_getNumDiagnostics( + CXTranslationUnit Unit, +); + +/// Retrieve a diagnostic associated with the given translation unit. +/// +/// \param Unit the translation unit to query. +/// \param Index the zero-based diagnostic number to retrieve. +/// +/// \returns the requested diagnostic. This diagnostic must be freed +/// via a call to \c clang_disposeDiagnostic(). +@ffi.Native() +external CXDiagnostic clang_getDiagnostic( + CXTranslationUnit Unit, + int Index, +); + +/// Same as \c clang_parseTranslationUnit2, but returns +/// the \c CXTranslationUnit instead of an error code. In case of an error this +/// routine returns a \c NULL \c CXTranslationUnit, without further detailed +/// error codes. +@ffi.Native< + CXTranslationUnit Function( + CXIndex, + ffi.Pointer, + ffi.Pointer>, + ffi.Int32, + ffi.Pointer, + ffi.Uint32, + ffi.Uint32)>() +external CXTranslationUnit clang_parseTranslationUnit( + CXIndex CIdx, + ffi.Pointer source_filename, + ffi.Pointer> command_line_args, + int num_command_line_args, + ffi.Pointer unsaved_files, + int num_unsaved_files, + int options, +); + +/// Destroy the specified CXTranslationUnit object. +@ffi.Native() +external void clang_disposeTranslationUnit( + CXTranslationUnit arg0, +); + +/// Returns the kind of the evaluated result. +@ffi.Native() +external int clang_EvalResult_getKind( + CXEvalResult E, +); + +/// Returns the evaluation result as a long long integer if the +/// kind is Int. This prevents overflows that may happen if the result is +/// returned with clang_EvalResult_getAsInt. +@ffi.Native() +external int clang_EvalResult_getAsLongLong( + CXEvalResult E, +); + +/// Returns the evaluation result as double if the +/// kind is double. +@ffi.Native() +external double clang_EvalResult_getAsDouble( + CXEvalResult E, +); + +/// Returns the evaluation result as a constant string if the +/// kind is other than Int or float. User must not free this pointer, +/// instead call clang_EvalResult_dispose on the CXEvalResult returned +/// by clang_Cursor_Evaluate. +@ffi.Native Function(CXEvalResult)>() +external ffi.Pointer clang_EvalResult_getAsStr( + CXEvalResult E, +); + +/// Disposes the created Eval memory. +@ffi.Native() +external void clang_EvalResult_dispose( + CXEvalResult E, +); + +@ffi.Native Function()>() +external ffi.Pointer clang_getClangVersion_wrap(); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCString_wrap( + ffi.Pointer string, +); + +@ffi.Native)>() +external void clang_disposeString_wrap( + ffi.Pointer string, +); + +@ffi.Native)>() +external int clang_getCursorKind_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCursorDefinition_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Uint32)>() +external ffi.Pointer clang_getCursorKindSpelling_wrap( + int kind, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCursorType_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getTypeSpelling_wrap( + ffi.Pointer type, +); + +@ffi.Native Function(ffi.Uint32)>() +external ffi.Pointer clang_getTypeKindSpelling_wrap( + int typeKind, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getResultType_wrap( + ffi.Pointer functionType, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getPointeeType_wrap( + ffi.Pointer pointerType, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCanonicalType_wrap( + ffi.Pointer typerefType, +); + +@ffi.Native)>() +external int getCXTypeKind( + ffi.Pointer cxtype, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Type_getModifiedType_wrap( + ffi.Pointer type, +); + +@ffi.Native)>() +external int clang_Type_getNullability_wrap( + ffi.Pointer type, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Type_getNamedType_wrap( + ffi.Pointer elaboratedType, +); + +@ffi.Native)>() +external int clang_Type_getAlignOf_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getTypeDeclaration_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getTypedefName_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getTypedefDeclUnderlyingType_wrap( + ffi.Pointer cxcursor, +); + +/// The name of parameter, struct, typedef. +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCursorSpelling_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCursorUSR_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(CXTranslationUnit)>() +external ffi.Pointer clang_getTranslationUnitCursor_wrap( + CXTranslationUnit tu, +); + +@ffi.Native Function(CXDiagnostic, ffi.Int32)>() +external ffi.Pointer clang_formatDiagnostic_wrap( + CXDiagnostic diag, + int opts, +); + +/// Visitor is a function pointer with parameters having pointers to cxcursor +/// instead of cxcursor by default. +@ffi.Native, ffi.UintPtr)>() +external int clang_visitChildren_wrap( + ffi.Pointer parent, + int _modifiedVisitor, +); + +@ffi.Native)>() +external int clang_getNumArgTypes_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native Function(ffi.Pointer, ffi.Uint32)>() +external ffi.Pointer clang_getArgType_wrap( + ffi.Pointer cxtype, + int i, +); + +@ffi.Native)>() +external int clang_getEnumConstantDeclValue_wrap( + ffi.Pointer cursor, +); + +/// Returns non-zero if the ranges are the same, zero if they differ. +@ffi.Native< + ffi.Uint32 Function( + ffi.Pointer, ffi.Pointer)>() +external int clang_equalRanges_wrap( + ffi.Pointer c1, + ffi.Pointer c2, +); + +@ffi.Native)>() +external CXEvalResult clang_Cursor_Evaluate_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Pointer, ffi.Uint32)>() +external ffi.Pointer clang_Cursor_getArgument_wrap( + ffi.Pointer cursor, + int i, +); + +@ffi.Native)>() +external int clang_Cursor_getNumArguments_wrap( + ffi.Pointer cursor, +); + +/// Returns the comment range. +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Cursor_getCommentRange_wrap( + ffi.Pointer cursor, +); + +/// Returns the raw comment. +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Cursor_getRawCommentText_wrap( + ffi.Pointer cursor, +); + +/// Returns the first paragraph of doxygen doc comment. +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Cursor_getBriefCommentText_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_Cursor_getStorageClass_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_getFieldDeclBitWidth_wrap( + ffi.Pointer C, +); + +@ffi.Native)>() +external int clang_Cursor_hasAttrs_wrap( + ffi.Pointer C, +); + +@ffi.Native)>() +external int clang_Cursor_isFunctionInlined_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_Cursor_isAnonymous_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_Cursor_isAnonymousRecordDecl_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_Cursor_isNull_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_Cursor_isMacroFunctionLike_wrap( + ffi.Pointer cursor, +); + +@ffi.Native)>() +external int clang_Cursor_isMacroBuiltin_wrap( + ffi.Pointer cursor, +); + +@ffi.Native, ffi.Uint32)>() +external int clang_Cursor_getObjCPropertyAttributes_wrap( + ffi.Pointer cursor, + int reserved, +); + +@ffi.Native)>() +external int clang_Cursor_isObjCOptional_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Cursor_getObjCPropertyGetterName_wrap( + ffi.Pointer C, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_Cursor_getObjCPropertySetterName_wrap( + ffi.Pointer C, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCursorResultType_wrap( + ffi.Pointer C, +); + +@ffi.Native)>() +external int clang_isFunctionTypeVariadic_wrap( + ffi.Pointer type, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getCursorLocation_wrap( + ffi.Pointer cursor, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getEnumDeclIntegerType_wrap( + ffi.Pointer cursor, +); + +@ffi.Native< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>() +external void clang_getFileLocation_wrap( + ffi.Pointer location, + ffi.Pointer file, + ffi.Pointer line, + ffi.Pointer column, + ffi.Pointer offset, +); + +@ffi.Native Function(CXFile)>() +external ffi.Pointer clang_getFileName_wrap( + CXFile SFile, +); + +@ffi.Native)>() +external int clang_getNumElements_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native Function(ffi.Pointer)>() +external ffi.Pointer clang_getArrayElementType_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native)>() +external int clang_isConstQualifiedType_wrap( + ffi.Pointer cxtype, +); + +@ffi.Native)>() +external int clang_Location_isInSystemHeader_wrap( + ffi.Pointer location, +); + +/// Describes the severity of a particular diagnostic. +abstract class CXDiagnosticSeverity { + /// A diagnostic that has been suppressed, e.g., by a command-line + /// option. + static const CXDiagnostic_Ignored = 0; + + /// This diagnostic is a note that should be attached to the + /// previous (non-note) diagnostic. + static const CXDiagnostic_Note = 1; + + /// This diagnostic indicates suspicious code that may not be + /// wrong. + static const CXDiagnostic_Warning = 2; + + /// This diagnostic indicates that the code is ill-formed. + static const CXDiagnostic_Error = 3; + + /// This diagnostic indicates that the code is ill-formed such + /// that future parser recovery is unlikely to produce useful + /// results. + static const CXDiagnostic_Fatal = 4; +} + +/// A single diagnostic, containing the diagnostic's severity, +/// location, text, source ranges, and fix-it hints. +typedef CXDiagnostic = ffi.Pointer; + +/// Options to control the display of diagnostics. +/// +/// The values in this enum are meant to be combined to customize the +/// behavior of \c clang_formatDiagnostic(). +abstract class CXDiagnosticDisplayOptions { + /// Display the source-location information where the + /// diagnostic was located. + /// + /// When set, diagnostics will be prefixed by the file, line, and + /// (optionally) column to which the diagnostic refers. For example, + /// + /// \code + /// test.c:28: warning: extra tokens at end of #endif directive + /// \endcode + /// + /// This option corresponds to the clang flag \c -fshow-source-location. + static const CXDiagnostic_DisplaySourceLocation = 1; + + /// If displaying the source-location information of the + /// diagnostic, also include the column number. + /// + /// This option corresponds to the clang flag \c -fshow-column. + static const CXDiagnostic_DisplayColumn = 2; + + /// If displaying the source-location information of the + /// diagnostic, also include information about source ranges in a + /// machine-parsable format. + /// + /// This option corresponds to the clang flag + /// \c -fdiagnostics-print-source-range-info. + static const CXDiagnostic_DisplaySourceRanges = 4; + + /// Display the option name associated with this diagnostic, if any. + /// + /// The option name displayed (e.g., -Wconversion) will be placed in brackets + /// after the diagnostic text. This option corresponds to the clang flag + /// \c -fdiagnostics-show-option. + static const CXDiagnostic_DisplayOption = 8; + + /// Display the category number associated with this diagnostic, if any. + /// + /// The category number is displayed within brackets after the diagnostic text. + /// This option corresponds to the clang flag + /// \c -fdiagnostics-show-category=id. + static const CXDiagnostic_DisplayCategoryId = 16; + + /// Display the category name associated with this diagnostic, if any. + /// + /// The category name is displayed within brackets after the diagnostic text. + /// This option corresponds to the clang flag + /// \c -fdiagnostics-show-category=name. + static const CXDiagnostic_DisplayCategoryName = 32; +} + +/// An "index" that consists of a set of translation units that would +/// typically be linked together into an executable or library. +typedef CXIndex = ffi.Pointer; + +/// A single translation unit, which resides in an index. +typedef CXTranslationUnit = ffi.Pointer; + +final class CXTranslationUnitImpl extends ffi.Opaque {} + +/// Flags that control the creation of translation units. +/// +/// The enumerators in this enumeration type are meant to be bitwise +/// ORed together to specify which options should be used when +/// constructing the translation unit. +abstract class CXTranslationUnit_Flags { + /// Used to indicate that no special translation-unit options are + /// needed. + static const CXTranslationUnit_None = 0; + + /// Used to indicate that the parser should construct a "detailed" + /// preprocessing record, including all macro definitions and instantiations. + /// + /// Constructing a detailed preprocessing record requires more memory + /// and time to parse, since the information contained in the record + /// is usually not retained. However, it can be useful for + /// applications that require more detailed information about the + /// behavior of the preprocessor. + static const CXTranslationUnit_DetailedPreprocessingRecord = 1; + + /// Used to indicate that the translation unit is incomplete. + /// + /// When a translation unit is considered "incomplete", semantic + /// analysis that is typically performed at the end of the + /// translation unit will be suppressed. For example, this suppresses + /// the completion of tentative declarations in C and of + /// instantiation of implicitly-instantiation function templates in + /// C++. This option is typically used when parsing a header with the + /// intent of producing a precompiled header. + static const CXTranslationUnit_Incomplete = 2; + + /// Used to indicate that the translation unit should be built with an + /// implicit precompiled header for the preamble. + /// + /// An implicit precompiled header is used as an optimization when a + /// particular translation unit is likely to be reparsed many times + /// when the sources aren't changing that often. In this case, an + /// implicit precompiled header will be built containing all of the + /// initial includes at the top of the main file (what we refer to as + /// the "preamble" of the file). In subsequent parses, if the + /// preamble or the files in it have not changed, \c + /// clang_reparseTranslationUnit() will re-use the implicit + /// precompiled header to improve parsing performance. + static const CXTranslationUnit_PrecompiledPreamble = 4; + + /// Used to indicate that the translation unit should cache some + /// code-completion results with each reparse of the source file. + /// + /// Caching of code-completion results is a performance optimization that + /// introduces some overhead to reparsing but improves the performance of + /// code-completion operations. + static const CXTranslationUnit_CacheCompletionResults = 8; + + /// Used to indicate that the translation unit will be serialized with + /// \c clang_saveTranslationUnit. + /// + /// This option is typically used when parsing a header with the intent of + /// producing a precompiled header. + static const CXTranslationUnit_ForSerialization = 16; + + /// DEPRECATED: Enabled chained precompiled preambles in C++. + /// + /// Note: this is a *temporary* option that is available only while + /// we are testing C++ precompiled preamble support. It is deprecated. + static const CXTranslationUnit_CXXChainedPCH = 32; + + /// Used to indicate that function/method bodies should be skipped while + /// parsing. + /// + /// This option can be used to search for declarations/definitions while + /// ignoring the usages. + static const CXTranslationUnit_SkipFunctionBodies = 64; + + /// Used to indicate that brief documentation comments should be + /// included into the set of code completions returned from this translation + /// unit. + static const CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 128; + + /// Used to indicate that the precompiled preamble should be created on + /// the first parse. Otherwise it will be created on the first reparse. This + /// trades runtime on the first parse (serializing the preamble takes time) for + /// reduced runtime on the second parse (can now reuse the preamble). + static const CXTranslationUnit_CreatePreambleOnFirstParse = 256; + + /// Do not stop processing when fatal errors are encountered. + /// + /// When fatal errors are encountered while parsing a translation unit, + /// semantic analysis is typically stopped early when compiling code. A common + /// source for fatal errors are unresolvable include files. For the + /// purposes of an IDE, this is undesirable behavior and as much information + /// as possible should be reported. Use this flag to enable this behavior. + static const CXTranslationUnit_KeepGoing = 512; + + /// Sets the preprocessor in a mode for parsing a single file only. + static const CXTranslationUnit_SingleFileParse = 1024; + + /// Used in combination with CXTranslationUnit_SkipFunctionBodies to + /// constrain the skipping of function bodies to the preamble. + /// + /// The function bodies of the main file are not skipped. + static const CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 2048; + + /// Used to indicate that attributed types should be included in CXType. + static const CXTranslationUnit_IncludeAttributedTypes = 4096; + + /// Used to indicate that implicit attributes should be visited. + static const CXTranslationUnit_VisitImplicitAttributes = 8192; + + /// Used to indicate that non-errors from included files should be ignored. + /// + /// If set, clang_getDiagnosticSetFromTU() will not report e.g. warnings from + /// included files anymore. This speeds up clang_getDiagnosticSetFromTU() for + /// the case where these warnings are not of interest, as for an IDE for + /// example, which typically shows only the diagnostics in the main file. + static const CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles = 16384; + + /// Tells the preprocessor not to skip excluded conditional blocks. + static const CXTranslationUnit_RetainExcludedConditionalBlocks = 32768; +} + +/// Provides the contents of a file that has not yet been saved to disk. +/// +/// Each CXUnsavedFile instance provides the name of a file on the +/// system along with the current contents of that file that have not +/// yet been saved to disk. +final class CXUnsavedFile extends ffi.Opaque {} + +/// Describes the kind of entity that a cursor refers to. +abstract class CXCursorKind { + /// A declaration whose specific kind is not exposed via this + /// interface. + /// + /// Unexposed declarations have the same operations as any other kind + /// of declaration; one can extract their location information, + /// spelling, find their definitions, etc. However, the specific kind + /// of the declaration is not reported. + static const CXCursor_UnexposedDecl = 1; + + /// A C or C++ struct. + static const CXCursor_StructDecl = 2; + + /// A C or C++ union. + static const CXCursor_UnionDecl = 3; + + /// A C++ class. + static const CXCursor_ClassDecl = 4; + + /// An enumeration. + static const CXCursor_EnumDecl = 5; + + /// A field (in C) or non-static data member (in C++) in a + /// struct, union, or C++ class. + static const CXCursor_FieldDecl = 6; + + /// An enumerator constant. + static const CXCursor_EnumConstantDecl = 7; + + /// A function. + static const CXCursor_FunctionDecl = 8; + + /// A variable. + static const CXCursor_VarDecl = 9; + + /// A function or method parameter. + static const CXCursor_ParmDecl = 10; + + /// An Objective-C \@interface. + static const CXCursor_ObjCInterfaceDecl = 11; + + /// An Objective-C \@interface for a category. + static const CXCursor_ObjCCategoryDecl = 12; + + /// An Objective-C \@protocol declaration. + static const CXCursor_ObjCProtocolDecl = 13; + + /// An Objective-C \@property declaration. + static const CXCursor_ObjCPropertyDecl = 14; + + /// An Objective-C instance variable. + static const CXCursor_ObjCIvarDecl = 15; + + /// An Objective-C instance method. + static const CXCursor_ObjCInstanceMethodDecl = 16; + + /// An Objective-C class method. + static const CXCursor_ObjCClassMethodDecl = 17; + + /// An Objective-C \@implementation. + static const CXCursor_ObjCImplementationDecl = 18; + + /// An Objective-C \@implementation for a category. + static const CXCursor_ObjCCategoryImplDecl = 19; + + /// A typedef. + static const CXCursor_TypedefDecl = 20; + + /// A C++ class method. + static const CXCursor_CXXMethod = 21; + + /// A C++ namespace. + static const CXCursor_Namespace = 22; + + /// A linkage specification, e.g. 'extern "C"'. + static const CXCursor_LinkageSpec = 23; + + /// A C++ constructor. + static const CXCursor_Constructor = 24; + + /// A C++ destructor. + static const CXCursor_Destructor = 25; + + /// A C++ conversion function. + static const CXCursor_ConversionFunction = 26; + + /// A C++ template type parameter. + static const CXCursor_TemplateTypeParameter = 27; + + /// A C++ non-type template parameter. + static const CXCursor_NonTypeTemplateParameter = 28; + + /// A C++ template template parameter. + static const CXCursor_TemplateTemplateParameter = 29; + + /// A C++ function template. + static const CXCursor_FunctionTemplate = 30; + + /// A C++ class template. + static const CXCursor_ClassTemplate = 31; + + /// A C++ class template partial specialization. + static const CXCursor_ClassTemplatePartialSpecialization = 32; + + /// A C++ namespace alias declaration. + static const CXCursor_NamespaceAlias = 33; + + /// A C++ using directive. + static const CXCursor_UsingDirective = 34; + + /// A C++ using declaration. + static const CXCursor_UsingDeclaration = 35; + + /// A C++ alias declaration + static const CXCursor_TypeAliasDecl = 36; + + /// An Objective-C \@synthesize definition. + static const CXCursor_ObjCSynthesizeDecl = 37; + + /// An Objective-C \@dynamic definition. + static const CXCursor_ObjCDynamicDecl = 38; + + /// An access specifier. + static const CXCursor_CXXAccessSpecifier = 39; + static const CXCursor_FirstDecl = 1; + static const CXCursor_LastDecl = 39; + static const CXCursor_FirstRef = 40; + static const CXCursor_ObjCSuperClassRef = 40; + static const CXCursor_ObjCProtocolRef = 41; + static const CXCursor_ObjCClassRef = 42; + + /// A reference to a type declaration. + /// + /// A type reference occurs anywhere where a type is named but not + /// declared. For example, given: + /// + /// \code + /// typedef unsigned size_type; + /// size_type size; + /// \endcode + /// + /// The typedef is a declaration of size_type (CXCursor_TypedefDecl), + /// while the type of the variable "size" is referenced. The cursor + /// referenced by the type of size is the typedef for size_type. + static const CXCursor_TypeRef = 43; + static const CXCursor_CXXBaseSpecifier = 44; + + /// A reference to a class template, function template, template + /// template parameter, or class template partial specialization. + static const CXCursor_TemplateRef = 45; + + /// A reference to a namespace or namespace alias. + static const CXCursor_NamespaceRef = 46; + + /// A reference to a member of a struct, union, or class that occurs in + /// some non-expression context, e.g., a designated initializer. + static const CXCursor_MemberRef = 47; + + /// A reference to a labeled statement. + /// + /// This cursor kind is used to describe the jump to "start_over" in the + /// goto statement in the following example: + /// + /// \code + /// start_over: + /// ++counter; + /// + /// goto start_over; + /// \endcode + /// + /// A label reference cursor refers to a label statement. + static const CXCursor_LabelRef = 48; + + /// A reference to a set of overloaded functions or function templates + /// that has not yet been resolved to a specific function or function template. + /// + /// An overloaded declaration reference cursor occurs in C++ templates where + /// a dependent name refers to a function. For example: + /// + /// \code + /// template void swap(T&, T&); + /// + /// struct X { ... }; + /// void swap(X&, X&); + /// + /// template + /// void reverse(T* first, T* last) { + /// while (first < last - 1) { + /// swap(*first, *--last); + /// ++first; + /// } + /// } + /// + /// struct Y { }; + /// void swap(Y&, Y&); + /// \endcode + /// + /// Here, the identifier "swap" is associated with an overloaded declaration + /// reference. In the template definition, "swap" refers to either of the two + /// "swap" functions declared above, so both results will be available. At + /// instantiation time, "swap" may also refer to other functions found via + /// argument-dependent lookup (e.g., the "swap" function at the end of the + /// example). + /// + /// The functions \c clang_getNumOverloadedDecls() and + /// \c clang_getOverloadedDecl() can be used to retrieve the definitions + /// referenced by this cursor. + static const CXCursor_OverloadedDeclRef = 49; + + /// A reference to a variable that occurs in some non-expression + /// context, e.g., a C++ lambda capture list. + static const CXCursor_VariableRef = 50; + static const CXCursor_LastRef = 50; + static const CXCursor_FirstInvalid = 70; + static const CXCursor_InvalidFile = 70; + static const CXCursor_NoDeclFound = 71; + static const CXCursor_NotImplemented = 72; + static const CXCursor_InvalidCode = 73; + static const CXCursor_LastInvalid = 73; + static const CXCursor_FirstExpr = 100; + + /// An expression whose specific kind is not exposed via this + /// interface. + /// + /// Unexposed expressions have the same operations as any other kind + /// of expression; one can extract their location information, + /// spelling, children, etc. However, the specific kind of the + /// expression is not reported. + static const CXCursor_UnexposedExpr = 100; + + /// An expression that refers to some value declaration, such + /// as a function, variable, or enumerator. + static const CXCursor_DeclRefExpr = 101; + + /// An expression that refers to a member of a struct, union, + /// class, Objective-C class, etc. + static const CXCursor_MemberRefExpr = 102; + + /// An expression that calls a function. + static const CXCursor_CallExpr = 103; + + /// An expression that sends a message to an Objective-C + /// object or class. + static const CXCursor_ObjCMessageExpr = 104; + + /// An expression that represents a block literal. + static const CXCursor_BlockExpr = 105; + + /// An integer literal. + static const CXCursor_IntegerLiteral = 106; + + /// A floating point number literal. + static const CXCursor_FloatingLiteral = 107; + + /// An imaginary number literal. + static const CXCursor_ImaginaryLiteral = 108; + + /// A string literal. + static const CXCursor_StringLiteral = 109; + + /// A character literal. + static const CXCursor_CharacterLiteral = 110; + + /// A parenthesized expression, e.g. "(1)". + /// + /// This AST node is only formed if full location information is requested. + static const CXCursor_ParenExpr = 111; + + /// This represents the unary-expression's (except sizeof and + /// alignof). + static const CXCursor_UnaryOperator = 112; + + /// [C99 6.5.2.1] Array Subscripting. + static const CXCursor_ArraySubscriptExpr = 113; + + /// A builtin binary operation expression such as "x + y" or + /// "x <= y". + static const CXCursor_BinaryOperator = 114; + + /// Compound assignment such as "+=". + static const CXCursor_CompoundAssignOperator = 115; + + /// The ?: ternary operator. + static const CXCursor_ConditionalOperator = 116; + + /// An explicit cast in C (C99 6.5.4) or a C-style cast in C++ + /// (C++ [expr.cast]), which uses the syntax (Type)expr. + /// + /// For example: (int)f. + static const CXCursor_CStyleCastExpr = 117; + + /// [C99 6.5.2.5] + static const CXCursor_CompoundLiteralExpr = 118; + + /// Describes an C or C++ initializer list. + static const CXCursor_InitListExpr = 119; + + /// The GNU address of label extension, representing &&label. + static const CXCursor_AddrLabelExpr = 120; + + /// This is the GNU Statement Expression extension: ({int X=4; X;}) + static const CXCursor_StmtExpr = 121; + + /// Represents a C11 generic selection. + static const CXCursor_GenericSelectionExpr = 122; + + /// Implements the GNU __null extension, which is a name for a null + /// pointer constant that has integral type (e.g., int or long) and is the same + /// size and alignment as a pointer. + /// + /// The __null extension is typically only used by system headers, which define + /// NULL as __null in C++ rather than using 0 (which is an integer that may not + /// match the size of a pointer). + static const CXCursor_GNUNullExpr = 123; + + /// C++'s static_cast<> expression. + static const CXCursor_CXXStaticCastExpr = 124; + + /// C++'s dynamic_cast<> expression. + static const CXCursor_CXXDynamicCastExpr = 125; + + /// C++'s reinterpret_cast<> expression. + static const CXCursor_CXXReinterpretCastExpr = 126; + + /// C++'s const_cast<> expression. + static const CXCursor_CXXConstCastExpr = 127; + + /// Represents an explicit C++ type conversion that uses "functional" + /// notion (C++ [expr.type.conv]). + /// + /// Example: + /// \code + /// x = int(0.5); + /// \endcode + static const CXCursor_CXXFunctionalCastExpr = 128; + + /// A C++ typeid expression (C++ [expr.typeid]). + static const CXCursor_CXXTypeidExpr = 129; + + /// [C++ 2.13.5] C++ Boolean Literal. + static const CXCursor_CXXBoolLiteralExpr = 130; + + /// [C++0x 2.14.7] C++ Pointer Literal. + static const CXCursor_CXXNullPtrLiteralExpr = 131; + + /// Represents the "this" expression in C++ + static const CXCursor_CXXThisExpr = 132; + + /// [C++ 15] C++ Throw Expression. + /// + /// This handles 'throw' and 'throw' assignment-expression. When + /// assignment-expression isn't present, Op will be null. + static const CXCursor_CXXThrowExpr = 133; + + /// A new expression for memory allocation and constructor calls, e.g: + /// "new CXXNewExpr(foo)". + static const CXCursor_CXXNewExpr = 134; + + /// A delete expression for memory deallocation and destructor calls, + /// e.g. "delete[] pArray". + static const CXCursor_CXXDeleteExpr = 135; + + /// A unary expression. (noexcept, sizeof, or other traits) + static const CXCursor_UnaryExpr = 136; + + /// An Objective-C string literal i.e. @"foo". + static const CXCursor_ObjCStringLiteral = 137; + + /// An Objective-C \@encode expression. + static const CXCursor_ObjCEncodeExpr = 138; + + /// An Objective-C \@selector expression. + static const CXCursor_ObjCSelectorExpr = 139; + + /// An Objective-C \@protocol expression. + static const CXCursor_ObjCProtocolExpr = 140; + + /// An Objective-C "bridged" cast expression, which casts between + /// Objective-C pointers and C pointers, transferring ownership in the process. + /// + /// \code + /// NSString *str = (__bridge_transfer NSString *)CFCreateString(); + /// \endcode + static const CXCursor_ObjCBridgedCastExpr = 141; + + /// Represents a C++0x pack expansion that produces a sequence of + /// expressions. + /// + /// A pack expansion expression contains a pattern (which itself is an + /// expression) followed by an ellipsis. For example: + /// + /// \code + /// template + /// void forward(F f, Types &&...args) { + /// f(static_cast(args)...); + /// } + /// \endcode + static const CXCursor_PackExpansionExpr = 142; + + /// Represents an expression that computes the length of a parameter + /// pack. + /// + /// \code + /// template + /// struct count { + /// static const unsigned value = sizeof...(Types); + /// }; + /// \endcode + static const CXCursor_SizeOfPackExpr = 143; + static const CXCursor_LambdaExpr = 144; + + /// Objective-c Boolean Literal. + static const CXCursor_ObjCBoolLiteralExpr = 145; + + /// Represents the "self" expression in an Objective-C method. + static const CXCursor_ObjCSelfExpr = 146; + + /// OpenMP 5.0 [2.1.5, Array Section]. + static const CXCursor_OMPArraySectionExpr = 147; + + /// Represents an @available(...) check. + static const CXCursor_ObjCAvailabilityCheckExpr = 148; + + /// Fixed point literal + static const CXCursor_FixedPointLiteral = 149; + + /// OpenMP 5.0 [2.1.4, Array Shaping]. + static const CXCursor_OMPArrayShapingExpr = 150; + + /// OpenMP 5.0 [2.1.6 Iterators] + static const CXCursor_OMPIteratorExpr = 151; + + /// OpenCL's addrspace_cast<> expression. + static const CXCursor_CXXAddrspaceCastExpr = 152; + + /// Expression that references a C++20 concept. + static const CXCursor_ConceptSpecializationExpr = 153; + + /// Expression that references a C++20 concept. + static const CXCursor_RequiresExpr = 154; + + /// Expression that references a C++20 parenthesized list aggregate + /// initializer. + static const CXCursor_CXXParenListInitExpr = 155; + static const CXCursor_LastExpr = 155; + static const CXCursor_FirstStmt = 200; + + /// A statement whose specific kind is not exposed via this + /// interface. + /// + /// Unexposed statements have the same operations as any other kind of + /// statement; one can extract their location information, spelling, + /// children, etc. However, the specific kind of the statement is not + /// reported. + static const CXCursor_UnexposedStmt = 200; + + /// A labelled statement in a function. + /// + /// This cursor kind is used to describe the "start_over:" label statement in + /// the following example: + /// + /// \code + /// start_over: + /// ++counter; + /// \endcode + static const CXCursor_LabelStmt = 201; + + /// A group of statements like { stmt stmt }. + /// + /// This cursor kind is used to describe compound statements, e.g. function + /// bodies. + static const CXCursor_CompoundStmt = 202; + + /// A case statement. + static const CXCursor_CaseStmt = 203; + + /// A default statement. + static const CXCursor_DefaultStmt = 204; + + /// An if statement + static const CXCursor_IfStmt = 205; + + /// A switch statement. + static const CXCursor_SwitchStmt = 206; + + /// A while statement. + static const CXCursor_WhileStmt = 207; + + /// A do statement. + static const CXCursor_DoStmt = 208; + + /// A for statement. + static const CXCursor_ForStmt = 209; + + /// A goto statement. + static const CXCursor_GotoStmt = 210; + + /// An indirect goto statement. + static const CXCursor_IndirectGotoStmt = 211; + + /// A continue statement. + static const CXCursor_ContinueStmt = 212; + + /// A break statement. + static const CXCursor_BreakStmt = 213; + + /// A return statement. + static const CXCursor_ReturnStmt = 214; + + /// A GCC inline assembly statement extension. + static const CXCursor_GCCAsmStmt = 215; + static const CXCursor_AsmStmt = 215; + + /// Objective-C's overall \@try-\@catch-\@finally statement. + static const CXCursor_ObjCAtTryStmt = 216; + + /// Objective-C's \@catch statement. + static const CXCursor_ObjCAtCatchStmt = 217; + + /// Objective-C's \@finally statement. + static const CXCursor_ObjCAtFinallyStmt = 218; + + /// Objective-C's \@throw statement. + static const CXCursor_ObjCAtThrowStmt = 219; + + /// Objective-C's \@synchronized statement. + static const CXCursor_ObjCAtSynchronizedStmt = 220; + + /// Objective-C's autorelease pool statement. + static const CXCursor_ObjCAutoreleasePoolStmt = 221; + + /// Objective-C's collection statement. + static const CXCursor_ObjCForCollectionStmt = 222; + + /// C++'s catch statement. + static const CXCursor_CXXCatchStmt = 223; + + /// C++'s try statement. + static const CXCursor_CXXTryStmt = 224; + + /// C++'s for (* : *) statement. + static const CXCursor_CXXForRangeStmt = 225; + + /// Windows Structured Exception Handling's try statement. + static const CXCursor_SEHTryStmt = 226; + + /// Windows Structured Exception Handling's except statement. + static const CXCursor_SEHExceptStmt = 227; + + /// Windows Structured Exception Handling's finally statement. + static const CXCursor_SEHFinallyStmt = 228; + + /// A MS inline assembly statement extension. + static const CXCursor_MSAsmStmt = 229; + + /// The null statement ";": C99 6.8.3p3. + /// + /// This cursor kind is used to describe the null statement. + static const CXCursor_NullStmt = 230; + + /// Adaptor class for mixing declarations with statements and + /// expressions. + static const CXCursor_DeclStmt = 231; + + /// OpenMP parallel directive. + static const CXCursor_OMPParallelDirective = 232; + + /// OpenMP SIMD directive. + static const CXCursor_OMPSimdDirective = 233; + + /// OpenMP for directive. + static const CXCursor_OMPForDirective = 234; + + /// OpenMP sections directive. + static const CXCursor_OMPSectionsDirective = 235; + + /// OpenMP section directive. + static const CXCursor_OMPSectionDirective = 236; + + /// OpenMP single directive. + static const CXCursor_OMPSingleDirective = 237; + + /// OpenMP parallel for directive. + static const CXCursor_OMPParallelForDirective = 238; + + /// OpenMP parallel sections directive. + static const CXCursor_OMPParallelSectionsDirective = 239; + + /// OpenMP task directive. + static const CXCursor_OMPTaskDirective = 240; + + /// OpenMP master directive. + static const CXCursor_OMPMasterDirective = 241; + + /// OpenMP critical directive. + static const CXCursor_OMPCriticalDirective = 242; + + /// OpenMP taskyield directive. + static const CXCursor_OMPTaskyieldDirective = 243; + + /// OpenMP barrier directive. + static const CXCursor_OMPBarrierDirective = 244; + + /// OpenMP taskwait directive. + static const CXCursor_OMPTaskwaitDirective = 245; + + /// OpenMP flush directive. + static const CXCursor_OMPFlushDirective = 246; + + /// Windows Structured Exception Handling's leave statement. + static const CXCursor_SEHLeaveStmt = 247; + + /// OpenMP ordered directive. + static const CXCursor_OMPOrderedDirective = 248; + + /// OpenMP atomic directive. + static const CXCursor_OMPAtomicDirective = 249; + + /// OpenMP for SIMD directive. + static const CXCursor_OMPForSimdDirective = 250; + + /// OpenMP parallel for SIMD directive. + static const CXCursor_OMPParallelForSimdDirective = 251; + + /// OpenMP target directive. + static const CXCursor_OMPTargetDirective = 252; + + /// OpenMP teams directive. + static const CXCursor_OMPTeamsDirective = 253; + + /// OpenMP taskgroup directive. + static const CXCursor_OMPTaskgroupDirective = 254; + + /// OpenMP cancellation point directive. + static const CXCursor_OMPCancellationPointDirective = 255; + + /// OpenMP cancel directive. + static const CXCursor_OMPCancelDirective = 256; + + /// OpenMP target data directive. + static const CXCursor_OMPTargetDataDirective = 257; + + /// OpenMP taskloop directive. + static const CXCursor_OMPTaskLoopDirective = 258; + + /// OpenMP taskloop simd directive. + static const CXCursor_OMPTaskLoopSimdDirective = 259; + + /// OpenMP distribute directive. + static const CXCursor_OMPDistributeDirective = 260; + + /// OpenMP target enter data directive. + static const CXCursor_OMPTargetEnterDataDirective = 261; + + /// OpenMP target exit data directive. + static const CXCursor_OMPTargetExitDataDirective = 262; + + /// OpenMP target parallel directive. + static const CXCursor_OMPTargetParallelDirective = 263; + + /// OpenMP target parallel for directive. + static const CXCursor_OMPTargetParallelForDirective = 264; + + /// OpenMP target update directive. + static const CXCursor_OMPTargetUpdateDirective = 265; + + /// OpenMP distribute parallel for directive. + static const CXCursor_OMPDistributeParallelForDirective = 266; + + /// OpenMP distribute parallel for simd directive. + static const CXCursor_OMPDistributeParallelForSimdDirective = 267; + + /// OpenMP distribute simd directive. + static const CXCursor_OMPDistributeSimdDirective = 268; + + /// OpenMP target parallel for simd directive. + static const CXCursor_OMPTargetParallelForSimdDirective = 269; + + /// OpenMP target simd directive. + static const CXCursor_OMPTargetSimdDirective = 270; + + /// OpenMP teams distribute directive. + static const CXCursor_OMPTeamsDistributeDirective = 271; + + /// OpenMP teams distribute simd directive. + static const CXCursor_OMPTeamsDistributeSimdDirective = 272; + + /// OpenMP teams distribute parallel for simd directive. + static const CXCursor_OMPTeamsDistributeParallelForSimdDirective = 273; + + /// OpenMP teams distribute parallel for directive. + static const CXCursor_OMPTeamsDistributeParallelForDirective = 274; + + /// OpenMP target teams directive. + static const CXCursor_OMPTargetTeamsDirective = 275; + + /// OpenMP target teams distribute directive. + static const CXCursor_OMPTargetTeamsDistributeDirective = 276; + + /// OpenMP target teams distribute parallel for directive. + static const CXCursor_OMPTargetTeamsDistributeParallelForDirective = 277; + + /// OpenMP target teams distribute parallel for simd directive. + static const CXCursor_OMPTargetTeamsDistributeParallelForSimdDirective = 278; + + /// OpenMP target teams distribute simd directive. + static const CXCursor_OMPTargetTeamsDistributeSimdDirective = 279; + + /// C++2a std::bit_cast expression. + static const CXCursor_BuiltinBitCastExpr = 280; + + /// OpenMP master taskloop directive. + static const CXCursor_OMPMasterTaskLoopDirective = 281; + + /// OpenMP parallel master taskloop directive. + static const CXCursor_OMPParallelMasterTaskLoopDirective = 282; + + /// OpenMP master taskloop simd directive. + static const CXCursor_OMPMasterTaskLoopSimdDirective = 283; + + /// OpenMP parallel master taskloop simd directive. + static const CXCursor_OMPParallelMasterTaskLoopSimdDirective = 284; + + /// OpenMP parallel master directive. + static const CXCursor_OMPParallelMasterDirective = 285; + + /// OpenMP depobj directive. + static const CXCursor_OMPDepobjDirective = 286; + + /// OpenMP scan directive. + static const CXCursor_OMPScanDirective = 287; + + /// OpenMP tile directive. + static const CXCursor_OMPTileDirective = 288; + + /// OpenMP canonical loop. + static const CXCursor_OMPCanonicalLoop = 289; + + /// OpenMP interop directive. + static const CXCursor_OMPInteropDirective = 290; + + /// OpenMP dispatch directive. + static const CXCursor_OMPDispatchDirective = 291; + + /// OpenMP masked directive. + static const CXCursor_OMPMaskedDirective = 292; + + /// OpenMP unroll directive. + static const CXCursor_OMPUnrollDirective = 293; + + /// OpenMP metadirective directive. + static const CXCursor_OMPMetaDirective = 294; + + /// OpenMP loop directive. + static const CXCursor_OMPGenericLoopDirective = 295; + + /// OpenMP teams loop directive. + static const CXCursor_OMPTeamsGenericLoopDirective = 296; + + /// OpenMP target teams loop directive. + static const CXCursor_OMPTargetTeamsGenericLoopDirective = 297; + + /// OpenMP parallel loop directive. + static const CXCursor_OMPParallelGenericLoopDirective = 298; + + /// OpenMP target parallel loop directive. + static const CXCursor_OMPTargetParallelGenericLoopDirective = 299; + + /// OpenMP parallel masked directive. + static const CXCursor_OMPParallelMaskedDirective = 300; + + /// OpenMP masked taskloop directive. + static const CXCursor_OMPMaskedTaskLoopDirective = 301; + + /// OpenMP masked taskloop simd directive. + static const CXCursor_OMPMaskedTaskLoopSimdDirective = 302; + + /// OpenMP parallel masked taskloop directive. + static const CXCursor_OMPParallelMaskedTaskLoopDirective = 303; + + /// OpenMP parallel masked taskloop simd directive. + static const CXCursor_OMPParallelMaskedTaskLoopSimdDirective = 304; + + /// OpenMP error directive. + static const CXCursor_OMPErrorDirective = 305; + + /// OpenMP scope directive. + static const CXCursor_OMPScopeDirective = 306; + static const CXCursor_LastStmt = 306; + + /// Cursor that represents the translation unit itself. + /// + /// The translation unit cursor exists primarily to act as the root + /// cursor for traversing the contents of a translation unit. + static const CXCursor_TranslationUnit = 350; + static const CXCursor_FirstAttr = 400; + + /// An attribute whose specific kind is not exposed via this + /// interface. + static const CXCursor_UnexposedAttr = 400; + static const CXCursor_IBActionAttr = 401; + static const CXCursor_IBOutletAttr = 402; + static const CXCursor_IBOutletCollectionAttr = 403; + static const CXCursor_CXXFinalAttr = 404; + static const CXCursor_CXXOverrideAttr = 405; + static const CXCursor_AnnotateAttr = 406; + static const CXCursor_AsmLabelAttr = 407; + static const CXCursor_PackedAttr = 408; + static const CXCursor_PureAttr = 409; + static const CXCursor_ConstAttr = 410; + static const CXCursor_NoDuplicateAttr = 411; + static const CXCursor_CUDAConstantAttr = 412; + static const CXCursor_CUDADeviceAttr = 413; + static const CXCursor_CUDAGlobalAttr = 414; + static const CXCursor_CUDAHostAttr = 415; + static const CXCursor_CUDASharedAttr = 416; + static const CXCursor_VisibilityAttr = 417; + static const CXCursor_DLLExport = 418; + static const CXCursor_DLLImport = 419; + static const CXCursor_NSReturnsRetained = 420; + static const CXCursor_NSReturnsNotRetained = 421; + static const CXCursor_NSReturnsAutoreleased = 422; + static const CXCursor_NSConsumesSelf = 423; + static const CXCursor_NSConsumed = 424; + static const CXCursor_ObjCException = 425; + static const CXCursor_ObjCNSObject = 426; + static const CXCursor_ObjCIndependentClass = 427; + static const CXCursor_ObjCPreciseLifetime = 428; + static const CXCursor_ObjCReturnsInnerPointer = 429; + static const CXCursor_ObjCRequiresSuper = 430; + static const CXCursor_ObjCRootClass = 431; + static const CXCursor_ObjCSubclassingRestricted = 432; + static const CXCursor_ObjCExplicitProtocolImpl = 433; + static const CXCursor_ObjCDesignatedInitializer = 434; + static const CXCursor_ObjCRuntimeVisible = 435; + static const CXCursor_ObjCBoxable = 436; + static const CXCursor_FlagEnum = 437; + static const CXCursor_ConvergentAttr = 438; + static const CXCursor_WarnUnusedAttr = 439; + static const CXCursor_WarnUnusedResultAttr = 440; + static const CXCursor_AlignedAttr = 441; + static const CXCursor_LastAttr = 441; + static const CXCursor_PreprocessingDirective = 500; + static const CXCursor_MacroDefinition = 501; + static const CXCursor_MacroExpansion = 502; + static const CXCursor_MacroInstantiation = 502; + static const CXCursor_InclusionDirective = 503; + static const CXCursor_FirstPreprocessing = 500; + static const CXCursor_LastPreprocessing = 503; + + /// A module import declaration. + static const CXCursor_ModuleImportDecl = 600; + static const CXCursor_TypeAliasTemplateDecl = 601; + + /// A static_assert or _Static_assert node + static const CXCursor_StaticAssert = 602; + + /// a friend declaration. + static const CXCursor_FriendDecl = 603; + + /// a concept declaration. + static const CXCursor_ConceptDecl = 604; + static const CXCursor_FirstExtraDecl = 600; + static const CXCursor_LastExtraDecl = 604; + + /// A code completion overload candidate. + static const CXCursor_OverloadCandidate = 700; +} + +/// Describes the kind of type +abstract class CXTypeKind { + /// Represents an invalid type (e.g., where no type is available). + static const CXType_Invalid = 0; + + /// A type whose specific kind is not exposed via this + /// interface. + static const CXType_Unexposed = 1; + static const CXType_Void = 2; + static const CXType_Bool = 3; + static const CXType_Char_U = 4; + static const CXType_UChar = 5; + static const CXType_Char16 = 6; + static const CXType_Char32 = 7; + static const CXType_UShort = 8; + static const CXType_UInt = 9; + static const CXType_ULong = 10; + static const CXType_ULongLong = 11; + static const CXType_UInt128 = 12; + static const CXType_Char_S = 13; + static const CXType_SChar = 14; + static const CXType_WChar = 15; + static const CXType_Short = 16; + static const CXType_Int = 17; + static const CXType_Long = 18; + static const CXType_LongLong = 19; + static const CXType_Int128 = 20; + static const CXType_Float = 21; + static const CXType_Double = 22; + static const CXType_LongDouble = 23; + static const CXType_NullPtr = 24; + static const CXType_Overload = 25; + static const CXType_Dependent = 26; + static const CXType_ObjCId = 27; + static const CXType_ObjCClass = 28; + static const CXType_ObjCSel = 29; + static const CXType_Float128 = 30; + static const CXType_Half = 31; + static const CXType_Float16 = 32; + static const CXType_ShortAccum = 33; + static const CXType_Accum = 34; + static const CXType_LongAccum = 35; + static const CXType_UShortAccum = 36; + static const CXType_UAccum = 37; + static const CXType_ULongAccum = 38; + static const CXType_BFloat16 = 39; + static const CXType_Ibm128 = 40; + static const CXType_FirstBuiltin = 2; + static const CXType_LastBuiltin = 40; + static const CXType_Complex = 100; + static const CXType_Pointer = 101; + static const CXType_BlockPointer = 102; + static const CXType_LValueReference = 103; + static const CXType_RValueReference = 104; + static const CXType_Record = 105; + static const CXType_Enum = 106; + static const CXType_Typedef = 107; + static const CXType_ObjCInterface = 108; + static const CXType_ObjCObjectPointer = 109; + static const CXType_FunctionNoProto = 110; + static const CXType_FunctionProto = 111; + static const CXType_ConstantArray = 112; + static const CXType_Vector = 113; + static const CXType_IncompleteArray = 114; + static const CXType_VariableArray = 115; + static const CXType_DependentSizedArray = 116; + static const CXType_MemberPointer = 117; + static const CXType_Auto = 118; + + /// Represents a type that was referred to using an elaborated type keyword. + /// + /// E.g., struct S, or via a qualified name, e.g., N::M::type, or both. + static const CXType_Elaborated = 119; + static const CXType_Pipe = 120; + static const CXType_OCLImage1dRO = 121; + static const CXType_OCLImage1dArrayRO = 122; + static const CXType_OCLImage1dBufferRO = 123; + static const CXType_OCLImage2dRO = 124; + static const CXType_OCLImage2dArrayRO = 125; + static const CXType_OCLImage2dDepthRO = 126; + static const CXType_OCLImage2dArrayDepthRO = 127; + static const CXType_OCLImage2dMSAARO = 128; + static const CXType_OCLImage2dArrayMSAARO = 129; + static const CXType_OCLImage2dMSAADepthRO = 130; + static const CXType_OCLImage2dArrayMSAADepthRO = 131; + static const CXType_OCLImage3dRO = 132; + static const CXType_OCLImage1dWO = 133; + static const CXType_OCLImage1dArrayWO = 134; + static const CXType_OCLImage1dBufferWO = 135; + static const CXType_OCLImage2dWO = 136; + static const CXType_OCLImage2dArrayWO = 137; + static const CXType_OCLImage2dDepthWO = 138; + static const CXType_OCLImage2dArrayDepthWO = 139; + static const CXType_OCLImage2dMSAAWO = 140; + static const CXType_OCLImage2dArrayMSAAWO = 141; + static const CXType_OCLImage2dMSAADepthWO = 142; + static const CXType_OCLImage2dArrayMSAADepthWO = 143; + static const CXType_OCLImage3dWO = 144; + static const CXType_OCLImage1dRW = 145; + static const CXType_OCLImage1dArrayRW = 146; + static const CXType_OCLImage1dBufferRW = 147; + static const CXType_OCLImage2dRW = 148; + static const CXType_OCLImage2dArrayRW = 149; + static const CXType_OCLImage2dDepthRW = 150; + static const CXType_OCLImage2dArrayDepthRW = 151; + static const CXType_OCLImage2dMSAARW = 152; + static const CXType_OCLImage2dArrayMSAARW = 153; + static const CXType_OCLImage2dMSAADepthRW = 154; + static const CXType_OCLImage2dArrayMSAADepthRW = 155; + static const CXType_OCLImage3dRW = 156; + static const CXType_OCLSampler = 157; + static const CXType_OCLEvent = 158; + static const CXType_OCLQueue = 159; + static const CXType_OCLReserveID = 160; + static const CXType_ObjCObject = 161; + static const CXType_ObjCTypeParam = 162; + static const CXType_Attributed = 163; + static const CXType_OCLIntelSubgroupAVCMcePayload = 164; + static const CXType_OCLIntelSubgroupAVCImePayload = 165; + static const CXType_OCLIntelSubgroupAVCRefPayload = 166; + static const CXType_OCLIntelSubgroupAVCSicPayload = 167; + static const CXType_OCLIntelSubgroupAVCMceResult = 168; + static const CXType_OCLIntelSubgroupAVCImeResult = 169; + static const CXType_OCLIntelSubgroupAVCRefResult = 170; + static const CXType_OCLIntelSubgroupAVCSicResult = 171; + static const CXType_OCLIntelSubgroupAVCImeResultSingleReferenceStreamout = + 172; + static const CXType_OCLIntelSubgroupAVCImeResultDualReferenceStreamout = 173; + static const CXType_OCLIntelSubgroupAVCImeSingleReferenceStreamin = 174; + static const CXType_OCLIntelSubgroupAVCImeDualReferenceStreamin = 175; + static const CXType_OCLIntelSubgroupAVCImeResultSingleRefStreamout = 172; + static const CXType_OCLIntelSubgroupAVCImeResultDualRefStreamout = 173; + static const CXType_OCLIntelSubgroupAVCImeSingleRefStreamin = 174; + static const CXType_OCLIntelSubgroupAVCImeDualRefStreamin = 175; + static const CXType_ExtVector = 176; + static const CXType_Atomic = 177; + static const CXType_BTFTagAttributed = 178; +} + +abstract class CXTypeNullabilityKind { + /// Values of this type can never be null. + static const CXTypeNullability_NonNull = 0; + + /// Values of this type can be null. + static const CXTypeNullability_Nullable = 1; + + /// Whether values of this type can be null is (explicitly) + /// unspecified. This captures a (fairly rare) case where we + /// can't conclude anything about the nullability of the type even + /// though it has been considered. + static const CXTypeNullability_Unspecified = 2; + + /// Nullability is not applicable to this type. + static const CXTypeNullability_Invalid = 3; + + /// Generally behaves like Nullable, except when used in a block parameter that + /// was imported into a swift async method. There, swift will assume that the + /// parameter can get null even if no error occurred. _Nullable parameters are + /// assumed to only get null on error. + static const CXTypeNullability_NullableResult = 4; +} + +/// List the possible error codes for \c clang_Type_getSizeOf, +/// \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and +/// \c clang_Cursor_getOffsetOf. +/// +/// A value of this enumeration type can be returned if the target type is not +/// a valid argument to sizeof, alignof or offsetof. +abstract class CXTypeLayoutError { + /// Type is of kind CXType_Invalid. + static const CXTypeLayoutError_Invalid = -1; + + /// The type is an incomplete Type. + static const CXTypeLayoutError_Incomplete = -2; + + /// The type is a dependent Type. + static const CXTypeLayoutError_Dependent = -3; + + /// The type is not a constant size type. + static const CXTypeLayoutError_NotConstantSize = -4; + + /// The Field name is not valid for this record. + static const CXTypeLayoutError_InvalidFieldName = -5; + + /// The type is undeduced. + static const CXTypeLayoutError_Undeduced = -6; +} + +/// Represents the storage classes as declared in the source. CX_SC_Invalid +/// was added for the case that the passed cursor in not a declaration. +abstract class CX_StorageClass { + static const CX_SC_Invalid = 0; + static const CX_SC_None = 1; + static const CX_SC_Extern = 2; + static const CX_SC_Static = 3; + static const CX_SC_PrivateExtern = 4; + static const CX_SC_OpenCLWorkGroupLocal = 5; + static const CX_SC_Auto = 6; + static const CX_SC_Register = 7; +} + +/// Describes how the traversal of the children of a particular +/// cursor should proceed after visiting a particular child cursor. +/// +/// A value of this enumeration type should be returned by each +/// \c CXCursorVisitor to indicate how clang_visitChildren() proceed. +abstract class CXChildVisitResult { + /// Terminates the cursor traversal. + static const CXChildVisit_Break = 0; + + /// Continues the cursor traversal with the next sibling of + /// the cursor just visited, without visiting its children. + static const CXChildVisit_Continue = 1; + + /// Recursively traverse the children of this cursor, using + /// the same visitor and client data. + static const CXChildVisit_Recurse = 2; +} + +/// Property attributes for a \c CXCursor_ObjCPropertyDecl. +abstract class CXObjCPropertyAttrKind { + static const CXObjCPropertyAttr_noattr = 0; + static const CXObjCPropertyAttr_readonly = 1; + static const CXObjCPropertyAttr_getter = 2; + static const CXObjCPropertyAttr_assign = 4; + static const CXObjCPropertyAttr_readwrite = 8; + static const CXObjCPropertyAttr_retain = 16; + static const CXObjCPropertyAttr_copy = 32; + static const CXObjCPropertyAttr_nonatomic = 64; + static const CXObjCPropertyAttr_setter = 128; + static const CXObjCPropertyAttr_atomic = 256; + static const CXObjCPropertyAttr_weak = 512; + static const CXObjCPropertyAttr_strong = 1024; + static const CXObjCPropertyAttr_unsafe_unretained = 2048; + static const CXObjCPropertyAttr_class = 4096; +} + +abstract class CXEvalResultKind { + static const CXEval_Int = 1; + static const CXEval_Float = 2; + static const CXEval_ObjCStrLiteral = 3; + static const CXEval_StrLiteral = 4; + static const CXEval_CFStr = 5; + static const CXEval_Other = 6; + static const CXEval_UnExposed = 0; +} + +/// Evaluation result of a cursor +typedef CXEvalResult = ffi.Pointer; + +/// A character string. +/// +/// The \c CXString type is used to return strings from the interface when +/// the ownership of that string might differ from one call to the next. +/// Use \c clang_getCString() to retrieve the string data and, once finished +/// with the string data, call \c clang_disposeString() to free the string. +final class CXString extends ffi.Opaque {} + +/// A cursor representing some element in the abstract syntax tree for +/// a translation unit. +/// +/// The cursor abstraction unifies the different kinds of entities in a +/// program--declaration, statements, expressions, references to declarations, +/// etc.--under a single "cursor" abstraction with a common set of operations. +/// Common operation for a cursor include: getting the physical location in +/// a source file where the cursor points, getting the name associated with a +/// cursor, and retrieving cursors for any child nodes of a particular cursor. +/// +/// Cursors can be produced in two specific ways. +/// clang_getTranslationUnitCursor() produces a cursor for a translation unit, +/// from which one can use clang_visitChildren() to explore the rest of the +/// translation unit. clang_getCursor() maps from a physical source location +/// to the entity that resides at that location, allowing one to map from the +/// source code into the AST. +final class CXCursor extends ffi.Opaque {} + +/// The type of an element in the abstract syntax tree. +final class CXType extends ffi.Opaque {} + +/// Identifies a half-open character range in the source code. +/// +/// Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the +/// starting and end locations from a source range, respectively. +final class CXSourceRange extends ffi.Opaque {} + +/// Identifies a specific source location within a translation +/// unit. +/// +/// Use clang_getExpansionLocation() or clang_getSpellingLocation() +/// to map a source location to a particular file, line, and column. +final class CXSourceLocation extends ffi.Opaque {} + +/// A particular source file that is part of a translation unit. +typedef CXFile = ffi.Pointer; diff --git a/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_types.dart b/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_types.dart new file mode 100644 index 0000000000..8ba3716c2b --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_types.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Wraps every opaque struct in a pointer for similartiy with ffigen codebase. +library; + +import 'dart:ffi'; + +import 'clang_bindings.dart' as clang; + +export 'clang_bindings.dart' + show + CXChildVisitResult, + CXCursorKind, + CXDiagnostic, + CXDiagnosticDisplayOptions, + CXDiagnosticSeverity, + CXEvalResult, + CXEvalResultKind, + CXFile, + CXIndex, + CXObjCPropertyAttrKind, + CXTranslationUnit, + CXTranslationUnit_Flags, + CXTypeKind, + CXTypeLayoutError, + CXTypeNullabilityKind, + CX_StorageClass; + +typedef CXString = Pointer; +typedef CXUnsavedFile = Pointer; +typedef CXCursor = Pointer; +typedef CXType = Pointer; +typedef CXSourceRange = Pointer; +typedef CXSourceLocation = Pointer; diff --git a/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_wrapper.dart b/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_wrapper.dart new file mode 100644 index 0000000000..99c0b7957c --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/clang_bindings/clang_wrapper.dart @@ -0,0 +1,90 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// AUTO GENERATED FILE, DO NOT EDIT. +// ignore_for_file: camel_case_types, non_constant_identifier_names + +import 'clang_bindings.dart' as c; + +class Clang { + final clang_createIndex = c.clang_createIndex; + final clang_disposeIndex = c.clang_disposeIndex; + final clang_parseTranslationUnit = c.clang_parseTranslationUnit; + final clang_disposeTranslationUnit = c.clang_disposeTranslationUnit; + final clang_getNumDiagnostics = c.clang_getNumDiagnostics; + final clang_getDiagnostic = c.clang_getDiagnostic; + final clang_getDiagnosticSeverity = c.clang_getDiagnosticSeverity; + final clang_disposeDiagnostic = c.clang_disposeDiagnostic; + final clang_EvalResult_getKind = c.clang_EvalResult_getKind; + final clang_EvalResult_getAsLongLong = c.clang_EvalResult_getAsLongLong; + final clang_EvalResult_getAsDouble = c.clang_EvalResult_getAsDouble; + final clang_EvalResult_getAsStr = c.clang_EvalResult_getAsStr; + final clang_EvalResult_dispose = c.clang_EvalResult_dispose; + final clang_getCString = c.clang_getCString_wrap; + final clang_disposeString = c.clang_disposeString_wrap; + final clang_getClangVersion = c.clang_getClangVersion_wrap; + final clang_getCursorKind = c.clang_getCursorKind_wrap; + final clang_getCursorDefinition = c.clang_getCursorDefinition_wrap; + final clang_getCursorKindSpelling = c.clang_getCursorKindSpelling_wrap; + final clang_getCursorType = c.clang_getCursorType_wrap; + final clang_getTypeSpelling = c.clang_getTypeSpelling_wrap; + final clang_getTypeKindSpelling = c.clang_getTypeKindSpelling_wrap; + final clang_getResultType = c.clang_getResultType_wrap; + final clang_getPointeeType = c.clang_getPointeeType_wrap; + final clang_getCanonicalType = c.clang_getCanonicalType_wrap; + final clang_Type_getModifiedType = c.clang_Type_getModifiedType_wrap; + final clang_Type_getNullability = c.clang_Type_getNullability_wrap; + final clang_Type_getNamedType = c.clang_Type_getNamedType_wrap; + final clang_Type_getAlignOf = c.clang_Type_getAlignOf_wrap; + final clang_getTypeDeclaration = c.clang_getTypeDeclaration_wrap; + final clang_getTypedefName = c.clang_getTypedefName_wrap; + final clang_getTypedefDeclUnderlyingType = + c.clang_getTypedefDeclUnderlyingType_wrap; + final clang_getCursorSpelling = c.clang_getCursorSpelling_wrap; + final clang_getCursorUSR = c.clang_getCursorUSR_wrap; + final clang_getTranslationUnitCursor = c.clang_getTranslationUnitCursor_wrap; + final clang_formatDiagnostic = c.clang_formatDiagnostic_wrap; + final clang_visitChildren = c.clang_visitChildren_wrap; + final clang_getArgType = c.clang_getArgType_wrap; + final clang_getNumArgTypes = c.clang_getNumArgTypes_wrap; + final clang_getEnumConstantDeclValue = c.clang_getEnumConstantDeclValue_wrap; + final clang_equalRanges = c.clang_equalRanges_wrap; + final clang_Cursor_Evaluate = c.clang_Cursor_Evaluate_wrap; + final clang_Cursor_getArgument = c.clang_Cursor_getArgument_wrap; + final clang_Cursor_getNumArguments = c.clang_Cursor_getNumArguments_wrap; + final clang_Cursor_getCommentRange = c.clang_Cursor_getCommentRange_wrap; + final clang_Cursor_getRawCommentText = c.clang_Cursor_getRawCommentText_wrap; + final clang_Cursor_getBriefCommentText = + c.clang_Cursor_getBriefCommentText_wrap; + final clang_Cursor_getStorageClass = c.clang_Cursor_getStorageClass_wrap; + final clang_getFieldDeclBitWidth = c.clang_getFieldDeclBitWidth_wrap; + final clang_Cursor_hasAttrs = c.clang_Cursor_hasAttrs_wrap; + final clang_Cursor_isFunctionInlined = c.clang_Cursor_isFunctionInlined_wrap; + final clang_Cursor_isAnonymous = c.clang_Cursor_isAnonymous_wrap; + final clang_Cursor_isAnonymousRecordDecl = + c.clang_Cursor_isAnonymousRecordDecl_wrap; + final clang_Cursor_isNull = c.clang_Cursor_isNull_wrap; + final clang_Cursor_isMacroFunctionLike = + c.clang_Cursor_isMacroFunctionLike_wrap; + final clang_Cursor_isMacroBuiltin = c.clang_Cursor_isMacroBuiltin_wrap; + final clang_Cursor_getObjCPropertyAttributes = + c.clang_Cursor_getObjCPropertyAttributes_wrap; + final clang_Cursor_isObjCOptional = c.clang_Cursor_isObjCOptional_wrap; + final clang_Cursor_getObjCPropertyGetterName = + c.clang_Cursor_getObjCPropertyGetterName_wrap; + final clang_Cursor_getObjCPropertySetterName = + c.clang_Cursor_getObjCPropertySetterName_wrap; + final clang_getCursorResultType = c.clang_getCursorResultType_wrap; + final clang_isFunctionTypeVariadic = c.clang_isFunctionTypeVariadic_wrap; + final clang_getCursorLocation = c.clang_getCursorLocation_wrap; + final clang_getEnumDeclIntegerType = c.clang_getEnumDeclIntegerType_wrap; + final clang_getFileLocation = c.clang_getFileLocation_wrap; + final clang_getFileName = c.clang_getFileName_wrap; + final clang_getNumElements = c.clang_getNumElements_wrap; + final clang_getArrayElementType = c.clang_getArrayElementType_wrap; + final clang_isConstQualifiedType = c.clang_isConstQualifiedType_wrap; + final clang_Location_isInSystemHeader = + c.clang_Location_isInSystemHeader_wrap; + final getCXTypeKind = c.getCXTypeKind; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/data.dart b/pkgs/ffigenpad/lib/src/header_parser/data.dart new file mode 100644 index 0000000000..28d246782e --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/data.dart @@ -0,0 +1,58 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../code_generator.dart' show Constant, ObjCBuiltInFunctions; +import '../config_provider.dart' show Config; +import 'clang_bindings/clang_wrapper.dart' show Clang; + +import 'utils.dart'; + +// /// Holds configurations. +Config get config => _config; +late Config _config; + +/// Holds clang functions. +Clang get clang => _clang; +Clang _clang = Clang(); + +// Cursor index. +CursorIndex get cursorIndex => _cursorIndex; +CursorIndex _cursorIndex = CursorIndex(); + +// // Tracks seen status for bindings +BindingsIndex get bindingsIndex => _bindingsIndex; +BindingsIndex _bindingsIndex = BindingsIndex(); + +/// Used for naming typedefs. +IncrementalNamer get incrementalNamer => _incrementalNamer; +IncrementalNamer _incrementalNamer = IncrementalNamer(); + +/// Saved macros, Key: prefixedName, Value originalName. +Map get savedMacros => _savedMacros; +Map _savedMacros = {}; + +/// Saved unnamed EnumConstants. +List get unnamedEnumConstants => _unnamedEnumConstants; +List _unnamedEnumConstants = []; + +/// Built in functions used by the Objective C bindings. +ObjCBuiltInFunctions get objCBuiltInFunctions => _objCBuiltInFunctions; +late ObjCBuiltInFunctions _objCBuiltInFunctions; + +/// Tracks if any source error/warning has occured which can potentially cause +/// invalid generated bindings. +bool hasSourceErrors = false; + +void initializeGlobals({required Config config}) { + _config = config; + _clang = Clang(); + _incrementalNamer = IncrementalNamer(); + _savedMacros = {}; + _unnamedEnumConstants = []; + _cursorIndex = CursorIndex(); + _bindingsIndex = BindingsIndex(); + _objCBuiltInFunctions = + ObjCBuiltInFunctions(config.generateForPackageObjectiveC); + hasSourceErrors = false; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/includer.dart b/pkgs/ffigenpad/lib/src/header_parser/includer.dart new file mode 100644 index 0000000000..5173f39512 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/includer.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Utility functions to check whether a binding should be parsed or not +/// based on filters. +library; + +import '../config_provider/config_types.dart'; +import '../strings.dart' as strings; +import 'data.dart'; + +bool _shouldIncludeDecl( + Declaration declaration, + bool Function(String) isSeenDecl, + bool Function(Declaration) configIncludes) { + if (isSeenDecl(declaration.usr) || declaration.originalName == '') { + return false; + } else if (config.usrTypeMappings.containsKey(declaration.usr)) { + return false; + } else if (configIncludes(declaration)) { + return true; + } else { + return false; + } +} + +bool shouldIncludeStruct(Declaration declaration) { + return _shouldIncludeDecl( + declaration, bindingsIndex.isSeenType, config.structDecl.shouldInclude); +} + +bool shouldIncludeUnion(Declaration declaration) { + return _shouldIncludeDecl( + declaration, bindingsIndex.isSeenType, config.unionDecl.shouldInclude); +} + +bool shouldIncludeFunc(Declaration declaration) { + return _shouldIncludeDecl( + declaration, bindingsIndex.isSeenFunc, config.functionDecl.shouldInclude); +} + +bool shouldIncludeEnumClass(Declaration declaration) { + return _shouldIncludeDecl(declaration, bindingsIndex.isSeenType, + config.enumClassDecl.shouldInclude); +} + +bool shouldIncludeUnnamedEnumConstant(Declaration declaration) { + return _shouldIncludeDecl( + declaration, + bindingsIndex.isSeenUnnamedEnumConstant, + config.unnamedEnumConstants.shouldInclude); +} + +bool shouldIncludeGlobalVar(Declaration declaration) { + return _shouldIncludeDecl( + declaration, bindingsIndex.isSeenGlobalVar, config.globals.shouldInclude); +} + +bool shouldIncludeMacro(Declaration declaration) { + return _shouldIncludeDecl( + declaration, bindingsIndex.isSeenMacro, config.macroDecl.shouldInclude); +} + +bool shouldIncludeTypealias(Declaration declaration) { + // Objective C has some core typedefs that are important to keep. + if (config.language == Language.objc && + declaration.originalName == strings.objcInstanceType) { + return true; + } + return _shouldIncludeDecl( + declaration, bindingsIndex.isSeenType, config.typedefs.shouldInclude); +} + +bool shouldIncludeObjCInterface(Declaration declaration) { + return _shouldIncludeDecl(declaration, bindingsIndex.isSeenType, + config.objcInterfaces.shouldInclude); +} + +bool shouldIncludeObjCProtocol(Declaration declaration) { + return _shouldIncludeDecl(declaration, bindingsIndex.isSeenObjCProtocol, + config.objcProtocols.shouldInclude); +} + +/// True if a cursor should be included based on headers config, used on root +/// declarations. +bool shouldIncludeRootCursor(String sourceFile) { + // Handle empty string in case of system headers or macros. + if (sourceFile.isEmpty) { + return false; + } + + // Add header to seen if it's not. + if (!bindingsIndex.isSeenHeader(sourceFile)) { + bindingsIndex.addHeaderToSeen( + sourceFile, config.shouldIncludeHeader(Uri.file(sourceFile))); + } + + return bindingsIndex.getSeenHeaderStatus(sourceFile)!; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/parser.dart b/pkgs/ffigenpad/lib/src/header_parser/parser.dart new file mode 100644 index 0000000000..0cb2e15bb8 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/parser.dart @@ -0,0 +1,175 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:logging/logging.dart'; + +import '../code_generator.dart'; +import '../config_provider.dart'; +import '../config_provider/config_types.dart'; +import '../strings.dart' as strings; +import 'clang_bindings/clang_types.dart' as clang_types; +import 'data.dart'; +import 'sub_parsers/macro_parser.dart'; +import 'translation_unit_parser.dart'; +import 'utils.dart'; + +/// Main entrypoint for header_parser. +Library parse(Config c) { + initParser(c); + + final bindings = parseToBindings(c); + + final library = Library( + bindings: bindings, + name: c.wrapperName, + description: c.wrapperDocComment, + header: c.preamble, + sort: c.sort, + generateForPackageObjectiveC: c.generateForPackageObjectiveC, + packingOverride: c.structPackingOverride, + libraryImports: c.libraryImports.values.toList(), + silenceEnumWarning: c.silenceEnumWarning, + nativeEntryPoints: c.entryPoints.map((uri) => uri.toFilePath()).toList(), + ); + + return library; +} + +// ============================================================================= +// BELOW FUNCTIONS ARE MEANT FOR INTERNAL USE AND TESTING +// ============================================================================= + +final _logger = Logger('ffigen.header_parser.parser'); + +/// Initializes parser, clears any previous values. +void initParser(Config c) { + // Initialize global variables. + initializeGlobals( + config: c, + ); +} + +/// Parses source files and returns the bindings. +List parseToBindings(Config c) { + final index = clang.clang_createIndex(0, 0); + + Pointer> clangCmdArgs = nullptr; + final compilerOpts = [ + // Add compiler opt for comment parsing for clang based on config. + if (config.commentType.length != CommentLength.none && + config.commentType.style == CommentStyle.any) + strings.fparseAllComments, + + // If the config targets Objective C, add a compiler opt for it. + if (config.language == Language.objc) ...[ + ...strings.clangLangObjC, + ..._findObjectiveCSysroot(), + ], + + // Add the user options last so they can override any other options. + ...config.compilerOpts + ]; + + _logger.fine('CompilerOpts used: $compilerOpts'); + clangCmdArgs = createDynamicStringArray(compilerOpts); + final cmdLen = compilerOpts.length; + + // Contains all bindings. A set ensures we never have duplicates. + final bindings = {}; + + // Log all headers for user. + _logger.info('Input Headers: ${config.entryPoints}'); + + // TODO: for some reason it can't add to a List of pointers + var tuList = []; + + // Parse all translation units from entry points. + for (final headerLocationUri in config.entryPoints) { + final headerLocation = headerLocationUri.toFilePath(); + _logger.fine('Creating TranslationUnit for header: $headerLocation'); + + final tu = clang.clang_parseTranslationUnit( + index, + headerLocation.toNativeUint8().cast(), + clangCmdArgs.cast(), + cmdLen, + nullptr, + 0, + clang_types.CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies | + clang_types.CXTranslationUnit_Flags + .CXTranslationUnit_DetailedPreprocessingRecord | + clang_types + .CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes, + ); + + if (tu == nullptr) { + _logger.severe( + "Skipped header/file: $headerLocation, couldn't parse source."); + // Skip parsing this header. + continue; + } + + logTuDiagnostics(tu, _logger, headerLocation); + tuList.add(tu.address); + } + + if (hasSourceErrors) { + _logger.warning('The compiler found warnings/errors in source files.'); + _logger.warning('This will likely generate invalid bindings.'); + if (config.ignoreSourceErrors) { + _logger.warning( + 'Ignored source errors. (User supplied --ignore-source-errors)'); + } else if (config.language == Language.objc) { + _logger.warning('Ignored source errors. (ObjC)'); + } else { + _logger.severe( + 'Skipped generating bindings due to errors in source files. See https://github.com/dart-lang/native/blob/main/pkgs/ffigen/doc/errors.md.'); + // return empty bindings instead of exiting + return []; + // exit(1); + } + } + + final tuCursors = tuList.map( + (tu) => clang.clang_getTranslationUnitCursor(Pointer.fromAddress(tu))); + + // Build usr to CXCusror map from translation units. + for (final rootCursor in tuCursors) { + buildUsrCursorDefinitionMap(rootCursor); + } + + // Parse definitions from translation units. + for (final rootCursor in tuCursors) { + bindings.addAll(parseTranslationUnit(rootCursor)); + } + + // Dispose translation units. + for (final tu in tuList) { + clang.clang_disposeTranslationUnit(Pointer.fromAddress(tu)); + } + + // Add all saved unnamed enums. + bindings.addAll(unnamedEnumConstants); + + // Parse all saved macros. + bindings.addAll(parseSavedMacros()); + + clangCmdArgs.dispose(cmdLen); + clang.clang_disposeIndex(index); + return bindings.toList(); +} + +List _findObjectiveCSysroot() { + // final result = Process.runSync('xcrun', ['--show-sdk-path']); + // if (result.exitCode == 0) { + // for (final line in (result.stdout as String).split('\n')) { + // if (line.isNotEmpty) { + // return ['-isysroot', line]; + // } + // } + // } + return []; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/compounddecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/compounddecl_parser.dart new file mode 100644 index 0000000000..b08eb2829d --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/compounddecl_parser.dart @@ -0,0 +1,329 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config.dart'; +import '../../config_provider/config_types.dart'; +import '../../strings.dart' as strings; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.compounddecl_parser'); + +/// Holds temporary information regarding [compound] while parsing. +class _ParsedCompound { + Compound compound; + bool unimplementedMemberType = false; + bool flexibleArrayMember = false; + bool bitFieldMember = false; + bool dartHandleMember = false; + bool incompleteCompoundMember = false; + + _ParsedCompound(this.compound); + + bool get isIncomplete => + unimplementedMemberType || + flexibleArrayMember || + bitFieldMember || + (dartHandleMember && config.useDartHandle) || + incompleteCompoundMember || + alignment == clang_types.CXTypeLayoutError.CXTypeLayoutError_Incomplete; + + // A struct without any attribute is definitely not packed. #pragma pack(...) + // also adds an attribute, but it's unexposed and cannot be travesed. + bool hasAttr = false; + + // A struct which as a __packed__ attribute is definitely packed. + bool hasPackedAttr = false; + + // Stores the maximum alignment from all the children. + int maxChildAlignment = 0; + + // Alignment of this struct. + int alignment = 0; + + bool get _isPacked { + if (!hasAttr || isIncomplete) return false; + if (hasPackedAttr) return true; + + return maxChildAlignment > alignment; + } + + /// Returns pack value of a struct depending on config, returns null for no + /// packing. + int? get packValue { + if (compound.isStruct && _isPacked && !isIncomplete) { + if (strings.packingValuesMap.containsKey(alignment)) { + return alignment; + } else { + _logger.warning('Unsupported pack value "$alignment" for Struct ' + '"${compound.name}".'); + return null; + } + } else { + return null; + } + } +} + +/// Parses a compound declaration. +Compound? parseCompoundDeclaration( + clang_types.CXCursor cursor, + CompoundType compoundType, { + /// Option to ignore declaration filter (Useful in case of extracting + /// declarations when they are passed/returned by an included function.) + bool ignoreFilter = false, + + /// To track if the declaration was used by reference(i.e T*). (Used to only + /// generate these as opaque if `dependency-only` was set to opaque). + bool pointerReference = false, +}) { + // Set includer functions according to compoundType. + final bool Function(Declaration) shouldIncludeDecl; + final DeclarationFilters configDecl; + final className = _compoundTypeDebugName(compoundType); + switch (compoundType) { + case CompoundType.struct: + shouldIncludeDecl = shouldIncludeStruct; + configDecl = config.structDecl; + break; + case CompoundType.union: + shouldIncludeDecl = shouldIncludeUnion; + configDecl = config.unionDecl; + break; + } + + // Parse the cursor definition instead, if this is a forward declaration. + final declUsr = cursor.usr(); + final String declName; + + // Only set name using USR if the type is not Anonymous (A struct is anonymous + // if it has no name, is not inside any typedef and declared inline inside + // another declaration). + if (clang.clang_Cursor_isAnonymous(cursor) == 0) { + // This gives the significant name, i.e name of the struct if defined or + // name of the first typedef declaration that refers to it. + declName = declUsr.split('@').last; + } else { + // Empty names are treated as inline declarations. + declName = ''; + } + + final decl = Declaration(usr: declUsr, originalName: declName); + if (declName.isEmpty) { + if (ignoreFilter) { + cursor = cursorIndex.getDefinition(cursor); + // This declaration is defined inside some other declaration and hence + // must be generated. + return Compound.fromType( + type: compoundType, + name: incrementalNamer.name('Unnamed$className'), + usr: declUsr, + dartDoc: getCursorDocComment(cursor), + objCBuiltInFunctions: objCBuiltInFunctions, + nativeType: cursor.type().spelling(), + ); + } else { + _logger.finest('unnamed $className declaration'); + } + } else if (ignoreFilter || shouldIncludeDecl(decl)) { + cursor = cursorIndex.getDefinition(cursor); + _logger.fine('++++ Adding $className: Name: $declName, ' + '${cursor.completeStringRepr()}'); + return Compound.fromType( + type: compoundType, + usr: declUsr, + originalName: declName, + name: configDecl.rename(decl), + dartDoc: getCursorDocComment(cursor), + objCBuiltInFunctions: objCBuiltInFunctions, + nativeType: cursor.type().spelling(), + ); + } + return null; +} + +void fillCompoundMembersIfNeeded( + Compound compound, + clang_types.CXCursor cursor, { + /// Option to ignore declaration filter (Useful in case of extracting + /// declarations when they are passed/returned by an included function.) + bool ignoreFilter = false, + + /// To track if the declaration was used by reference(i.e T*). (Used to only + /// generate these as opaque if `dependency-only` was set to opaque). + bool pointerReference = false, +}) { + final compoundType = compound.compoundType; + + // Skip dependencies if already seen OR user has specified `dependency-only` + // as opaque AND this is a pointer reference AND the declaration was not + // included according to config (ignoreFilter). + final skipDependencies = compound.parsedDependencies || + (pointerReference && + ignoreFilter && + ((compoundType == CompoundType.struct && + config.structDependencies == CompoundDependencies.opaque) || + (compoundType == CompoundType.union && + config.unionDependencies == CompoundDependencies.opaque))); + if (skipDependencies) return; + cursor = cursorIndex.getDefinition(cursor); + + final parsed = _ParsedCompound(compound); + final className = _compoundTypeDebugName(compoundType); + parsed.hasAttr = clang.clang_Cursor_hasAttrs(cursor) != 0; + parsed.alignment = cursor.type().alignment(); + compound.parsedDependencies = true; // Break cycles. + + cursor.visitChildren((cursor) => _compoundMembersVisitor(cursor, parsed)); + + _logger.finest('Opaque: ${parsed.isIncomplete}, HasAttr: ${parsed.hasAttr}, ' + 'AlignValue: ${parsed.alignment}, ' + 'MaxChildAlignValue: ${parsed.maxChildAlignment}, ' + 'PackValue: ${parsed.packValue}.'); + compound.pack = parsed.packValue; + + if (parsed.unimplementedMemberType) { + _logger.fine('---- Removed $className members, reason: member with ' + 'unimplementedtype ${cursor.completeStringRepr()}'); + _logger.warning('Removed All $className Members from ${compound.name}' + '(${compound.originalName}), struct member has an unsupported type.'); + } else if (parsed.flexibleArrayMember) { + _logger.fine('---- Removed $className members, reason: incomplete array ' + 'member ${cursor.completeStringRepr()}'); + _logger.warning('Removed All $className Members from ${compound.name}' + '(${compound.originalName}), Flexible array members not supported.'); + } else if (parsed.bitFieldMember) { + _logger.fine('---- Removed $className members, reason: bitfield members ' + '${cursor.completeStringRepr()}'); + _logger.warning('Removed All $className Members from ${compound.name}' + '(${compound.originalName}), Bit Field members not supported.'); + } else if (parsed.dartHandleMember && config.useDartHandle) { + _logger.fine('---- Removed $className members, reason: Dart_Handle member. ' + '${cursor.completeStringRepr()}'); + _logger.warning('Removed All $className Members from ${compound.name}' + '(${compound.originalName}), Dart_Handle member not supported.'); + } else if (parsed.incompleteCompoundMember) { + _logger.fine( + '---- Removed $className members, reason: Incomplete Nested Struct ' + 'member. ${cursor.completeStringRepr()}'); + _logger.warning('Removed All $className Members from ${compound.name}' + '(${compound.originalName}), Incomplete Nested Struct member not ' + 'supported.'); + } + + // Clear all members if declaration is incomplete. + if (parsed.isIncomplete) { + compound.members.clear(); + } + + // C allows empty structs/union, but it's undefined behaviour at runtine. + // So we need to mark a declaration incomplete if it has no members. + compound.isIncomplete = parsed.isIncomplete || compound.members.isEmpty; +} + +/// Visitor for the struct/union cursor +/// [clang_types.CXCursorKind.CXCursor_StructDecl]/ +/// [clang_types.CXCursorKind.CXCursor_UnionDecl]. +/// +/// Child visitor invoked on struct/union cursor. +void _compoundMembersVisitor( + clang_types.CXCursor cursor, _ParsedCompound parsed) { + final decl = Declaration( + usr: parsed.compound.usr, + originalName: parsed.compound.originalName, + ); + try { + switch (cursor.kind) { + case clang_types.CXCursorKind.CXCursor_FieldDecl: + _logger.finer('===== member: ${cursor.completeStringRepr()}'); + + // Set maxChildAlignValue. + final align = cursor.type().alignment(); + if (align > parsed.maxChildAlignment) { + parsed.maxChildAlignment = align; + } + + final mt = cursor.toCodeGenType(); + if (mt is IncompleteArray) { + // TODO(https://github.com/dart-lang/ffigen/issues/68): Structs with + // flexible Array Members are not supported. + parsed.flexibleArrayMember = true; + } + if (clang.clang_getFieldDeclBitWidth(cursor) != -1) { + // TODO(https://github.com/dart-lang/ffigen/issues/84): Struct with + // bitfields are not suppoorted. + parsed.bitFieldMember = true; + } + if (mt is HandleType) { + parsed.dartHandleMember = true; + } + if (mt.isIncompleteCompound) { + parsed.incompleteCompoundMember = true; + } + if (mt.baseType is UnimplementedType) { + parsed.unimplementedMemberType = true; + } + parsed.compound.members.add( + Member( + dartDoc: getCursorDocComment( + cursor, + nesting.length + commentPrefix.length, + ), + originalName: cursor.spelling(), + name: config.structDecl.renameMember(decl, cursor.spelling()), + type: mt, + ), + ); + + break; + + case clang_types.CXCursorKind.CXCursor_PackedAttr: + parsed.hasPackedAttr = true; + + break; + case clang_types.CXCursorKind.CXCursor_UnionDecl: + case clang_types.CXCursorKind.CXCursor_StructDecl: + // If the union/struct are anonymous, then we need to add them now, + // otherwise they will be added in the next iteration. + if (!cursor.isAnonymousRecordDecl()) break; + + final mt = cursor.toCodeGenType(); + if (mt.isIncompleteCompound) { + parsed.incompleteCompoundMember = true; + } + + // Anonymous members are always unnamed. To avoid environment- + // dependent naming issues with the generated code, we explicitly + // use the empty string as spelling. + final spelling = ''; + + parsed.compound.members.add( + Member( + dartDoc: getCursorDocComment( + cursor, + nesting.length + commentPrefix.length, + ), + originalName: spelling, + name: config.structDecl.renameMember(decl, spelling), + type: mt, + ), + ); + + break; + } + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } +} + +String _compoundTypeDebugName(CompoundType compoundType) { + return compoundType == CompoundType.struct ? 'Struct' : 'Union'; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/enumdecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/enumdecl_parser.dart new file mode 100644 index 0000000000..e155d1ab8f --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/enumdecl_parser.dart @@ -0,0 +1,109 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../type_extractor/cxtypekindmap.dart'; +import '../utils.dart'; +import 'unnamed_enumdecl_parser.dart'; + +final _logger = Logger('ffigen.header_parser.enumdecl_parser'); + +/// Parses an enum declaration. Returns (enumClass, nativeType). enumClass +/// is null for anonymous enums. +(EnumClass? enumClass, Type nativeType) parseEnumDeclaration( + clang_types.CXCursor cursor, { + /// Option to ignore declaration filter (Useful in case of extracting + /// declarations when they are passed/returned by an included function.) + bool ignoreFilter = false, +}) { + EnumClass? enumClass; + // Parse the cursor definition instead, if this is a forward declaration. + cursor = cursorIndex.getDefinition(cursor); + + final enumUsr = cursor.usr(); + final String enumName; + // Only set name using USR if the type is not Anonymous (i.e not inside + // any typedef and declared inplace inside another type). + if (clang.clang_Cursor_isAnonymous(cursor) == 0) { + // This gives the significant name, i.e name of the enum if defined or + // name of the first typedef declaration that refers to it. + enumName = enumUsr.split('@').last; + } else { + enumName = ''; + } + var nativeType = clang.clang_getEnumDeclIntegerType(cursor).toCodeGenType(); + // Change to unsigned type by default. + nativeType = signedToUnsignedNativeIntType[nativeType] ?? nativeType; + var hasNegativeEnumConstants = false; + + final decl = Declaration(usr: enumUsr, originalName: enumName); + if (enumName.isEmpty) { + _logger.fine('Saving anonymous enum.'); + final addedConstants = saveUnNamedEnum(cursor); + hasNegativeEnumConstants = + addedConstants.where((c) => c.rawValue.startsWith('-')).isNotEmpty; + } else if (ignoreFilter || shouldIncludeEnumClass(decl)) { + _logger.fine('++++ Adding Enum: ${cursor.completeStringRepr()}'); + enumClass = EnumClass( + usr: enumUsr, + dartDoc: getCursorDocComment(cursor), + originalName: enumName, + name: config.enumClassDecl.rename(decl), + nativeType: nativeType, + generateAsInt: config.enumShouldBeInt(decl), + objCBuiltInFunctions: objCBuiltInFunctions, + ); + cursor.visitChildren((clang_types.CXCursor child) { + try { + _logger.finest(' enumCursorVisitor: ${child.completeStringRepr()}'); + switch (clang.clang_getCursorKind(child)) { + case clang_types.CXCursorKind.CXCursor_EnumConstantDecl: + final enumIntValue = clang.clang_getEnumConstantDeclValue(child); + enumClass!.enumConstants.add( + EnumConstant( + dartDoc: getCursorDocComment( + child, + nesting.length + commentPrefix.length, + ), + originalName: child.spelling(), + name: config.enumClassDecl.renameMember( + decl, + child.spelling(), + ), + value: enumIntValue), + ); + if (enumIntValue < 0) { + hasNegativeEnumConstants = true; + } + break; + case clang_types.CXCursorKind.CXCursor_UnexposedAttr: + // Ignore. + break; + default: + _logger.fine('invalid enum constant'); + } + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + }); + } + + if (hasNegativeEnumConstants) { + // Change enum native type to signed type. + _logger.fine('For enum $enumUsr - using signed type for $nativeType : ' + '${unsignedToSignedNativeIntType[nativeType]}'); + nativeType = unsignedToSignedNativeIntType[nativeType] ?? nativeType; + enumClass?.nativeType = nativeType; + } + + return (enumClass, nativeType); +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/function_type_param_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/function_type_param_parser.dart new file mode 100644 index 0000000000..a1c53c6406 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/function_type_param_parser.dart @@ -0,0 +1,39 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../clang_bindings/clang_types.dart'; +import '../utils.dart'; + +/// This type holds the list of `ParmDecl` nodes of a function type declaration. +class FunctionTypeParams { + final List paramNames; + final Map params; + FunctionTypeParams() + : paramNames = [], + params = {}; +} + +/// Returns `ParmDecl` nodes of function pointer declaration +/// directly or indirectly pointed to by [cursor]. +FunctionTypeParams parseFunctionPointerParamNames(CXCursor cursor) { + final params = FunctionTypeParams(); + cursor.visitChildrenMayRecurse((child, parent) { + if (child.kind == CXCursorKind.CXCursor_ParmDecl) { + final spelling = child.spelling(); + if (spelling.isNotEmpty) { + params.paramNames.add(spelling); + params.params[spelling] = child; + return CXChildVisitResult.CXChildVisit_Continue; + } else { + // A parameter's spelling is empty, do not continue further traversal. + params.paramNames.clear(); + params.params.clear(); + return CXChildVisitResult.CXChildVisit_Break; + } + } + // The cursor itself may be a pointer etc.. + return CXChildVisitResult.CXChildVisit_Recurse; + }); + return params; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/functiondecl_parser.dart new file mode 100644 index 0000000000..517247aed2 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/functiondecl_parser.dart @@ -0,0 +1,133 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.functiondecl_parser'); + +/// Parses a function declaration. +List? parseFunctionDeclaration(clang_types.CXCursor cursor) { + /// Multiple values are since there may be more than one instance of the + /// same base C function with different variadic arguments. + final funcs = []; + + final funcUsr = cursor.usr(); + final funcName = cursor.spelling(); + final decl = Declaration(usr: funcUsr, originalName: funcName); + if (shouldIncludeFunc(decl)) { + _logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}'); + + final returnType = cursor.returnType().toCodeGenType(); + + final parameters = []; + var incompleteStructParameter = false; + var unimplementedParameterType = false; + final totalArgs = clang.clang_Cursor_getNumArguments(cursor); + for (var i = 0; i < totalArgs; i++) { + final paramCursor = clang.clang_Cursor_getArgument(cursor, i); + + _logger.finer('===== parameter: ${paramCursor.completeStringRepr()}'); + + final paramType = paramCursor.toCodeGenType(); + if (paramType.isIncompleteCompound) { + incompleteStructParameter = true; + } else if (paramType.baseType is UnimplementedType) { + _logger.finer('Unimplemented type: ${paramType.baseType}'); + unimplementedParameterType = true; + } + + final paramName = paramCursor.spelling(); + + /// If [paramName] is null or empty, its set to `arg$i` by code_generator. + parameters.add( + Parameter( + originalName: paramName, + name: config.functionDecl.renameMember(decl, paramName), + type: paramType, + ), + ); + } + + if (clang.clang_Cursor_isFunctionInlined(cursor) != 0 && + clang.clang_Cursor_getStorageClass(cursor) != + clang_types.CX_StorageClass.CX_SC_Extern) { + _logger.fine('---- Removed Function, reason: inline function: ' + '${cursor.completeStringRepr()}'); + _logger.warning( + "Skipped Function '$funcName', inline functions are not supported."); + // Returning empty so that [addToBindings] function excludes this. + return funcs; + } + + if (returnType.isIncompleteCompound || incompleteStructParameter) { + _logger.fine( + '---- Removed Function, reason: Incomplete struct pass/return by ' + 'value: ${cursor.completeStringRepr()}'); + _logger.warning( + "Skipped Function '$funcName', Incomplete struct pass/return by " + 'value not supported.'); + // Returning null so that [addToBindings] function excludes this. + return funcs; + } + + if (returnType.baseType is UnimplementedType || + unimplementedParameterType) { + _logger.fine('---- Removed Function, reason: unsupported return type or ' + 'parameter type: ${cursor.completeStringRepr()}'); + _logger.warning( + "Skipped Function '$funcName', function has unsupported return type " + 'or parameter type.'); + // Returning null so that [addToBindings] function excludes this. + return funcs; + } + + // Look for any annotations on the function. + final objCReturnsRetained = cursor + .hasChildWithKind(clang_types.CXCursorKind.CXCursor_NSReturnsRetained); + + // Initialized with a single value with no prefix and empty var args. + var varArgFunctions = [VarArgFunction('', [])]; + if (config.varArgFunctions.containsKey(funcName)) { + if (clang.clang_isFunctionTypeVariadic(cursor.type()) == 1) { + varArgFunctions = config.varArgFunctions[funcName]!; + } else { + _logger.warning('Skipping variadic-argument config for function ' + "'$funcName' since its not variadic."); + } + } + for (final vaFunc in varArgFunctions) { + funcs.add(Func( + dartDoc: getCursorDocComment( + cursor, + nesting.length + commentPrefix.length, + ), + usr: funcUsr + vaFunc.postfix, + name: config.functionDecl.rename(decl) + vaFunc.postfix, + originalName: funcName, + returnType: returnType, + parameters: parameters, + varArgParameters: + vaFunc.types.map((ta) => Parameter(type: ta, name: 'va')).toList(), + exposeSymbolAddress: + config.functionDecl.shouldIncludeSymbolAddress(decl), + exposeFunctionTypedefs: config.shouldExposeFunctionTypedef(decl), + isLeaf: config.isLeafFunction(decl), + objCReturnsRetained: objCReturnsRetained, + ffiNativeConfig: config.ffiNativeConfig, + )); + } + bindingsIndex.addFuncToSeen(funcUsr, funcs.last); + } else if (bindingsIndex.isSeenFunc(funcUsr)) { + funcs.add(bindingsIndex.getSeenFunc(funcUsr)!); + } + + return funcs; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/macro_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/macro_parser.dart new file mode 100644 index 0000000000..c2940dedd6 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/macro_parser.dart @@ -0,0 +1,325 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:path/path.dart' as p; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../../strings.dart' as strings; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.macro_parser'); + +/// Adds a macro definition to be parsed later. +void saveMacroDefinition(clang_types.CXCursor cursor) { + final macroUsr = cursor.usr(); + final originalMacroName = cursor.spelling(); + final decl = Declaration(usr: macroUsr, originalName: originalMacroName); + if (clang.clang_Cursor_isMacroBuiltin(cursor) == 0 && + clang.clang_Cursor_isMacroFunctionLike(cursor) == 0 && + shouldIncludeMacro(decl)) { + // Parse macro only if it's not builtin or function-like. + _logger.fine("++++ Saved Macro '$originalMacroName' for later : " + '${cursor.completeStringRepr()}'); + final prefixedName = config.macroDecl.rename(decl); + bindingsIndex.addMacroToSeen(macroUsr, prefixedName); + _saveMacro(prefixedName, macroUsr, originalMacroName); + } +} + +/// Saves a macro to be parsed later. +/// +/// Macros are parsed later in [parseSavedMacros()]. +void _saveMacro(String name, String usr, String originalName) { + savedMacros[name] = Macro(usr, originalName); +} + +/// Macros cannot be parsed directly, so we create a new `.hpp` file in which +/// they are assigned to a variable after which their value can be determined +/// by evaluating the value of the variable. +List parseSavedMacros() { + final bindings = []; + + if (savedMacros.keys.isEmpty) { + return bindings; + } + + // Create a file for parsing macros; + final file = createFileForMacros(); + + final index = clang.clang_createIndex(0, 0); + Pointer> clangCmdArgs = nullptr; + var cmdLen = 0; + + final compilerOpts = config.compilerOpts; + clangCmdArgs = createDynamicStringArray(compilerOpts); + + cmdLen = config.compilerOpts.length; + final tu = clang.clang_parseTranslationUnit( + index, + file.path.toNativeUint8().cast(), + clangCmdArgs.cast(), + cmdLen, + nullptr, + 0, + clang_types.CXTranslationUnit_Flags.CXTranslationUnit_KeepGoing, + ); + + if (tu == nullptr) { + _logger.severe('Unable to parse Macros.'); + } else { + logTuDiagnostics(tu, _logger, file.path, logLevel: Level.FINEST); + final rootCursor = clang.clang_getTranslationUnitCursor(tu); + rootCursor.visitChildren((child) => _macroVariablevisitor(child, bindings)); + } + + clang.clang_disposeTranslationUnit(tu); + clang.clang_disposeIndex(index); + // Delete the temp file created for macros. + file.deleteSync(); + + return bindings; +} + +/// Child visitor invoked on translationUnitCursor for parsing macroVariables. +void _macroVariablevisitor( + clang_types.CXCursor cursor, List bindings) { + Constant? constant; + try { + if (isFromGeneratedFile(cursor) && + _macroVarNames.contains(cursor.spelling()) && + cursor.kind == clang_types.CXCursorKind.CXCursor_VarDecl) { + final e = clang.clang_Cursor_Evaluate(cursor); + final k = clang.clang_EvalResult_getKind(e); + _logger.fine('macroVariablevisitor: ${cursor.completeStringRepr()}'); + + /// Get macro name, the variable name starts with '_'. + final macroName = MacroVariableString.decode(cursor.spelling()); + switch (k) { + case clang_types.CXEvalResultKind.CXEval_Int: + constant = Constant( + usr: savedMacros[macroName]!.usr, + originalName: savedMacros[macroName]!.originalName, + name: macroName, + rawType: 'int', + rawValue: clang.clang_EvalResult_getAsLongLong(e).toString(), + ); + break; + case clang_types.CXEvalResultKind.CXEval_Float: + constant = Constant( + usr: savedMacros[macroName]!.usr, + originalName: savedMacros[macroName]!.originalName, + name: macroName, + rawType: 'double', + rawValue: + _writeDoubleAsString(clang.clang_EvalResult_getAsDouble(e)), + ); + break; + case clang_types.CXEvalResultKind.CXEval_StrLiteral: + final rawValue = _getWrittenRepresentation( + macroName, + clang.clang_EvalResult_getAsStr(e), + ); + constant = Constant( + usr: savedMacros[macroName]!.usr, + originalName: savedMacros[macroName]!.originalName, + name: macroName, + rawType: 'String', + rawValue: "'$rawValue'", + ); + break; + } + clang.clang_EvalResult_dispose(e); + + if (constant != null) { + bindings.add(constant); + } + } + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } +} + +/// Returns true if cursor is from generated file. +bool isFromGeneratedFile(clang_types.CXCursor cursor) { + final s = cursor.sourceFileName(); + return p.basename(s) == _generatedFileBaseName; +} + +/// Base name of generated file. +String? _generatedFileBaseName; + +/// Generated macro variable names. +/// +/// Used to determine if macro should be included in bindings or not. +late Set _macroVarNames; + +/// Creates a temporary file for parsing macros in current directory. +File createFileForMacros() { + final fileNameBase = p.join(strings.tmpDir, 'temp_for_macros'); + final fileExt = 'hpp'; + + // Find a filename which doesn't already exist. + var file = File('$fileNameBase.$fileExt'); + var i = 0; + while (file.existsSync()) { + i++; + file = File('${fileNameBase}_$i.$fileExt'); + } + + // Create file. + file.createSync(); + + // Save generated name. + _generatedFileBaseName = p.basename(file.path); + + // Write file contents. + final sb = StringBuffer(); + for (final h in config.entryPoints) { + final fullHeaderPath = File(h.toFilePath()).absolute.path; + sb.writeln('#include "$fullHeaderPath"'); + } + + _macroVarNames = {}; + for (final prefixedMacroName in savedMacros.keys) { + // Write macro. + final macroVarName = MacroVariableString.encode(prefixedMacroName); + sb.writeln('auto $macroVarName = ' + '${savedMacros[prefixedMacroName]!.originalName};'); + // Add to _macroVarNames. + _macroVarNames.add(macroVarName); + } + final macroFileContent = sb.toString(); + // Log this generated file for debugging purpose. + // We use the finest log because this file may be very big. + _logger.finest('=====FILE FOR MACROS===='); + _logger.finest(macroFileContent); + _logger.finest('========================'); + + file.writeAsStringSync(macroFileContent); + return file; +} + +/// Deals with encoding/decoding name of the variable generated for a Macro. +class MacroVariableString { + static String encode(String s) { + return '_${s.length}_${s}_generated_macro_variable'; + } + + static String decode(String s) { + // Remove underscore. + s = s.substring(1); + final intReg = RegExp('[0-9]+'); + final lengthEnd = intReg.matchAsPrefix(s)!.end; + final len = int.parse(s.substring(0, lengthEnd)); + + // Name starts after an unerscore. + final nameStart = lengthEnd + 1; + return s.substring(nameStart, nameStart + len); + } +} + +/// Gets a written representation string of a C string. +/// +/// E.g- For a string "Hello\nWorld", The new line character is converted to \n. +/// Note: The string is considered to be Utf8, but is treated as Extended ASCII, +/// if the conversion fails. +String _getWrittenRepresentation(String macroName, Pointer strPtr) { + final sb = StringBuffer(); + try { + // Consider string to be Utf8 encoded by default. + sb.clear(); + // This throws a Format Exception if string isn't Utf8 so that we handle it + // in the catch block. + final result = strPtr.cast().toDartString(); + for (final s in result.runes) { + sb.write(_getWritableChar(s)); + } + } catch (e) { + // Handle string if it isn't Utf8. String is considered to be + // Extended ASCII in this case. + _logger.warning("Couldn't decode Macro string '$macroName' as Utf8, using " + 'ASCII instead.'); + sb.clear(); + // final length = strPtr.cast().length; + final charList = strPtr.toCharList(); + + for (final char in charList) { + sb.write(_getWritableChar(char, utf8: false)); + } + } + + return sb.toString(); +} + +/// Creates a writable char from [char] code. +/// +/// E.g- `\` is converted to `\\`. +String _getWritableChar(int char, {bool utf8 = true}) { + /// Handle control characters. + if (char >= 0 && char < 32 || char == 127) { + /// Handle these - `\b \t \n \v \f \r` as special cases. + switch (char) { + case 8: // \b + return r'\b'; + case 9: // \t + return r'\t'; + case 10: // \n + return r'\n'; + case 11: // \v + return r'\v'; + case 12: // \f + return r'\f'; + case 13: // \r + return r'\r'; + default: + final h = char.toRadixString(16).toUpperCase().padLeft(2, '0'); + return '\\x$h'; + } + } + + /// Handle characters - `$ ' \` these need to be escaped when writing to file. + switch (char) { + case 36: // $ + return r'\$'; + case 39: // ' + return r"\'"; + case 92: // \ + return r'\\'; + } + + /// In case encoding is not Utf8, we know all characters will fall in [0..255] + /// Print range [128..255] as `\xHH`. + if (!utf8) { + final h = char.toRadixString(16).toUpperCase().padLeft(2, '0'); + return '\\x$h'; + } + + /// In all other cases, simply convert to string. + return String.fromCharCode(char); +} + +/// Converts a double to a string, handling cases like Infinity and NaN. +String _writeDoubleAsString(double d) { + if (d.isFinite) { + return d.toString(); + } else { + // The only Non-Finite numbers are Infinity, NegativeInfinity and NaN. + if (d.isInfinite) { + return d.isNegative + ? strings.doubleNegativeInfinity + : strings.doubleInfinity; + } + return strings.doubleNaN; + } +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objc_block_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objc_block_parser.dart new file mode 100644 index 0000000000..b3ddaa4a5a --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objc_block_parser.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../../code_generator.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../utils.dart'; + +ObjCBlock parseObjCBlock(clang_types.CXType cxtype) { + final blk = clang.clang_getPointeeType(cxtype); + final returnType = clang.clang_getResultType(blk).toCodeGenType(); + final argTypes = []; + final numArgs = clang.clang_getNumArgTypes(blk); + for (var i = 0; i < numArgs; ++i) { + argTypes.add(clang.clang_getArgType(blk, i).toCodeGenType()); + } + return ObjCBlock( + returnType: returnType, + argTypes: argTypes, + ); +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart new file mode 100644 index 0000000000..6a59c1e462 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart @@ -0,0 +1,260 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.objcinterfacedecl_parser'); + +String applyModulePrefix(String name, String? module) => + module == null ? name : '$module.$name'; + +Type? parseObjCInterfaceDeclaration( + clang_types.CXCursor cursor, { + /// Option to ignore declaration filter (Useful in case of extracting + /// declarations when they are passed/returned by an included function.) + bool ignoreFilter = false, +}) { + final itfUsr = cursor.usr(); + final itfName = cursor.spelling(); + final decl = Declaration(usr: itfUsr, originalName: itfName); + if (!ignoreFilter && !shouldIncludeObjCInterface(decl)) { + return null; + } + + _logger.fine('++++ Adding ObjC interface: ' + 'Name: $itfName, ${cursor.completeStringRepr()}'); + + return ObjCInterface( + usr: itfUsr, + originalName: itfName, + name: config.objcInterfaces.rename(decl), + lookupName: applyModulePrefix(itfName, config.interfaceModule(decl)), + dartDoc: getCursorDocComment(cursor), + builtInFunctions: objCBuiltInFunctions, + ); +} + +void fillObjCInterfaceMethodsIfNeeded( + ObjCInterface itf, clang_types.CXCursor cursor) { + if (_isClassDeclaration(cursor)) { + // @class declarations are ObjC's way of forward declaring classes. In that + // case there's nothing to fill yet. + return; + } + + if (itf.filled) return; + itf.filled = true; // Break cycles. + + _logger.fine('++++ Filling ObjC interface: ' + 'Name: ${itf.originalName}, ${cursor.completeStringRepr()}'); + + _fillInterface(itf, cursor); + + _logger.fine('++++ Finished ObjC interface: ' + 'Name: ${itf.originalName}, ${cursor.completeStringRepr()}'); +} + +void _fillInterface(ObjCInterface itf, clang_types.CXCursor cursor) { + cursor.visitChildren((child) { + switch (child.kind) { + case clang_types.CXCursorKind.CXCursor_ObjCSuperClassRef: + _parseSuperType(child, itf); + break; + case clang_types.CXCursorKind.CXCursor_ObjCPropertyDecl: + _parseProperty(child, itf); + break; + case clang_types.CXCursorKind.CXCursor_ObjCInstanceMethodDecl: + case clang_types.CXCursorKind.CXCursor_ObjCClassMethodDecl: + _parseInterfaceMethod(child, itf); + break; + } + }); +} + +bool _isClassDeclaration(clang_types.CXCursor cursor) { + // It's a class declaration if it has no children other than ObjCClassRef. + var result = true; + cursor.visitChildrenMayBreak((child) { + if (child.kind == clang_types.CXCursorKind.CXCursor_ObjCClassRef) { + return true; + } + result = false; + return false; + }); + return result; +} + +void _parseSuperType(clang_types.CXCursor cursor, ObjCInterface itf) { + final superType = cursor.type().toCodeGenType(); + _logger.fine(' > Super type: ' + '$superType ${cursor.completeStringRepr()}'); + if (superType is ObjCInterface) { + itf.superType = superType; + } else { + _logger.severe( + 'Super type of $itf is $superType, which is not a valid interface.'); + } +} + +void _parseProperty(clang_types.CXCursor cursor, ObjCInterface itf) { + final fieldName = cursor.spelling(); + final fieldType = cursor.type().toCodeGenType(); + + if (fieldType.isIncompleteCompound) { + _logger.warning('Property "$fieldName" in instance "${itf.originalName}" ' + 'has incomplete type: $fieldType.'); + return; + } + + final dartDoc = getCursorDocComment(cursor); + + final propertyAttributes = + clang.clang_Cursor_getObjCPropertyAttributes(cursor, 0); + final isClassMethod = propertyAttributes & + clang_types.CXObjCPropertyAttrKind.CXObjCPropertyAttr_class > + 0; + final isReadOnly = propertyAttributes & + clang_types.CXObjCPropertyAttrKind.CXObjCPropertyAttr_readonly > + 0; + final isOptionalMethod = clang.clang_Cursor_isObjCOptional(cursor) != 0; + + final property = ObjCProperty(fieldName); + + _logger.fine(' > Property: ' + '$fieldType $fieldName ${cursor.completeStringRepr()}'); + + final getterName = + clang.clang_Cursor_getObjCPropertyGetterName(cursor).toStringAndDispose(); + final getter = ObjCMethod( + originalName: getterName, + property: property, + dartDoc: dartDoc, + kind: ObjCMethodKind.propertyGetter, + isClassMethod: isClassMethod, + isOptional: isOptionalMethod, + returnType: fieldType, + ); + itf.addMethod(getter); + + if (!isReadOnly) { + final setterName = clang + .clang_Cursor_getObjCPropertySetterName(cursor) + .toStringAndDispose(); + final setter = ObjCMethod( + originalName: setterName, + property: property, + dartDoc: dartDoc, + kind: ObjCMethodKind.propertySetter, + isClassMethod: isClassMethod, + isOptional: isOptionalMethod, + returnType: NativeType(SupportedNativeType.voidType)); + setter.params.add(ObjCMethodParam(fieldType, 'value')); + itf.addMethod(setter); + } +} + +void _parseInterfaceMethod(clang_types.CXCursor cursor, ObjCInterface itf) { + final method = parseObjCMethod(cursor, itf.originalName); + if (method != null) { + itf.addMethod(method); + } +} + +ObjCMethod? parseObjCMethod(clang_types.CXCursor cursor, String itfName) { + final methodName = cursor.spelling(); + final isClassMethod = + cursor.kind == clang_types.CXCursorKind.CXCursor_ObjCClassMethodDecl; + final isOptionalMethod = clang.clang_Cursor_isObjCOptional(cursor) != 0; + final returnType = clang.clang_getCursorResultType(cursor).toCodeGenType(); + if (returnType.isIncompleteCompound) { + _logger.warning('Method "$methodName" in instance ' + '"$itfName" has incomplete ' + 'return type: $returnType.'); + return null; + } + final method = ObjCMethod( + originalName: methodName, + dartDoc: getCursorDocComment(cursor), + kind: ObjCMethodKind.method, + isClassMethod: isClassMethod, + isOptional: isOptionalMethod, + returnType: returnType, + ); + _logger.fine(' > ${isClassMethod ? 'Class' : 'Instance'} method: ' + '${method.originalName} ${cursor.completeStringRepr()}'); + var hasError = false; + cursor.visitChildren((child) { + switch (child.kind) { + case clang_types.CXCursorKind.CXCursor_ParmDecl: + if (!_parseMethodParam(child, itfName, method)) { + hasError = true; + } + break; + case clang_types.CXCursorKind.CXCursor_NSReturnsRetained: + method.returnsRetained = true; + break; + default: + } + }); + return hasError ? null : method; +} + +bool _parseMethodParam( + clang_types.CXCursor cursor, String itfName, ObjCMethod method) { + final name = cursor.spelling(); + final type = cursor.type().toCodeGenType(); + if (type.isIncompleteCompound) { + _logger.warning('Method "${method.originalName}" in instance ' + '"$itfName" has incomplete ' + 'parameter type: $type.'); + return false; + } + _logger.fine( + ' >> Parameter: $type $name ${cursor.completeStringRepr()}'); + method.params.add(ObjCMethodParam(type, name)); + return true; +} + +BindingType? parseObjCCategoryDeclaration(clang_types.CXCursor cursor) { + // Categories add methods to an existing interface, so first we run a visitor + // to find the interface, then we fully parse that interface, then we run + // _fillInterface over the category to add its methods etc. Reusing the + // interface visitor relies on the fact that the structure of the category AST + // looks exactly the same as the interface AST, and that the category's + // interface is a different kind of node to the interface's super type (so is + // ignored by _fillInterface). + final name = cursor.spelling(); + _logger.fine('++++ Adding ObjC category: ' + 'Name: $name, ${cursor.completeStringRepr()}'); + + final itfCursor = + cursor.findChildWithKind(clang_types.CXCursorKind.CXCursor_ObjCClassRef); + if (itfCursor == null) { + _logger.severe('Category $name has no interface.'); + return null; + } + + // TODO(https://github.com/dart-lang/ffigen/issues/347): Currently any + // interface with a category bypasses the filters. + final itf = itfCursor.type().toCodeGenType(); + if (itf is! ObjCInterface) { + _logger.severe( + 'Interface of category $name is $itf, which is not a valid interface.'); + return null; + } + + _fillInterface(itf, cursor); + + _logger.fine('++++ Finished ObjC category: ' + 'Name: $name, ${cursor.completeStringRepr()}'); + + return itf; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objcprotocoldecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objcprotocoldecl_parser.dart new file mode 100644 index 0000000000..07cfe0b78a --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/objcprotocoldecl_parser.dart @@ -0,0 +1,74 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; +import 'objcinterfacedecl_parser.dart'; + +final _logger = Logger('ffigen.header_parser.objcprotocoldecl_parser'); + +ObjCProtocol? parseObjCProtocolDeclaration(clang_types.CXCursor cursor, + {bool ignoreFilter = false}) { + if (cursor.kind != clang_types.CXCursorKind.CXCursor_ObjCProtocolDecl) { + return null; + } + + final usr = cursor.usr(); + final cachedProtocol = bindingsIndex.getSeenObjCProtocol(usr); + if (cachedProtocol != null) { + return cachedProtocol; + } + + final name = cursor.spelling(); + + final decl = Declaration(usr: usr, originalName: name); + if (!ignoreFilter && !shouldIncludeObjCProtocol(decl)) { + return null; + } + + _logger.fine('++++ Adding ObjC protocol: ' + 'Name: $name, ${cursor.completeStringRepr()}'); + + final protocol = ObjCProtocol( + usr: usr, + originalName: name, + name: config.objcProtocols.rename(decl), + lookupName: applyModulePrefix(name, config.protocolModule(decl)), + dartDoc: getCursorDocComment(cursor), + builtInFunctions: objCBuiltInFunctions, + ); + + // Make sure to add the protocol to the index before parsing the AST, to break + // cycles. + bindingsIndex.addObjCProtocolToSeen(usr, protocol); + + cursor.visitChildren((child) { + switch (child.kind) { + case clang_types.CXCursorKind.CXCursor_ObjCProtocolRef: + final declCursor = clang.clang_getCursorDefinition(child); + _logger.fine( + ' > Super protocol: ${declCursor.completeStringRepr()}'); + final superProtocol = + parseObjCProtocolDeclaration(declCursor, ignoreFilter: true); + if (superProtocol != null) { + protocol.superProtocols.add(superProtocol); + } + break; + case clang_types.CXCursorKind.CXCursor_ObjCInstanceMethodDecl: + case clang_types.CXCursorKind.CXCursor_ObjCClassMethodDecl: + final method = parseObjCMethod(child, name); + if (method != null) { + protocol.addMethod(method); + } + break; + } + }); + return protocol; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart new file mode 100644 index 0000000000..c137026f29 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart @@ -0,0 +1,87 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../type_extractor/extractor.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.typedefdecl_parser'); + +/// Parses a typedef declaration. +/// +/// Notes: +/// - Pointer to Typedefs structs are skipped if the struct is seen. +/// - If there are multiple typedefs for a declaration (struct/enum), the last +/// seen name is used. +/// - Typerefs are completely ignored. +/// +/// Libclang marks them as following - +/// ```C +/// typedef struct A{ +/// int a +/// } B, *pB; // Typedef(s). +/// +/// typedef A D; // Typeref. +/// ``` +/// +/// Returns `null` if the typedef could not be generated or has been excluded +/// by the config. +Typealias? parseTypedefDeclaration( + clang_types.CXCursor cursor, { + bool pointerReference = false, +}) { + final typedefName = cursor.spelling(); + final typedefUsr = cursor.usr(); + final decl = Declaration(usr: typedefUsr, originalName: typedefName); + if (shouldIncludeTypealias(decl)) { + final ct = clang.clang_getTypedefDeclUnderlyingType(cursor); + final s = getCodeGenType(ct, + pointerReference: pointerReference, originalCursor: cursor); + + if (bindingsIndex.isSeenUnsupportedTypealias(typedefUsr)) { + // Do not process unsupported typealiases again. + } else if (s is UnimplementedType) { + _logger.fine("Skipped Typedef '$typedefName': " + 'Unimplemented type referred.'); + bindingsIndex.addUnsupportedTypealiasToSeen(typedefUsr); + } else if (s is Compound && s.originalName == typedefName) { + // Ignore typedef if it refers to a compound with the same original name. + bindingsIndex.addUnsupportedTypealiasToSeen(typedefUsr); + _logger.fine("Skipped Typedef '$typedefName': " + 'Name matches with referred struct/union.'); + } else if (s is EnumClass) { + // Ignore typedefs to Enum. + bindingsIndex.addUnsupportedTypealiasToSeen(typedefUsr); + _logger.fine("Skipped Typedef '$typedefName': typedef to enum."); + } else if (s is HandleType) { + // Ignore typedefs to Handle. + _logger.fine("Skipped Typedef '$typedefName': typedef to Dart Handle."); + bindingsIndex.addUnsupportedTypealiasToSeen(typedefUsr); + } else if (s is ConstantArray || s is IncompleteArray) { + // Ignore typedefs to Constant Array. + _logger.fine("Skipped Typedef '$typedefName': typedef to array."); + bindingsIndex.addUnsupportedTypealiasToSeen(typedefUsr); + } else if (s is BooleanType) { + // Ignore typedefs to Boolean. + _logger.fine("Skipped Typedef '$typedefName': typedef to bool."); + bindingsIndex.addUnsupportedTypealiasToSeen(typedefUsr); + } else { + // Create typealias. + return Typealias( + usr: typedefUsr, + originalName: typedefName, + name: config.typedefs.rename(decl), + type: s, + dartDoc: getCursorDocComment(cursor), + ); + } + } + return null; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart new file mode 100644 index 0000000000..0cf3d3fd9d --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.unnamed_enumdecl_parser'); + +/// Saves unnamed enums. +List saveUnNamedEnum(clang_types.CXCursor cursor) { + final addedConstants = []; + cursor.visitChildren((child) { + try { + _logger + .finest(' unnamedenumCursorVisitor: ${child.completeStringRepr()}'); + switch (clang.clang_getCursorKind(child)) { + case clang_types.CXCursorKind.CXCursor_EnumConstantDecl: + if (shouldIncludeUnnamedEnumConstant( + Declaration(usr: child.usr(), originalName: child.spelling()))) { + addedConstants.add(_addUnNamedEnumConstant(child)); + } + break; + case clang_types.CXCursorKind.CXCursor_UnexposedAttr: + // Ignore. + break; + default: + _logger.severe('Invalid enum constant.'); + } + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + }); + return addedConstants; +} + +/// Adds the parameter to func in functiondecl_parser.dart. +Constant _addUnNamedEnumConstant(clang_types.CXCursor cursor) { + _logger.fine( + '++++ Adding Constant from unnamed enum: ${cursor.completeStringRepr()}'); + final constant = Constant( + usr: cursor.usr(), + originalName: cursor.spelling(), + name: config.unnamedEnumConstants.rename( + Declaration(usr: cursor.usr(), originalName: cursor.spelling()), + ), + rawType: 'int', + rawValue: clang.clang_getEnumConstantDeclValue(cursor).toString(), + ); + bindingsIndex.addUnnamedEnumConstantToSeen(cursor.usr(), constant); + unnamedEnumConstants.add(constant); + return constant; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/var_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/var_parser.dart new file mode 100644 index 0000000000..9bc77ffa87 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/sub_parsers/var_parser.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../includer.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.var_parser'); + +/// Parses a global variable +Global? parseVarDeclaration(clang_types.CXCursor cursor) { + final name = cursor.spelling(); + final usr = cursor.usr(); + if (bindingsIndex.isSeenGlobalVar(usr)) { + return bindingsIndex.getSeenGlobalVar(usr); + } + final decl = Declaration(usr: usr, originalName: name); + if (!shouldIncludeGlobalVar(decl)) { + return null; + } + + _logger.fine('++++ Adding Global: ${cursor.completeStringRepr()}'); + + final cType = cursor.type(); + + final type = cType.toCodeGenType( + // Native fields can be arrays, but if we use the lookup based method of + // reading fields there's no way to turn a Pointer into an array. + supportNonInlineArray: config.ffiNativeConfig.enabled); + if (type.baseType is UnimplementedType) { + _logger.fine('---- Removed Global, reason: unsupported type: ' + '${cursor.completeStringRepr()}'); + _logger.warning("Skipped global variable '$name', type not supported."); + return null; + } + + final global = Global( + originalName: name, + name: config.globals.rename(decl), + usr: usr, + type: type, + dartDoc: getCursorDocComment(cursor), + exposeSymbolAddress: config.globals.shouldIncludeSymbolAddress(decl), + constant: cType.isConstQualified, + nativeConfig: config.ffiNativeConfig, + ); + bindingsIndex.addGlobalVarToSeen(usr, global); + + return global; +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/translation_unit_parser.dart b/pkgs/ffigenpad/lib/src/header_parser/translation_unit_parser.dart new file mode 100644 index 0000000000..b2f688eb97 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/translation_unit_parser.dart @@ -0,0 +1,98 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; + +import '../code_generator.dart'; +import 'clang_bindings/clang_types.dart' as clang_types; +import 'data.dart'; +import 'includer.dart'; +import 'sub_parsers/functiondecl_parser.dart'; +import 'sub_parsers/macro_parser.dart'; +import 'sub_parsers/objcinterfacedecl_parser.dart'; +import 'sub_parsers/objcprotocoldecl_parser.dart'; +import 'sub_parsers/typedefdecl_parser.dart'; +import 'sub_parsers/var_parser.dart'; +import 'type_extractor/extractor.dart'; +import 'utils.dart'; + +final _logger = Logger('ffigen.header_parser.translation_unit_parser'); + +/// Parses the translation unit and returns the generated bindings. +Set parseTranslationUnit(clang_types.CXCursor translationUnitCursor) { + final bindings = {}; + + translationUnitCursor.visitChildren((cursor) { + try { + if (shouldIncludeRootCursor(cursor.sourceFileName())) { + _logger.finest('rootCursorVisitor: ${cursor.completeStringRepr()}'); + switch (clang.clang_getCursorKind(cursor)) { + case clang_types.CXCursorKind.CXCursor_FunctionDecl: + bindings.addAll(parseFunctionDeclaration(cursor) as List); + break; + case clang_types.CXCursorKind.CXCursor_StructDecl: + case clang_types.CXCursorKind.CXCursor_UnionDecl: + case clang_types.CXCursorKind.CXCursor_EnumDecl: + case clang_types.CXCursorKind.CXCursor_ObjCInterfaceDecl: + addToBindings(bindings, _getCodeGenTypeFromCursor(cursor)); + break; + case clang_types.CXCursorKind.CXCursor_ObjCCategoryDecl: + addToBindings(bindings, parseObjCCategoryDeclaration(cursor)); + break; + case clang_types.CXCursorKind.CXCursor_ObjCProtocolDecl: + addToBindings(bindings, parseObjCProtocolDeclaration(cursor)); + break; + case clang_types.CXCursorKind.CXCursor_MacroDefinition: + saveMacroDefinition(cursor); + break; + case clang_types.CXCursorKind.CXCursor_VarDecl: + addToBindings(bindings, parseVarDeclaration(cursor)); + break; + case clang_types.CXCursorKind.CXCursor_TypedefDecl: + if (config.includeUnusedTypedefs) { + addToBindings(bindings, parseTypedefDeclaration(cursor)); + } + break; + default: + _logger.finer('rootCursorVisitor: CursorKind not implemented'); + } + } else { + _logger.finest( + 'rootCursorVisitor:(not included) ${cursor.completeStringRepr()}'); + } + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + }); + + return bindings; +} + +/// Adds to binding if unseen and not null. +void addToBindings(Set bindings, Binding? b) { + if (b != null) { + // This is a set, and hence will not have duplicates. + bindings.add(b); + } +} + +BindingType? _getCodeGenTypeFromCursor(clang_types.CXCursor cursor) { + final t = getCodeGenType(cursor.type(), ignoreFilter: false); + return t is BindingType ? t : null; +} + +/// Visits all cursors and builds a map of usr and [clang_types.CXCursor]. +void buildUsrCursorDefinitionMap(clang_types.CXCursor translationUnitCursor) { + translationUnitCursor.visitChildren((cursor) { + try { + cursorIndex.saveDefinition(cursor); + } catch (e, s) { + _logger.severe(e); + _logger.severe(s); + rethrow; + } + }); +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/type_extractor/cxtypekindmap.dart b/pkgs/ffigenpad/lib/src/header_parser/type_extractor/cxtypekindmap.dart new file mode 100644 index 0000000000..89f6c5f57e --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/type_extractor/cxtypekindmap.dart @@ -0,0 +1,54 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:collection/collection.dart'; +import '../../code_generator.dart' show SupportedNativeType, Type; +import '../../code_generator/imports.dart'; + +Map cxTypeKindToImportedTypes = { + 'void': voidType, + 'unsigned char': unsignedCharType, + 'signed char': signedCharType, + 'char': charType, + 'unsigned short': unsignedShortType, + 'short': shortType, + 'unsigned int': unsignedIntType, + 'int': intType, + 'unsigned long': unsignedLongType, + 'long': longType, + 'unsigned long long': unsignedLongLongType, + 'long long': longLongType, + 'float': floatType, + 'double': doubleType, +}; + +Map unsignedToSignedNativeIntType = Map.fromEntries( + cxTypeKindToImportedTypes.entries + .where((e) => e.key.contains('unsigned')) + .map((e) => MapEntry(e.value as Type, + cxTypeKindToImportedTypes[e.key.replaceFirst('unsigned ', '')]))); + +Map signedToUnsignedNativeIntType = Map.fromEntries( + cxTypeKindToImportedTypes.entries + .whereNot((e) => e.key.contains('unsigned')) + .map((e) => MapEntry( + e.value as Type, cxTypeKindToImportedTypes['unsigned ${e.key}']))); + +Map suportedTypedefToSuportedNativeType = { + 'uint8_t': SupportedNativeType.uint8, + 'uint16_t': SupportedNativeType.uint16, + 'uint32_t': SupportedNativeType.uint32, + 'uint64_t': SupportedNativeType.uint64, + 'int8_t': SupportedNativeType.int8, + 'int16_t': SupportedNativeType.int16, + 'int32_t': SupportedNativeType.int32, + 'int64_t': SupportedNativeType.int64, + 'intptr_t': SupportedNativeType.intPtr, + 'uintptr_t': SupportedNativeType.uintPtr, +}; + +Map supportedTypedefToImportedType = { + 'size_t': sizeType, + 'wchar_t': wCharType, +}; diff --git a/pkgs/ffigenpad/lib/src/header_parser/type_extractor/extractor.dart b/pkgs/ffigenpad/lib/src/header_parser/type_extractor/extractor.dart new file mode 100644 index 0000000000..9df103b666 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/type_extractor/extractor.dart @@ -0,0 +1,379 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Extracts code_gen Type from type. +library; + +import 'package:logging/logging.dart'; + +import '../../code_generator.dart'; +import '../../config_provider/config_types.dart'; +import '../../strings.dart' as strings; +import '../clang_bindings/clang_types.dart' as clang_types; +import '../data.dart'; +import '../sub_parsers/compounddecl_parser.dart'; +import '../sub_parsers/enumdecl_parser.dart'; +import '../sub_parsers/function_type_param_parser.dart'; +import '../sub_parsers/objc_block_parser.dart'; +import '../sub_parsers/objcinterfacedecl_parser.dart'; +import '../sub_parsers/typedefdecl_parser.dart'; +import '../type_extractor/cxtypekindmap.dart'; +import '../utils.dart'; + +final _logger = Logger('ffigen.header_parser.extractor'); +const _padding = ' '; + +const maxRecursionDepth = 5; + +/// Converts cxtype to a typestring code_generator can accept. +Type getCodeGenType( + clang_types.CXType cxtype, { + /// Option to ignore declaration filter (Useful in case of extracting + /// declarations when they are passed/returned by an included function.) + bool ignoreFilter = true, + + /// Passed on if a value was marked as a pointer before this one. + bool pointerReference = false, + + /// Cursor of the declaration, currently this is useful only to extract + /// parameter names in function types. + clang_types.CXCursor? originalCursor, + bool supportNonInlineArray = false, +}) { + _logger.fine('${_padding}getCodeGenType ${cxtype.completeStringRepr()}'); + + // Special case: Elaborated types just refer to another type. + if (cxtype.kind == clang_types.CXTypeKind.CXType_Elaborated) { + return getCodeGenType(clang.clang_Type_getNamedType(cxtype), + ignoreFilter: ignoreFilter, pointerReference: pointerReference); + } + + // These basic Objective C types skip the cache, and are conditional on the + // language flag. + if (config.language == Language.objc) { + switch (cxtype.kind) { + case clang_types.CXTypeKind.CXType_ObjCObjectPointer: + final pt = clang.clang_getPointeeType(cxtype); + final s = getCodeGenType(pt, + ignoreFilter: ignoreFilter, pointerReference: true); + if (s is ObjCInterface) { + return s; + } + return PointerType(objCObjectType); + case clang_types.CXTypeKind.CXType_ObjCId: + case clang_types.CXTypeKind.CXType_ObjCTypeParam: + case clang_types.CXTypeKind.CXType_ObjCClass: + return PointerType(objCObjectType); + case clang_types.CXTypeKind.CXType_ObjCSel: + return PointerType(objCSelType); + case clang_types.CXTypeKind.CXType_BlockPointer: + return parseObjCBlock(cxtype); + } + } + + // If the type has a declaration cursor, then use the BindingsIndex to break + // any potential cycles, and dedupe the Type. + final cursor = clang.clang_getTypeDeclaration(cxtype); + if (cursor.kind != clang_types.CXCursorKind.CXCursor_NoDeclFound) { + final usr = cursor.usr(); + var type = bindingsIndex.getSeenType(usr); + if (type == null) { + final result = + _createTypeFromCursor(cxtype, cursor, ignoreFilter, pointerReference); + type = result.type; + if (type == null) { + return UnimplementedType('${cxtype.kindSpelling()} not implemented'); + } + if (result.addToCache) { + bindingsIndex.addTypeToSeen(usr, type); + } + } + _fillFromCursorIfNeeded(type, cursor, ignoreFilter, pointerReference); + return type; + } + + // If the type doesn't have a declaration cursor, then it's a basic type such + // as int, or a simple derived type like a pointer, so doesn't need to be + // cached. + switch (cxtype.kind) { + case clang_types.CXTypeKind.CXType_Pointer: + final pt = clang.clang_getPointeeType(cxtype); + final s = getCodeGenType( + pt, + pointerReference: true, + originalCursor: originalCursor, + ); + + // Replace Pointer<_Dart_Handle> with Handle. + if (config.useDartHandle && + s is Compound && + s.compoundType == CompoundType.struct && + s.usr == strings.dartHandleUsr) { + return HandleType(); + } + return PointerType(s); + case clang_types.CXTypeKind.CXType_FunctionProto: + // Primarily used for function pointers. + return _extractFromFunctionProto(cxtype, cursor: originalCursor); + case clang_types.CXTypeKind.CXType_FunctionNoProto: + // Primarily used for function types with zero arguments. + return _extractFromFunctionProto(cxtype, cursor: originalCursor); + case clang_types.CXTypeKind.CXType_ConstantArray: + // Primarily used for constant array in struct members. + final numElements = clang.clang_getNumElements(cxtype); + final elementType = clang + .clang_getArrayElementType(cxtype) + .toCodeGenType(supportNonInlineArray: supportNonInlineArray); + // Handle numElements being 0 as an incomplete array. + return numElements == 0 + ? IncompleteArray(elementType) + : ConstantArray( + numElements, + elementType, + useArrayType: supportNonInlineArray, + ); + case clang_types.CXTypeKind.CXType_IncompleteArray: + // Primarily used for incomplete array in function parameters. + return IncompleteArray( + clang.clang_getArrayElementType(cxtype).toCodeGenType(), + ); + case clang_types.CXTypeKind.CXType_Bool: + return BooleanType(); + case clang_types.CXTypeKind.CXType_Attributed: + case clang_types.CXTypeKind.CXType_Unexposed: + final innerType = getCodeGenType( + clang.clang_Type_getModifiedType(cxtype), + ignoreFilter: ignoreFilter, + originalCursor: originalCursor, + ); + final isNullable = clang.clang_Type_getNullability(cxtype) == + clang_types.CXTypeNullabilityKind.CXTypeNullability_Nullable; + return isNullable && ObjCNullable.isSupported(innerType) + ? ObjCNullable(innerType) + : innerType; + default: + var typeSpellKey = + clang.clang_getTypeSpelling(cxtype).toStringAndDispose(); + if (typeSpellKey.startsWith('const ')) { + typeSpellKey = typeSpellKey.replaceFirst('const ', ''); + } + if (config.nativeTypeMappings.containsKey(typeSpellKey)) { + _logger.fine(' Type $typeSpellKey mapped from type-map.'); + return config.nativeTypeMappings[typeSpellKey]!; + } else if (cxTypeKindToImportedTypes.containsKey(typeSpellKey)) { + return cxTypeKindToImportedTypes[typeSpellKey]!; + } else { + _logger.fine('typedeclarationCursorVisitor: getCodeGenType: Type Not ' + 'Implemented, ${cxtype.completeStringRepr()}'); + return UnimplementedType('${cxtype.kindSpelling()} not implemented'); + } + } +} + +class _CreateTypeFromCursorResult { + final Type? type; + + // Flag that controls whether the type is added to the cache. It should not + // be added to the cache if it's just a fallback implementation, such as the + // int that is returned when an enum is excluded by the config. Later we might + // need to build the full enum type (eg if it's part of an included struct), + // and if we put the fallback int in the cache then the full enum will never + // be created. + final bool addToCache; + + _CreateTypeFromCursorResult(this.type, {this.addToCache = true}); +} + +_CreateTypeFromCursorResult _createTypeFromCursor(clang_types.CXType cxtype, + clang_types.CXCursor cursor, bool ignoreFilter, bool pointerReference) { + switch (cxtype.kind) { + case clang_types.CXTypeKind.CXType_Typedef: + final spelling = clang.clang_getTypedefName(cxtype).toStringAndDispose(); + if (config.language == Language.objc && spelling == strings.objcBOOL) { + // Objective C's BOOL type can be either bool or signed char, depending + // on the platform. We want to present a consistent API to the user, and + // those two types are ABI compatible, so just return bool regardless. + return _CreateTypeFromCursorResult(BooleanType()); + } + final usr = cursor.usr(); + if (config.typedefTypeMappings.containsKey(spelling)) { + _logger.fine(' Type $spelling mapped from type-map'); + return _CreateTypeFromCursorResult( + config.typedefTypeMappings[spelling]!); + } + if (config.usrTypeMappings.containsKey(usr)) { + _logger.fine(' Type $spelling mapped from usr'); + return _CreateTypeFromCursorResult(config.usrTypeMappings[usr]!); + } + // Get name from supported typedef name if config allows. + if (config.useSupportedTypedefs) { + if (suportedTypedefToSuportedNativeType.containsKey(spelling)) { + _logger.fine(' Type Mapped from supported typedef'); + return _CreateTypeFromCursorResult( + NativeType(suportedTypedefToSuportedNativeType[spelling]!)); + } else if (supportedTypedefToImportedType.containsKey(spelling)) { + _logger.fine(' Type Mapped from supported typedef'); + return _CreateTypeFromCursorResult( + supportedTypedefToImportedType[spelling]!); + } + } + + final typealias = + parseTypedefDeclaration(cursor, pointerReference: pointerReference); + + if (typealias != null) { + return _CreateTypeFromCursorResult(typealias); + } else { + // Use underlying type if typealias couldn't be created or if the user + // excluded this typedef. + final ct = clang.clang_getTypedefDeclUnderlyingType(cursor); + return _CreateTypeFromCursorResult( + getCodeGenType(ct, pointerReference: pointerReference), + addToCache: false); + } + case clang_types.CXTypeKind.CXType_Record: + return _CreateTypeFromCursorResult( + _extractfromRecord(cxtype, cursor, ignoreFilter, pointerReference)); + case clang_types.CXTypeKind.CXType_Enum: + final (enumClass, nativeType) = parseEnumDeclaration( + cursor, + ignoreFilter: ignoreFilter, + ); + if (enumClass == null) { + // Handle anonymous enum declarations within another declaration. + return _CreateTypeFromCursorResult(nativeType, addToCache: false); + } else { + return _CreateTypeFromCursorResult(enumClass); + } + case clang_types.CXTypeKind.CXType_ObjCInterface: + return _CreateTypeFromCursorResult( + parseObjCInterfaceDeclaration(cursor, ignoreFilter: ignoreFilter)); + default: + return _CreateTypeFromCursorResult( + UnimplementedType('Unknown type: ${cxtype.completeStringRepr()}'), + addToCache: false); + } +} + +void _fillFromCursorIfNeeded(Type? type, clang_types.CXCursor cursor, + bool ignoreFilter, bool pointerReference) { + if (type == null) return; + if (type is Compound) { + fillCompoundMembersIfNeeded(type, cursor, + ignoreFilter: ignoreFilter, pointerReference: pointerReference); + } else if (type is ObjCInterface) { + fillObjCInterfaceMethodsIfNeeded(type, cursor); + } +} + +Type? _extractfromRecord(clang_types.CXType cxtype, clang_types.CXCursor cursor, + bool ignoreFilter, bool pointerReference) { + _logger.fine('${_padding}_extractfromRecord: ${cursor.completeStringRepr()}'); + + final cursorKind = clang.clang_getCursorKind(cursor); + if (cursorKind == clang_types.CXCursorKind.CXCursor_StructDecl || + cursorKind == clang_types.CXCursorKind.CXCursor_UnionDecl) { + final declSpelling = cursor.spelling(); + final declUsr = cursor.usr(); + + // Set includer functions according to compoundType. + final CompoundType compoundType; + final Map compoundTypeMappings; + + switch (cursorKind) { + case clang_types.CXCursorKind.CXCursor_StructDecl: + compoundType = CompoundType.struct; + compoundTypeMappings = config.structTypeMappings; + break; + case clang_types.CXCursorKind.CXCursor_UnionDecl: + compoundType = CompoundType.union; + compoundTypeMappings = config.unionTypeMappings; + break; + default: + throw Exception('Unhandled compound type cursorkind.'); + } + + // Also add a struct binding, if its unseen. + if (compoundTypeMappings.containsKey(declSpelling)) { + _logger.fine(' Type Mapped from type-map'); + return compoundTypeMappings[declSpelling]!; + } else if (config.usrTypeMappings.containsKey(declUsr)) { + _logger.fine(' Type Mapped from usr'); + return config.usrTypeMappings[declUsr]!; + } else { + final struct = parseCompoundDeclaration( + cursor, + compoundType, + ignoreFilter: ignoreFilter, + pointerReference: pointerReference, + ); + return struct; + } + } + _logger.fine('typedeclarationCursorVisitor: _extractfromRecord: ' + 'Not Implemented, ${cursor.completeStringRepr()}'); + return UnimplementedType('${cxtype.kindSpelling()} not implemented'); +} + +// Used for function pointer arguments. +Type _extractFromFunctionProto(clang_types.CXType cxtype, + {clang_types.CXCursor? cursor}) { + final parameters = []; + final totalArgs = clang.clang_getNumArgTypes(cxtype); + for (var i = 0; i < totalArgs; i++) { + final t = clang.clang_getArgType(cxtype, i); + final pt = t.toCodeGenType(); + + if (pt.isIncompleteCompound) { + return UnimplementedType( + 'Incomplete Struct by value in function parameter.'); + } else if (pt.baseType is UnimplementedType) { + return UnimplementedType('Function parameter has an unsupported type.'); + } + + parameters.add( + Parameter(name: '', type: pt), + ); + } + + final functionType = FunctionType( + parameters: parameters, + returnType: clang.clang_getResultType(cxtype).toCodeGenType(), + ); + _parseAndMergeParamNames(functionType, cursor, maxRecursionDepth); + return NativeFunc(functionType); +} + +void _parseAndMergeParamNames( + FunctionType functionType, + clang_types.CXCursor? cursor, + int recursionDepth, +) { + if (cursor == null) { + return; + } + if (recursionDepth == 0) { + final cursorRepr = cursor.completeStringRepr(); + _logger.warning('Recursion depth exceeded when merging function parameters.' + ' Last cursor encountered was $cursorRepr'); + return; + } + + final paramsInfo = parseFunctionPointerParamNames(cursor); + functionType.addParameterNames(paramsInfo.paramNames); + + for (final param in functionType.parameters) { + final paramRealType = param.type.typealiasType; + final paramBaseType = paramRealType.baseType.typealiasType; + if (paramBaseType is NativeFunc && param.name.isNotEmpty) { + final paramFunctionType = paramBaseType.type; + final paramCursor = paramsInfo.params[param.name]; + _parseAndMergeParamNames( + paramFunctionType, + paramCursor, + recursionDepth - 1, + ); + } + } +} diff --git a/pkgs/ffigenpad/lib/src/header_parser/utils.dart b/pkgs/ffigenpad/lib/src/header_parser/utils.dart new file mode 100644 index 0000000000..e10a2c7271 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/header_parser/utils.dart @@ -0,0 +1,516 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:convert' as convert; +import 'dart:ffi'; +import 'dart:js_interop'; + +import 'package:ffigen/src/header_parser/utils.dart' + show commentPrefix, removeRawCommentMarkups; +import 'package:logging/logging.dart'; + +import '../code_generator.dart'; +import '../config_provider/config_types.dart'; +import 'calloc.dart'; +import 'clang_bindings/clang_types.dart' as clang_types; +import 'data.dart'; +import 'type_extractor/extractor.dart'; + +export 'package:ffigen/src/header_parser/utils.dart' + show + IncrementalNamer, + Macro, + Stack, + commentPrefix, + nesting, + removeRawCommentMarkups; + +final _logger = Logger('ffigen.header_parser.utils'); + +const exceptionalVisitorReturn = + clang_types.CXChildVisitResult.CXChildVisit_Break; + +/// Logs the warnings/errors returned by clang for a translation unit. +void logTuDiagnostics( + clang_types.CXTranslationUnit tu, Logger logger, String header, + {Level logLevel = Level.SEVERE}) { + final total = clang.clang_getNumDiagnostics(tu); + if (total == 0) { + return; + } + logger.log(logLevel, 'Header $header: Total errors/warnings: $total.'); + for (var i = 0; i < total; i++) { + final diag = clang.clang_getDiagnostic(tu, i); + if (clang.clang_getDiagnosticSeverity(diag) >= + clang_types.CXDiagnosticSeverity.CXDiagnostic_Warning) { + hasSourceErrors = true; + } + final cxstring = clang.clang_formatDiagnostic( + diag, + clang_types + .CXDiagnosticDisplayOptions.CXDiagnostic_DisplaySourceLocation | + clang_types.CXDiagnosticDisplayOptions.CXDiagnostic_DisplayColumn | + clang_types + .CXDiagnosticDisplayOptions.CXDiagnostic_DisplayCategoryName, + ); + logger.log(logLevel, ' ${cxstring.toStringAndDispose()}'); + clang.clang_disposeDiagnostic(diag); + } +} + +extension CXSourceRangeExt on clang_types.CXSourceRange { + void dispose() { + calloc.free(this); + } +} + +extension CXCursorExt on clang_types.CXCursor { + String usr() { + var res = clang.clang_getCursorUSR(this).toStringAndDispose(); + if (isAnonymousRecordDecl()) { + res += '@offset:${sourceFileOffset()}'; + } + return res; + } + + /// Returns the kind int from [clang_types.CXCursorKind]. + int get kind { + return clang.clang_getCursorKind(this); + } + + /// Name of the cursor (E.g function name, Struct name, Parameter name). + String spelling() { + return clang.clang_getCursorSpelling(this).toStringAndDispose(); + } + + /// Spelling for a [clang_types.CXCursorKind], useful for debug purposes. + String kindSpelling() { + return clang + .clang_getCursorKindSpelling(clang.clang_getCursorKind(this)) + .toStringAndDispose(); + } + + /// Get code_gen [Type] representation of [clang_types.CXType]. + Type toCodeGenType() { + return getCodeGenType(type(), originalCursor: this); + } + + /// for debug: returns [spelling] [kind] [kindSpelling] type typeSpelling. + String completeStringRepr() { + final cxtype = type(); + final s = '(Cursor) spelling: ${spelling()}, kind: $kind, ' + 'kindSpelling: ${kindSpelling()}, type: ${cxtype.kind}, ' + 'typeSpelling: ${cxtype.spelling()}, usr: ${usr()}'; + return s; + } + + /// Type associated with the pointer if any. Type will have kind + /// [clang.CXTypeKind.CXType_Invalid] otherwise. + clang_types.CXType type() { + return clang.clang_getCursorType(this); + } + + /// Determine whether the given cursor + /// represents an anonymous record declaration. + bool isAnonymousRecordDecl() { + return clang.clang_Cursor_isAnonymousRecordDecl(this) == 1; + } + + /// Only valid for [clang.CXCursorKind.CXCursor_FunctionDecl]. Type will have + /// kind [clang.CXTypeKind.CXType_Invalid] otherwise. + clang_types.CXType returnType() { + return clang.clang_getResultType(type()); + } + + /// Returns the file name of the file that the cursor is inside. + String sourceFileName() { + final cxsource = clang.clang_getCursorLocation(this); + final cxfilePtr = calloc(); + + // Puts the values in these pointers. + clang.clang_getFileLocation(cxsource, cxfilePtr, nullptr, nullptr, nullptr); + final s = clang.clang_getFileName(cxfilePtr.value).toStringAndDispose(); + + calloc.free(cxfilePtr); + return s; + } + + int sourceFileOffset() { + final cxsource = clang.clang_getCursorLocation(this); + final cxOffset = calloc(); + + // Puts the values in these pointers. + clang.clang_getFileLocation(cxsource, nullptr, nullptr, nullptr, cxOffset); + final offset = cxOffset.value; + calloc.free(cxOffset); + return offset; + } + + /// Returns whether the file that the cursor is inside is a system header. + bool isInSystemHeader() { + final location = clang.clang_getCursorLocation(this); + return clang.clang_Location_isInSystemHeader(location) != 0; + } + + /// Visits all the direct children of this cursor. + /// + /// [callback] is called with the child cursor. The iteration continues until + /// completion. The only way it can be interrupted is if the [callback] + /// throws, in which case this method also throws. + void visitChildren(void Function(clang_types.CXCursor child) callback) { + final completed = visitChildrenMayBreak((clang_types.CXCursor child) { + callback(child); + return true; + }); + if (!completed) { + throw Exception('Exception thrown in a dart function called via C, ' + 'use --verbose to see more details'); + } + } + + /// Visits all the direct children of this cursor. + /// + /// [callback] is called with the child cursor. If [callback] returns true, + /// the iteration will continue. Otherwise, if [callback] returns false, the + /// iteration will stop. + /// + /// Returns whether the iteration completed. + bool visitChildrenMayBreak( + bool Function(clang_types.CXCursor child) callback) => + visitChildrenMayRecurse( + (clang_types.CXCursor child, clang_types.CXCursor parent) => + callback(child) + ? clang_types.CXChildVisitResult.CXChildVisit_Continue + : clang_types.CXChildVisitResult.CXChildVisit_Break); + + /// Visits all the direct children of this cursor. + /// + /// [callback] is called with the child cursor and parent cursor. If + /// [callback] returns CXChildVisit_Continue, the iteration continues. If it + /// returns CXChildVisit_Break the iteration stops. If it returns + /// CXChildVisit_Recurse, the iteration recurses into the node. + /// + /// Returns whether the iteration completed. + bool visitChildrenMayRecurse( + int Function(clang_types.CXCursor child, clang_types.CXCursor parent) + callback) { + int visitorWrapper(int childAddress, int parentAddress, int _) { + final child = clang_types.CXCursor.fromAddress(childAddress); + final parent = clang_types.CXCursor.fromAddress(parentAddress); + return callback(child, parent); + } + + final visitorIndex = addFunction(visitorWrapper.toJS, 'iiii'); + final result = clang.clang_visitChildren(this, visitorIndex); + removeFunction(visitorIndex); + return result == 0; + } + + /// Returns the first child with the given CXCursorKind, or null if there + /// isn't one. + clang_types.CXCursor? findChildWithKind(int kind) { + clang_types.CXCursor? result; + visitChildrenMayBreak((child) { + if (child.kind == kind) { + result = child; + return false; + } + return true; + }); + return result; + } + + /// Returns whether there is a child with the given CXCursorKind. + bool hasChildWithKind(int kind) => findChildWithKind(kind) != null; + + /// Recursively print the AST, for debugging. + void printAst([int maxDepth = 3]) => _printAst(maxDepth, 0); + void _printAst(int maxDepth, int depth) { + if (depth > maxDepth) { + return; + } + print((' ' * depth) + completeStringRepr()); + visitChildren((child) => child._printAst(maxDepth, depth + 1)); + } +} + +/// Stores the [clang_types.CXSourceRange] of the last comment. +clang_types.CXSourceRange? lastCommentRange; + +/// Returns a cursor's associated comment. +/// +/// The given string is wrapped at line width = 80 - [indent]. The [indent] is +/// [commentPrefix].length by default because a comment starts with +/// [commentPrefix]. +String? getCursorDocComment(clang_types.CXCursor cursor, + [int indent = commentPrefix.length]) { + String? formattedDocComment; + final currentCommentRange = clang.clang_Cursor_getCommentRange(cursor); + + // See if this comment and the last comment both point to the same source + // range. + if (lastCommentRange != null && + clang.clang_equalRanges(lastCommentRange!, currentCommentRange) != 0) { + formattedDocComment = null; + } else { + switch (config.commentType.length) { + case CommentLength.full: + formattedDocComment = removeRawCommentMarkups( + clang.clang_Cursor_getRawCommentText(cursor).toStringAndDispose()); + break; + case CommentLength.brief: + formattedDocComment = _wrapNoNewLineString( + clang.clang_Cursor_getBriefCommentText(cursor).toStringAndDispose(), + 80 - indent); + break; + default: + formattedDocComment = null; + } + } + lastCommentRange = currentCommentRange; + return formattedDocComment; +} + +/// Wraps [string] according to given [lineWidth]. +/// +/// Wrapping will work properly only when String has no new lines +/// characters(\n). +String? _wrapNoNewLineString(String? string, int lineWidth) { + if (string == null || string.isEmpty) { + return null; + } + final sb = StringBuffer(); + + final words = string.split(' '); + + sb.write(words[0]); + var trackLineWidth = words[0].length; + for (var i = 1; i < words.length; i++) { + final word = words[i]; + if (trackLineWidth + word.length < lineWidth) { + sb.write(' '); + sb.write(word); + trackLineWidth += word.length + 1; + } else { + sb.write('\n'); + sb.write(word); + trackLineWidth = word.length; + } + } + return sb.toString(); +} + +extension CXTypeExt on clang_types.CXType { + /// Get code_gen [Type] representation of [clang_types.CXType]. + Type toCodeGenType({bool supportNonInlineArray = false}) { + return getCodeGenType(this, supportNonInlineArray: supportNonInlineArray); + } + + /// Spelling for a [clang_types.CXTypeKind], useful for debug purposes. + String spelling() { + return clang.clang_getTypeSpelling(this).toStringAndDispose(); + } + + /// Returns the typeKind int from [clang_types.CXTypeKind]. + int get kind { + return clang.getCXTypeKind(this); + } + + String kindSpelling() { + return clang.clang_getTypeKindSpelling(kind).toStringAndDispose(); + } + + int alignment() { + return clang.clang_Type_getAlignOf(this); + } + + /// For debugging: returns [spelling] [kind] [kindSpelling]. + String completeStringRepr() { + final s = '(Type) spelling: ${spelling()}, kind: $kind, ' + 'kindSpelling: ${kindSpelling()}'; + return s; + } + + bool get isConstQualified { + return clang.clang_isConstQualifiedType(this) != 0; + } +} + +extension CXStringExt on clang_types.CXString { + /// Convert CXString to a Dart string + /// + /// Make sure to dispose CXstring using dispose method, or use the + /// [toStringAndDispose] method. + String string() { + final cstring = clang.clang_getCString(this); + if (cstring != nullptr) { + return cstring.toDartString(); + } else { + return ''; + } + } + + /// Converts CXString to dart string and disposes CXString. + String toStringAndDispose() { + // Note: clang_getCString_wrap returns a const char *, calling free will + // result in error. + final s = string(); + dispose(); + return s; + } + + void dispose() { + clang.clang_disposeString(this); + } +} + +extension UTF on Pointer { + int get length { + var output = 0; + while (this[output] != 0) { + output++; + } + return output; + } + + List toCharList() { + return List.generate( + length, + (int index) => this[index], + growable: false, + ); + } + + String toDartString() { + // TODO: why do we need allowMalformed as true? + return convert.utf8.decode(toCharList(), allowMalformed: true); + } +} + +extension StringUtf8Pointer on String { + /// Converts string into an array of bytes and allocates it in WASM memory + Pointer toNativeUint8() { + final units = convert.utf8.encode(this); + final result = calloc(units.length + 1); + for (var i = 0; i < units.length; i++) { + result[i] = units[i]; + } + result[units.length] = 0; + return result; + } +} + +/// Converts a [List<String>] to [Pointer<Pointer<Uint8>>]. +Pointer> createDynamicStringArray(List list) { + final nativeCmdArgs = calloc>(list.length); + + for (var i = 0; i < list.length; i++) { + nativeCmdArgs[i] = list[i].toNativeUint8(); + } + + return nativeCmdArgs; +} + +extension DynamicCStringArray on Pointer> { + // Properly disposes a Pointer, ensure that sure length is + // correct. + void dispose(int length) { + for (var i = 0; i < length; i++) { + calloc.free(this[i]); + } + calloc.free(this); + } +} + +/// Tracks if a binding is 'seen' or not. +class BindingsIndex { + // Tracks if bindings are already seen, Map key is USR obtained from libclang. + final Map _declaredTypes = {}; + final Map _functions = {}; + final Map _unnamedEnumConstants = {}; + final Map _macros = {}; + final Map _globals = {}; + final Map _objcBlocks = {}; + final Map _objcProtocols = {}; + + /// Contains usr for typedefs which cannot be generated. + final Set _unsupportedTypealiases = {}; + + /// Index for headers. + final Map _headerCache = {}; + + bool isSeenType(String usr) => _declaredTypes.containsKey(usr); + void addTypeToSeen(String usr, Type type) => _declaredTypes[usr] = type; + Type? getSeenType(String usr) => _declaredTypes[usr]; + bool isSeenFunc(String usr) => _functions.containsKey(usr); + void addFuncToSeen(String usr, Func func) => _functions[usr] = func; + Func? getSeenFunc(String usr) => _functions[usr]; + bool isSeenUnnamedEnumConstant(String usr) => + _unnamedEnumConstants.containsKey(usr); + void addUnnamedEnumConstantToSeen(String usr, Constant enumConstant) => + _unnamedEnumConstants[usr] = enumConstant; + Constant? getSeenUnnamedEnumConstant(String usr) => + _unnamedEnumConstants[usr]; + bool isSeenGlobalVar(String usr) => _globals.containsKey(usr); + void addGlobalVarToSeen(String usr, Global global) => _globals[usr] = global; + Global? getSeenGlobalVar(String usr) => _globals[usr]; + bool isSeenMacro(String usr) => _macros.containsKey(usr); + void addMacroToSeen(String usr, String macro) => _macros[usr] = macro; + String? getSeenMacro(String usr) => _macros[usr]; + bool isSeenUnsupportedTypealias(String usr) => + _unsupportedTypealiases.contains(usr); + void addUnsupportedTypealiasToSeen(String usr) => + _unsupportedTypealiases.add(usr); + bool isSeenHeader(String source) => _headerCache.containsKey(source); + void addHeaderToSeen(String source, bool includeStatus) => + _headerCache[source] = includeStatus; + bool? getSeenHeaderStatus(String source) => _headerCache[source]; + void addObjCBlockToSeen(String key, ObjCBlock t) => _objcBlocks[key] = t; + ObjCBlock? getSeenObjCBlock(String key) => _objcBlocks[key]; + void addObjCProtocolToSeen(String usr, ObjCProtocol t) => + _objcProtocols[usr] = t; + ObjCProtocol? getSeenObjCProtocol(String usr) => _objcProtocols[usr]; + bool isSeenObjCProtocol(String usr) => _objcProtocols.containsKey(usr); +} + +class CursorIndex { + final _usrCursorDefinition = {}; + + /// Returns the Cursor definition (if found) or itself. + clang_types.CXCursor getDefinition(clang_types.CXCursor cursor) { + final cursorDefinition = clang.clang_getCursorDefinition(cursor); + if (clang.clang_Cursor_isNull(cursorDefinition) == 0) { + return cursorDefinition; + } else { + final usr = cursor.usr(); + if (_usrCursorDefinition.containsKey(usr)) { + return _usrCursorDefinition[cursor.usr()]!; + } else { + _logger.warning('No definition found for declaration -' + '${cursor.completeStringRepr()}'); + return cursor; + } + } + } + + /// Saves cursor definition based on its kind. + void saveDefinition(clang_types.CXCursor cursor) { + switch (cursor.kind) { + case clang_types.CXCursorKind.CXCursor_StructDecl: + case clang_types.CXCursorKind.CXCursor_UnionDecl: + case clang_types.CXCursorKind.CXCursor_EnumDecl: + final usr = cursor.usr(); + if (!_usrCursorDefinition.containsKey(usr)) { + final cursorDefinition = clang.clang_getCursorDefinition(cursor); + if (clang.clang_Cursor_isNull(cursorDefinition) == 0) { + _usrCursorDefinition[usr] = cursorDefinition; + } else { + _logger.finest( + 'Missing cursor definition in current translation unit: ' + '${cursor.completeStringRepr()}'); + } + } + } + } +} diff --git a/pkgs/ffigenpad/lib/src/strings.dart b/pkgs/ffigenpad/lib/src/strings.dart new file mode 100644 index 0000000000..cc430494c4 --- /dev/null +++ b/pkgs/ffigenpad/lib/src/strings.dart @@ -0,0 +1,28 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:ffigen/src/strings.dart'; +import 'header_parser/clang_bindings/clang_types.dart' as clang; + +export 'package:ffigen/src/strings.dart'; + +final sizemapNativeMapping = { + sChar: clang.CXTypeKind.CXType_SChar, + uChar: clang.CXTypeKind.CXType_UChar, + short: clang.CXTypeKind.CXType_Short, + uShort: clang.CXTypeKind.CXType_UShort, + intType: clang.CXTypeKind.CXType_Int, + uInt: clang.CXTypeKind.CXType_UInt, + long: clang.CXTypeKind.CXType_Long, + uLong: clang.CXTypeKind.CXType_ULong, + longLong: clang.CXTypeKind.CXType_LongLong, + uLongLong: clang.CXTypeKind.CXType_ULongLong, + enumType: clang.CXTypeKind.CXType_Enum +}; + +/// A path to a unique temporary directory that should be used for files meant +/// to be discarded after the current execution is finished. +String get tmpDir { + return '/tmp'; +} diff --git a/pkgs/ffigenpad/pubspec.lock b/pkgs/ffigenpad/pubspec.lock new file mode 100644 index 0000000000..bf86623819 --- /dev/null +++ b/pkgs/ffigenpad/pubspec.lock @@ -0,0 +1,457 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77" + url: "https://pub.dev" + source: hosted + version: "73.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a" + url: "https://pub.dev" + source: hosted + version: "6.8.0" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + collection: + dependency: "direct main" + description: + name: collection + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + url: "https://pub.dev" + source: hosted + version: "1.19.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "576aaab8b1abdd452e0f656c3e73da9ead9d7880e15bdc494189d9c1a1baf0db" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + url: "https://pub.dev" + source: hosted + version: "3.0.5" + dart_flutter_team_lints: + dependency: "direct dev" + description: + name: dart_flutter_team_lints + sha256: "084338b81e33917c7c180da7aaccb59a5e5d16ece372465c6a2b930841b9009a" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + dart_style: + dependency: "direct main" + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + ffigen: + dependency: "direct main" + description: + path: "../ffigen" + relative: true + source: path + version: "14.0.0-wip" + file: + dependency: "direct main" + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: "direct main" + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + logging: + dependency: "direct main" + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: "direct main" + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + quiver: + dependency: "direct main" + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" + url: "https://pub.dev" + source: hosted + version: "1.25.8" + test_api: + dependency: transitive + description: + name: test_api + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + url: "https://pub.dev" + source: hosted + version: "0.7.3" + test_core: + dependency: transitive + description: + name: test_core + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" + url: "https://pub.dev" + source: hosted + version: "0.6.5" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + yaml_edit: + dependency: "direct main" + description: + name: yaml_edit + sha256: e9c1a3543d2da0db3e90270dbb1e4eebc985ee5e3ffe468d83224472b2194a5f + url: "https://pub.dev" + source: hosted + version: "2.2.1" +sdks: + dart: ">=3.5.0 <4.0.0" diff --git a/pkgs/ffigenpad/pubspec.yaml b/pkgs/ffigenpad/pubspec.yaml new file mode 100644 index 0000000000..1320b1c782 --- /dev/null +++ b/pkgs/ffigenpad/pubspec.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +name: ffigenpad +description: A web app thats outputs dart:ffi bindings generated by ffigen entirely on the client. +version: 0.1.0 +repository: https://github.com/dart-lang/native/tree/main/pkgs/ffigenpad +publish_to: none +environment: + sdk: ^3.5.1 + +# Add regular dependencies here. +dependencies: + collection: ^1.19.0 + dart_style: ^2.3.6 + ffigen: + path: ../ffigen + file: ^7.0.0 + glob: ^2.1.2 + logging: ^1.2.0 + package_config: ^2.1.0 + path: ^1.9.0 + quiver: ^3.0.0 + yaml: ^3.1.2 + yaml_edit: ^2.2.1 + +dev_dependencies: + dart_flutter_team_lints: ^3.2.0 + lints: ^4.0.0 + test: ^1.24.0 diff --git a/pkgs/ffigenpad/third_party/libclang/.gitignore b/pkgs/ffigenpad/third_party/libclang/.gitignore new file mode 100644 index 0000000000..40ba0fc6c1 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/.gitignore @@ -0,0 +1 @@ +llvm-project \ No newline at end of file diff --git a/pkgs/ffigenpad/third_party/libclang/README.md b/pkgs/ffigenpad/third_party/libclang/README.md new file mode 100644 index 0000000000..2056f69a52 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/README.md @@ -0,0 +1,19 @@ +# Overview + +## Contents + +### wrapper.c + +Contains wrapper functions that interact with pointers because directly passing around structs in dart2wasm is currently not possible. + +### libclang.exports + +List of functions `bin/libclang.wasm` is made to export by emscripten. + +### include/ + +Contains header files for libclang that are used by ffigen to generate `dart:ffi` bindings. + +### llvm-project/ + +Contains precompiled archive files for building libclang, downloaded using `tool/setup.dart`. diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/BuildSystem.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/BuildSystem.h new file mode 100644 index 0000000000..57e16af20a --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/BuildSystem.h @@ -0,0 +1,153 @@ +/*==-- clang-c/BuildSystem.h - Utilities for use by build systems -*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides various utilities for use by build systems. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_BUILDSYSTEM_H +#define LLVM_CLANG_C_BUILDSYSTEM_H + +#include "clang-c/CXErrorCode.h" +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup BUILD_SYSTEM Build system utilities + * @{ + */ + +/** + * Return the timestamp for use with Clang's + * \c -fbuild-session-timestamp= option. + */ +CINDEX_LINKAGE unsigned long long clang_getBuildSessionTimestamp(void); + +/** + * Object encapsulating information about overlaying virtual + * file/directories over the real file system. + */ +typedef struct CXVirtualFileOverlayImpl *CXVirtualFileOverlay; + +/** + * Create a \c CXVirtualFileOverlay object. + * Must be disposed with \c clang_VirtualFileOverlay_dispose(). + * + * \param options is reserved, always pass 0. + */ +CINDEX_LINKAGE CXVirtualFileOverlay +clang_VirtualFileOverlay_create(unsigned options); + +/** + * Map an absolute virtual file path to an absolute real one. + * The virtual path must be canonicalized (not contain "."/".."). + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay, + const char *virtualPath, + const char *realPath); + +/** + * Set the case sensitivity for the \c CXVirtualFileOverlay object. + * The \c CXVirtualFileOverlay object is case-sensitive by default, this + * option can be used to override the default. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_VirtualFileOverlay_setCaseSensitivity(CXVirtualFileOverlay, + int caseSensitive); + +/** + * Write out the \c CXVirtualFileOverlay object to a char buffer. + * + * \param options is reserved, always pass 0. + * \param out_buffer_ptr pointer to receive the buffer pointer, which should be + * disposed using \c clang_free(). + * \param out_buffer_size pointer to receive the buffer size. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay, unsigned options, + char **out_buffer_ptr, + unsigned *out_buffer_size); + +/** + * free memory allocated by libclang, such as the buffer returned by + * \c CXVirtualFileOverlay() or \c clang_ModuleMapDescriptor_writeToBuffer(). + * + * \param buffer memory pointer to free. + */ +CINDEX_LINKAGE void clang_free(void *buffer); + +/** + * Dispose a \c CXVirtualFileOverlay object. + */ +CINDEX_LINKAGE void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay); + +/** + * Object encapsulating information about a module.modulemap file. + */ +typedef struct CXModuleMapDescriptorImpl *CXModuleMapDescriptor; + +/** + * Create a \c CXModuleMapDescriptor object. + * Must be disposed with \c clang_ModuleMapDescriptor_dispose(). + * + * \param options is reserved, always pass 0. + */ +CINDEX_LINKAGE CXModuleMapDescriptor +clang_ModuleMapDescriptor_create(unsigned options); + +/** + * Sets the framework module name that the module.modulemap describes. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_ModuleMapDescriptor_setFrameworkModuleName(CXModuleMapDescriptor, + const char *name); + +/** + * Sets the umbrella header name that the module.modulemap describes. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor, + const char *name); + +/** + * Write out the \c CXModuleMapDescriptor object to a char buffer. + * + * \param options is reserved, always pass 0. + * \param out_buffer_ptr pointer to receive the buffer pointer, which should be + * disposed using \c clang_free(). + * \param out_buffer_size pointer to receive the buffer size. + * \returns 0 for success, non-zero to indicate an error. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_ModuleMapDescriptor_writeToBuffer(CXModuleMapDescriptor, unsigned options, + char **out_buffer_ptr, + unsigned *out_buffer_size); + +/** + * Dispose a \c CXModuleMapDescriptor object. + */ +CINDEX_LINKAGE void clang_ModuleMapDescriptor_dispose(CXModuleMapDescriptor); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif /* CLANG_C_BUILD_SYSTEM_H */ + diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXCompilationDatabase.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXCompilationDatabase.h new file mode 100644 index 0000000000..2b336e5464 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXCompilationDatabase.h @@ -0,0 +1,174 @@ +/*===-- clang-c/CXCompilationDatabase.h - Compilation database ---*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface to use CompilationDatabase without *| +|* the full Clang C++ API. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXCOMPILATIONDATABASE_H +#define LLVM_CLANG_C_CXCOMPILATIONDATABASE_H + +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** \defgroup COMPILATIONDB CompilationDatabase functions + * \ingroup CINDEX + * + * @{ + */ + +/** + * A compilation database holds all information used to compile files in a + * project. For each file in the database, it can be queried for the working + * directory or the command line used for the compiler invocation. + * + * Must be freed by \c clang_CompilationDatabase_dispose + */ +typedef void * CXCompilationDatabase; + +/** + * Contains the results of a search in the compilation database + * + * When searching for the compile command for a file, the compilation db can + * return several commands, as the file may have been compiled with + * different options in different places of the project. This choice of compile + * commands is wrapped in this opaque data structure. It must be freed by + * \c clang_CompileCommands_dispose. + */ +typedef void * CXCompileCommands; + +/** + * Represents the command line invocation to compile a specific file. + */ +typedef void * CXCompileCommand; + +/** + * Error codes for Compilation Database + */ +typedef enum { + /* + * No error occurred + */ + CXCompilationDatabase_NoError = 0, + + /* + * Database can not be loaded + */ + CXCompilationDatabase_CanNotLoadDatabase = 1 + +} CXCompilationDatabase_Error; + +/** + * Creates a compilation database from the database found in directory + * buildDir. For example, CMake can output a compile_commands.json which can + * be used to build the database. + * + * It must be freed by \c clang_CompilationDatabase_dispose. + */ +CINDEX_LINKAGE CXCompilationDatabase +clang_CompilationDatabase_fromDirectory(const char *BuildDir, + CXCompilationDatabase_Error *ErrorCode); + +/** + * Free the given compilation database + */ +CINDEX_LINKAGE void +clang_CompilationDatabase_dispose(CXCompilationDatabase); + +/** + * Find the compile commands used for a file. The compile commands + * must be freed by \c clang_CompileCommands_dispose. + */ +CINDEX_LINKAGE CXCompileCommands +clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase, + const char *CompleteFileName); + +/** + * Get all the compile commands in the given compilation database. + */ +CINDEX_LINKAGE CXCompileCommands +clang_CompilationDatabase_getAllCompileCommands(CXCompilationDatabase); + +/** + * Free the given CompileCommands + */ +CINDEX_LINKAGE void clang_CompileCommands_dispose(CXCompileCommands); + +/** + * Get the number of CompileCommand we have for a file + */ +CINDEX_LINKAGE unsigned +clang_CompileCommands_getSize(CXCompileCommands); + +/** + * Get the I'th CompileCommand for a file + * + * Note : 0 <= i < clang_CompileCommands_getSize(CXCompileCommands) + */ +CINDEX_LINKAGE CXCompileCommand +clang_CompileCommands_getCommand(CXCompileCommands, unsigned I); + +/** + * Get the working directory where the CompileCommand was executed from + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getDirectory(CXCompileCommand); + +/** + * Get the filename associated with the CompileCommand. + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getFilename(CXCompileCommand); + +/** + * Get the number of arguments in the compiler invocation. + * + */ +CINDEX_LINKAGE unsigned +clang_CompileCommand_getNumArgs(CXCompileCommand); + +/** + * Get the I'th argument value in the compiler invocations + * + * Invariant : + * - argument 0 is the compiler executable + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getArg(CXCompileCommand, unsigned I); + +/** + * Get the number of source mappings for the compiler invocation. + */ +CINDEX_LINKAGE unsigned +clang_CompileCommand_getNumMappedSources(CXCompileCommand); + +/** + * Get the I'th mapped source path for the compiler invocation. + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getMappedSourcePath(CXCompileCommand, unsigned I); + +/** + * Get the I'th mapped source content for the compiler invocation. + */ +CINDEX_LINKAGE CXString +clang_CompileCommand_getMappedSourceContent(CXCompileCommand, unsigned I); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif + diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXDiagnostic.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXDiagnostic.h new file mode 100644 index 0000000000..911d001f06 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXDiagnostic.h @@ -0,0 +1,379 @@ +/*===-- clang-c/CXDiagnostic.h - C Index Diagnostics --------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the interface to C Index diagnostics. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXDIAGNOSTIC_H +#define LLVM_CLANG_C_CXDIAGNOSTIC_H + +#include "clang-c/CXSourceLocation.h" +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup CINDEX_DIAG Diagnostic reporting + * + * @{ + */ + +/** + * Describes the severity of a particular diagnostic. + */ +enum CXDiagnosticSeverity { + /** + * A diagnostic that has been suppressed, e.g., by a command-line + * option. + */ + CXDiagnostic_Ignored = 0, + + /** + * This diagnostic is a note that should be attached to the + * previous (non-note) diagnostic. + */ + CXDiagnostic_Note = 1, + + /** + * This diagnostic indicates suspicious code that may not be + * wrong. + */ + CXDiagnostic_Warning = 2, + + /** + * This diagnostic indicates that the code is ill-formed. + */ + CXDiagnostic_Error = 3, + + /** + * This diagnostic indicates that the code is ill-formed such + * that future parser recovery is unlikely to produce useful + * results. + */ + CXDiagnostic_Fatal = 4 +}; + +/** + * A single diagnostic, containing the diagnostic's severity, + * location, text, source ranges, and fix-it hints. + */ +typedef void *CXDiagnostic; + +/** + * A group of CXDiagnostics. + */ +typedef void *CXDiagnosticSet; + +/** + * Determine the number of diagnostics in a CXDiagnosticSet. + */ +CINDEX_LINKAGE unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags); + +/** + * Retrieve a diagnostic associated with the given CXDiagnosticSet. + * + * \param Diags the CXDiagnosticSet to query. + * \param Index the zero-based diagnostic number to retrieve. + * + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). + */ +CINDEX_LINKAGE CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, + unsigned Index); + +/** + * Describes the kind of error that occurred (if any) in a call to + * \c clang_loadDiagnostics. + */ +enum CXLoadDiag_Error { + /** + * Indicates that no error occurred. + */ + CXLoadDiag_None = 0, + + /** + * Indicates that an unknown error occurred while attempting to + * deserialize diagnostics. + */ + CXLoadDiag_Unknown = 1, + + /** + * Indicates that the file containing the serialized diagnostics + * could not be opened. + */ + CXLoadDiag_CannotLoad = 2, + + /** + * Indicates that the serialized diagnostics file is invalid or + * corrupt. + */ + CXLoadDiag_InvalidFile = 3 +}; + +/** + * Deserialize a set of diagnostics from a Clang diagnostics bitcode + * file. + * + * \param file The name of the file to deserialize. + * \param error A pointer to a enum value recording if there was a problem + * deserializing the diagnostics. + * \param errorString A pointer to a CXString for recording the error string + * if the file was not successfully loaded. + * + * \returns A loaded CXDiagnosticSet if successful, and NULL otherwise. These + * diagnostics should be released using clang_disposeDiagnosticSet(). + */ +CINDEX_LINKAGE CXDiagnosticSet clang_loadDiagnostics( + const char *file, enum CXLoadDiag_Error *error, CXString *errorString); + +/** + * Release a CXDiagnosticSet and all of its contained diagnostics. + */ +CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags); + +/** + * Retrieve the child diagnostics of a CXDiagnostic. + * + * This CXDiagnosticSet does not need to be released by + * clang_disposeDiagnosticSet. + */ +CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D); + +/** + * Destroy a diagnostic. + */ +CINDEX_LINKAGE void clang_disposeDiagnostic(CXDiagnostic Diagnostic); + +/** + * Options to control the display of diagnostics. + * + * The values in this enum are meant to be combined to customize the + * behavior of \c clang_formatDiagnostic(). + */ +enum CXDiagnosticDisplayOptions { + /** + * Display the source-location information where the + * diagnostic was located. + * + * When set, diagnostics will be prefixed by the file, line, and + * (optionally) column to which the diagnostic refers. For example, + * + * \code + * test.c:28: warning: extra tokens at end of #endif directive + * \endcode + * + * This option corresponds to the clang flag \c -fshow-source-location. + */ + CXDiagnostic_DisplaySourceLocation = 0x01, + + /** + * If displaying the source-location information of the + * diagnostic, also include the column number. + * + * This option corresponds to the clang flag \c -fshow-column. + */ + CXDiagnostic_DisplayColumn = 0x02, + + /** + * If displaying the source-location information of the + * diagnostic, also include information about source ranges in a + * machine-parsable format. + * + * This option corresponds to the clang flag + * \c -fdiagnostics-print-source-range-info. + */ + CXDiagnostic_DisplaySourceRanges = 0x04, + + /** + * Display the option name associated with this diagnostic, if any. + * + * The option name displayed (e.g., -Wconversion) will be placed in brackets + * after the diagnostic text. This option corresponds to the clang flag + * \c -fdiagnostics-show-option. + */ + CXDiagnostic_DisplayOption = 0x08, + + /** + * Display the category number associated with this diagnostic, if any. + * + * The category number is displayed within brackets after the diagnostic text. + * This option corresponds to the clang flag + * \c -fdiagnostics-show-category=id. + */ + CXDiagnostic_DisplayCategoryId = 0x10, + + /** + * Display the category name associated with this diagnostic, if any. + * + * The category name is displayed within brackets after the diagnostic text. + * This option corresponds to the clang flag + * \c -fdiagnostics-show-category=name. + */ + CXDiagnostic_DisplayCategoryName = 0x20 +}; + +/** + * Format the given diagnostic in a manner that is suitable for display. + * + * This routine will format the given diagnostic to a string, rendering + * the diagnostic according to the various options given. The + * \c clang_defaultDiagnosticDisplayOptions() function returns the set of + * options that most closely mimics the behavior of the clang compiler. + * + * \param Diagnostic The diagnostic to print. + * + * \param Options A set of options that control the diagnostic display, + * created by combining \c CXDiagnosticDisplayOptions values. + * + * \returns A new string containing for formatted diagnostic. + */ +CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, + unsigned Options); + +/** + * Retrieve the set of display options most similar to the + * default behavior of the clang compiler. + * + * \returns A set of display options suitable for use with \c + * clang_formatDiagnostic(). + */ +CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void); + +/** + * Determine the severity of the given diagnostic. + */ +CINDEX_LINKAGE enum CXDiagnosticSeverity + clang_getDiagnosticSeverity(CXDiagnostic); + +/** + * Retrieve the source location of the given diagnostic. + * + * This location is where Clang would print the caret ('^') when + * displaying the diagnostic on the command line. + */ +CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic); + +/** + * Retrieve the text of the given diagnostic. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic); + +/** + * Retrieve the name of the command-line option that enabled this + * diagnostic. + * + * \param Diag The diagnostic to be queried. + * + * \param Disable If non-NULL, will be set to the option that disables this + * diagnostic (if any). + * + * \returns A string that contains the command-line option used to enable this + * warning, such as "-Wconversion" or "-pedantic". + */ +CINDEX_LINKAGE CXString clang_getDiagnosticOption(CXDiagnostic Diag, + CXString *Disable); + +/** + * Retrieve the category number for this diagnostic. + * + * Diagnostics can be categorized into groups along with other, related + * diagnostics (e.g., diagnostics under the same warning flag). This routine + * retrieves the category number for the given diagnostic. + * + * \returns The number of the category that contains this diagnostic, or zero + * if this diagnostic is uncategorized. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticCategory(CXDiagnostic); + +/** + * Retrieve the name of a particular diagnostic category. This + * is now deprecated. Use clang_getDiagnosticCategoryText() + * instead. + * + * \param Category A diagnostic category number, as returned by + * \c clang_getDiagnosticCategory(). + * + * \returns The name of the given diagnostic category. + */ +CINDEX_DEPRECATED CINDEX_LINKAGE CXString +clang_getDiagnosticCategoryName(unsigned Category); + +/** + * Retrieve the diagnostic category text for a given diagnostic. + * + * \returns The text of the given diagnostic category. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticCategoryText(CXDiagnostic); + +/** + * Determine the number of source ranges associated with the given + * diagnostic. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticNumRanges(CXDiagnostic); + +/** + * Retrieve a source range associated with the diagnostic. + * + * A diagnostic's source ranges highlight important elements in the source + * code. On the command line, Clang displays source ranges by + * underlining them with '~' characters. + * + * \param Diagnostic the diagnostic whose range is being extracted. + * + * \param Range the zero-based index specifying which range to + * + * \returns the requested source range. + */ +CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic, + unsigned Range); + +/** + * Determine the number of fix-it hints associated with the + * given diagnostic. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic); + +/** + * Retrieve the replacement information for a given fix-it. + * + * Fix-its are described in terms of a source range whose contents + * should be replaced by a string. This approach generalizes over + * three kinds of operations: removal of source code (the range covers + * the code to be removed and the replacement string is empty), + * replacement of source code (the range covers the code to be + * replaced and the replacement string provides the new code), and + * insertion (both the start and end of the range point at the + * insertion location, and the replacement string provides the text to + * insert). + * + * \param Diagnostic The diagnostic whose fix-its are being queried. + * + * \param FixIt The zero-based index of the fix-it. + * + * \param ReplacementRange The source range whose contents will be + * replaced with the returned replacement string. Note that source + * ranges are half-open ranges [a, b), so the source code should be + * replaced from a and up to (but not including) b. + * + * \returns A string containing text that should be replace the source + * code indicated by the \c ReplacementRange. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticFixIt( + CXDiagnostic Diagnostic, unsigned FixIt, CXSourceRange *ReplacementRange); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXErrorCode.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXErrorCode.h new file mode 100644 index 0000000000..b3a0b9d66d --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXErrorCode.h @@ -0,0 +1,62 @@ +/*===-- clang-c/CXErrorCode.h - C Index Error Codes --------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the CXErrorCode enumerators. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXERRORCODE_H +#define LLVM_CLANG_C_CXERRORCODE_H + +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * Error codes returned by libclang routines. + * + * Zero (\c CXError_Success) is the only error code indicating success. Other + * error codes, including not yet assigned non-zero values, indicate errors. + */ +enum CXErrorCode { + /** + * No error. + */ + CXError_Success = 0, + + /** + * A generic error code, no further details are available. + * + * Errors of this kind can get their own specific error codes in future + * libclang versions. + */ + CXError_Failure = 1, + + /** + * libclang crashed while performing the requested operation. + */ + CXError_Crashed = 2, + + /** + * The function detected that the arguments violate the function + * contract. + */ + CXError_InvalidArguments = 3, + + /** + * An AST deserialization error has occurred. + */ + CXError_ASTReadError = 4 +}; + +LLVM_CLANG_C_EXTERN_C_END + +#endif + diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXFile.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXFile.h new file mode 100644 index 0000000000..c48f58c940 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXFile.h @@ -0,0 +1,83 @@ +/*===-- clang-c/CXFile.h - C Index File ---------------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the interface to C Index files. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXFILE_H +#define LLVM_CLANG_C_CXFILE_H + +#include + +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup CINDEX_FILES File manipulation routines + * + * @{ + */ + +/** + * A particular source file that is part of a translation unit. + */ +typedef void *CXFile; + +/** + * Retrieve the complete file and path name of the given file. + */ +CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile); + +/** + * Retrieve the last modification time of the given file. + */ +CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile); + +/** + * Uniquely identifies a CXFile, that refers to the same underlying file, + * across an indexing session. + */ +typedef struct { + unsigned long long data[3]; +} CXFileUniqueID; + +/** + * Retrieve the unique ID for the given \c file. + * + * \param file the file to get the ID for. + * \param outID stores the returned CXFileUniqueID. + * \returns If there was a failure getting the unique ID, returns non-zero, + * otherwise returns 0. + */ +CINDEX_LINKAGE int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID); + +/** + * Returns non-zero if the \c file1 and \c file2 point to the same file, + * or they are both NULL. + */ +CINDEX_LINKAGE int clang_File_isEqual(CXFile file1, CXFile file2); + +/** + * Returns the real path name of \c file. + * + * An empty string may be returned. Use \c clang_getFileName() in that case. + */ +CINDEX_LINKAGE CXString clang_File_tryGetRealPathName(CXFile file); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXSourceLocation.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXSourceLocation.h new file mode 100644 index 0000000000..dcb13ba273 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXSourceLocation.h @@ -0,0 +1,286 @@ +/*===-- clang-c/CXSourceLocation.h - C Index Source Location ------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the interface to C Index source locations. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXSOURCE_LOCATION_H +#define LLVM_CLANG_C_CXSOURCE_LOCATION_H + +#include "clang-c/CXFile.h" +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup CINDEX_LOCATIONS Physical source locations + * + * Clang represents physical source locations in its abstract syntax tree in + * great detail, with file, line, and column information for the majority of + * the tokens parsed in the source code. These data types and functions are + * used to represent source location information, either for a particular + * point in the program or for a range of points in the program, and extract + * specific location information from those data types. + * + * @{ + */ + +/** + * Identifies a specific source location within a translation + * unit. + * + * Use clang_getExpansionLocation() or clang_getSpellingLocation() + * to map a source location to a particular file, line, and column. + */ +typedef struct { + const void *ptr_data[2]; + unsigned int_data; +} CXSourceLocation; + +/** + * Identifies a half-open character range in the source code. + * + * Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the + * starting and end locations from a source range, respectively. + */ +typedef struct { + const void *ptr_data[2]; + unsigned begin_int_data; + unsigned end_int_data; +} CXSourceRange; + +/** + * Retrieve a NULL (invalid) source location. + */ +CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(void); + +/** + * Determine whether two source locations, which must refer into + * the same translation unit, refer to exactly the same point in the source + * code. + * + * \returns non-zero if the source locations refer to the same location, zero + * if they refer to different locations. + */ +CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1, + CXSourceLocation loc2); + +/** + * Returns non-zero if the given source location is in a system header. + */ +CINDEX_LINKAGE int clang_Location_isInSystemHeader(CXSourceLocation location); + +/** + * Returns non-zero if the given source location is in the main file of + * the corresponding translation unit. + */ +CINDEX_LINKAGE int clang_Location_isFromMainFile(CXSourceLocation location); + +/** + * Retrieve a NULL (invalid) source range. + */ +CINDEX_LINKAGE CXSourceRange clang_getNullRange(void); + +/** + * Retrieve a source range given the beginning and ending source + * locations. + */ +CINDEX_LINKAGE CXSourceRange clang_getRange(CXSourceLocation begin, + CXSourceLocation end); + +/** + * Determine whether two ranges are equivalent. + * + * \returns non-zero if the ranges are the same, zero if they differ. + */ +CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1, + CXSourceRange range2); + +/** + * Returns non-zero if \p range is null. + */ +CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range); + +/** + * Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro expansion, retrieves the + * location of the macro expansion. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ +CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location, + CXFile *file, unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * Retrieve the file, line and column represented by the given source + * location, as specified in a # line directive. + * + * Example: given the following source code in a file somefile.c + * + * \code + * #123 "dummy.c" 1 + * + * static int func(void) + * { + * return 0; + * } + * \endcode + * + * the location information returned by this function would be + * + * File: dummy.c Line: 124 Column: 12 + * + * whereas clang_getExpansionLocation would have returned + * + * File: somefile.c Line: 3 Column: 12 + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param filename [out] if non-NULL, will be set to the filename of the + * source location. Note that filenames returned will be for "virtual" files, + * which don't necessarily exist on the machine running clang - e.g. when + * parsing preprocessed output obtained from a different environment. If + * a non-NULL value is passed in, remember to dispose of the returned value + * using \c clang_disposeString() once you've finished with it. For an invalid + * source location, an empty string is returned. + * + * \param line [out] if non-NULL, will be set to the line number of the + * source location. For an invalid source location, zero is returned. + * + * \param column [out] if non-NULL, will be set to the column number of the + * source location. For an invalid source location, zero is returned. + */ +CINDEX_LINKAGE void clang_getPresumedLocation(CXSourceLocation location, + CXString *filename, + unsigned *line, unsigned *column); + +/** + * Legacy API to retrieve the file, line, column, and offset represented + * by the given source location. + * + * This interface has been replaced by the newer interface + * #clang_getExpansionLocation(). See that interface's documentation for + * details. + */ +CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro instantiation, return where the + * location was originally spelled in the source file. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ +CINDEX_LINKAGE void clang_getSpellingLocation(CXSourceLocation location, + CXFile *file, unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * Retrieve the file, line, column, and offset represented by + * the given source location. + * + * If the location refers into a macro expansion, return where the macro was + * expanded or where the macro argument was written, if the location points at + * a macro argument. + * + * \param location the location within a source file that will be decomposed + * into its parts. + * + * \param file [out] if non-NULL, will be set to the file to which the given + * source location points. + * + * \param line [out] if non-NULL, will be set to the line to which the given + * source location points. + * + * \param column [out] if non-NULL, will be set to the column to which the given + * source location points. + * + * \param offset [out] if non-NULL, will be set to the offset into the + * buffer to which the given source location points. + */ +CINDEX_LINKAGE void clang_getFileLocation(CXSourceLocation location, + CXFile *file, unsigned *line, + unsigned *column, unsigned *offset); + +/** + * Retrieve a source location representing the first character within a + * source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range); + +/** + * Retrieve a source location representing the last character within a + * source range. + */ +CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); + +/** + * Identifies an array of ranges. + */ +typedef struct { + /** The number of ranges in the \c ranges array. */ + unsigned count; + /** + * An array of \c CXSourceRanges. + */ + CXSourceRange *ranges; +} CXSourceRangeList; + +/** + * Destroy the given \c CXSourceRangeList. + */ +CINDEX_LINKAGE void clang_disposeSourceRangeList(CXSourceRangeList *ranges); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXString.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXString.h new file mode 100644 index 0000000000..f117010c71 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/CXString.h @@ -0,0 +1,69 @@ +/*===-- clang-c/CXString.h - C Index strings --------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides the interface to C Index strings. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_CXSTRING_H +#define LLVM_CLANG_C_CXSTRING_H + +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup CINDEX_STRING String manipulation routines + * \ingroup CINDEX + * + * @{ + */ + +/** + * A character string. + * + * The \c CXString type is used to return strings from the interface when + * the ownership of that string might differ from one call to the next. + * Use \c clang_getCString() to retrieve the string data and, once finished + * with the string data, call \c clang_disposeString() to free the string. + */ +typedef struct { + const void *data; + unsigned private_flags; +} CXString; + +typedef struct { + CXString *Strings; + unsigned Count; +} CXStringSet; + +/** + * Retrieve the character data associated with the given string. + */ +CINDEX_LINKAGE const char *clang_getCString(CXString string); + +/** + * Free the given string. + */ +CINDEX_LINKAGE void clang_disposeString(CXString string); + +/** + * Free the given string set. + */ +CINDEX_LINKAGE void clang_disposeStringSet(CXStringSet *set); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif + diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/Documentation.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Documentation.h new file mode 100644 index 0000000000..e04c50a0e6 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Documentation.h @@ -0,0 +1,619 @@ +/*==-- clang-c/Documentation.h - Utilities for comment processing -*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a supplementary interface for inspecting *| +|* documentation comments. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_DOCUMENTATION_H +#define LLVM_CLANG_C_DOCUMENTATION_H + +#include "clang-c/CXErrorCode.h" +#include "clang-c/ExternC.h" +#include "clang-c/Index.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup CINDEX_COMMENT Comment introspection + * + * The routines in this group provide access to information in documentation + * comments. These facilities are distinct from the core and may be subject to + * their own schedule of stability and deprecation. + * + * @{ + */ + +/** + * A parsed comment. + */ +typedef struct { + const void *ASTNode; + CXTranslationUnit TranslationUnit; +} CXComment; + +/** + * Given a cursor that represents a documentable entity (e.g., + * declaration), return the associated parsed comment as a + * \c CXComment_FullComment AST node. + */ +CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C); + +/** + * Describes the type of the comment AST node (\c CXComment). A comment + * node can be considered block content (e. g., paragraph), inline content + * (plain text) or neither (the root AST node). + */ +enum CXCommentKind { + /** + * Null comment. No AST node is constructed at the requested location + * because there is no text or a syntax error. + */ + CXComment_Null = 0, + + /** + * Plain text. Inline content. + */ + CXComment_Text = 1, + + /** + * A command with word-like arguments that is considered inline content. + * + * For example: \\c command. + */ + CXComment_InlineCommand = 2, + + /** + * HTML start tag with attributes (name-value pairs). Considered + * inline content. + * + * For example: + * \verbatim + *

+ * \endverbatim + */ + CXComment_HTMLStartTag = 3, + + /** + * HTML end tag. Considered inline content. + * + * For example: + * \verbatim + * + * \endverbatim + */ + CXComment_HTMLEndTag = 4, + + /** + * A paragraph, contains inline comment. The paragraph itself is + * block content. + */ + CXComment_Paragraph = 5, + + /** + * A command that has zero or more word-like arguments (number of + * word-like arguments depends on command name) and a paragraph as an + * argument. Block command is block content. + * + * Paragraph argument is also a child of the block command. + * + * For example: \has 0 word-like arguments and a paragraph argument. + * + * AST nodes of special kinds that parser knows about (e. g., \\param + * command) have their own node kinds. + */ + CXComment_BlockCommand = 6, + + /** + * A \\param or \\arg command that describes the function parameter + * (name, passing direction, description). + * + * For example: \\param [in] ParamName description. + */ + CXComment_ParamCommand = 7, + + /** + * A \\tparam command that describes a template parameter (name and + * description). + * + * For example: \\tparam T description. + */ + CXComment_TParamCommand = 8, + + /** + * A verbatim block command (e. g., preformatted code). Verbatim + * block has an opening and a closing command and contains multiple lines of + * text (\c CXComment_VerbatimBlockLine child nodes). + * + * For example: + * \\verbatim + * aaa + * \\endverbatim + */ + CXComment_VerbatimBlockCommand = 9, + + /** + * A line of text that is contained within a + * CXComment_VerbatimBlockCommand node. + */ + CXComment_VerbatimBlockLine = 10, + + /** + * A verbatim line command. Verbatim line has an opening command, + * a single line of text (up to the newline after the opening command) and + * has no closing command. + */ + CXComment_VerbatimLine = 11, + + /** + * A full comment attached to a declaration, contains block content. + */ + CXComment_FullComment = 12 +}; + +/** + * The most appropriate rendering mode for an inline command, chosen on + * command semantics in Doxygen. + */ +enum CXCommentInlineCommandRenderKind { + /** + * Command argument should be rendered in a normal font. + */ + CXCommentInlineCommandRenderKind_Normal, + + /** + * Command argument should be rendered in a bold font. + */ + CXCommentInlineCommandRenderKind_Bold, + + /** + * Command argument should be rendered in a monospaced font. + */ + CXCommentInlineCommandRenderKind_Monospaced, + + /** + * Command argument should be rendered emphasized (typically italic + * font). + */ + CXCommentInlineCommandRenderKind_Emphasized, + + /** + * Command argument should not be rendered (since it only defines an anchor). + */ + CXCommentInlineCommandRenderKind_Anchor +}; + +/** + * Describes parameter passing direction for \\param or \\arg command. + */ +enum CXCommentParamPassDirection { + /** + * The parameter is an input parameter. + */ + CXCommentParamPassDirection_In, + + /** + * The parameter is an output parameter. + */ + CXCommentParamPassDirection_Out, + + /** + * The parameter is an input and output parameter. + */ + CXCommentParamPassDirection_InOut +}; + +/** + * \param Comment AST node of any kind. + * + * \returns the type of the AST node. + */ +CINDEX_LINKAGE enum CXCommentKind clang_Comment_getKind(CXComment Comment); + +/** + * \param Comment AST node of any kind. + * + * \returns number of children of the AST node. + */ +CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment); + +/** + * \param Comment AST node of any kind. + * + * \param ChildIdx child index (zero-based). + * + * \returns the specified child of the AST node. + */ +CINDEX_LINKAGE +CXComment clang_Comment_getChild(CXComment Comment, unsigned ChildIdx); + +/** + * A \c CXComment_Paragraph node is considered whitespace if it contains + * only \c CXComment_Text nodes that are empty or whitespace. + * + * Other AST nodes (except \c CXComment_Paragraph and \c CXComment_Text) are + * never considered whitespace. + * + * \returns non-zero if \c Comment is whitespace. + */ +CINDEX_LINKAGE unsigned clang_Comment_isWhitespace(CXComment Comment); + +/** + * \returns non-zero if \c Comment is inline content and has a newline + * immediately following it in the comment text. Newlines between paragraphs + * do not count. + */ +CINDEX_LINKAGE +unsigned clang_InlineContentComment_hasTrailingNewline(CXComment Comment); + +/** + * \param Comment a \c CXComment_Text AST node. + * + * \returns text contained in the AST node. + */ +CINDEX_LINKAGE CXString clang_TextComment_getText(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \returns name of the inline command. + */ +CINDEX_LINKAGE +CXString clang_InlineCommandComment_getCommandName(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \returns the most appropriate rendering mode, chosen on command + * semantics in Doxygen. + */ +CINDEX_LINKAGE enum CXCommentInlineCommandRenderKind +clang_InlineCommandComment_getRenderKind(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \returns number of command arguments. + */ +CINDEX_LINKAGE +unsigned clang_InlineCommandComment_getNumArgs(CXComment Comment); + +/** + * \param Comment a \c CXComment_InlineCommand AST node. + * + * \param ArgIdx argument index (zero-based). + * + * \returns text of the specified argument. + */ +CINDEX_LINKAGE +CXString clang_InlineCommandComment_getArgText(CXComment Comment, + unsigned ArgIdx); + +/** + * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST + * node. + * + * \returns HTML tag name. + */ +CINDEX_LINKAGE CXString clang_HTMLTagComment_getTagName(CXComment Comment); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \returns non-zero if tag is self-closing (for example, <br />). + */ +CINDEX_LINKAGE +unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment Comment); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \returns number of attributes (name-value pairs) attached to the start tag. + */ +CINDEX_LINKAGE unsigned clang_HTMLStartTag_getNumAttrs(CXComment Comment); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \param AttrIdx attribute index (zero-based). + * + * \returns name of the specified attribute. + */ +CINDEX_LINKAGE +CXString clang_HTMLStartTag_getAttrName(CXComment Comment, unsigned AttrIdx); + +/** + * \param Comment a \c CXComment_HTMLStartTag AST node. + * + * \param AttrIdx attribute index (zero-based). + * + * \returns value of the specified attribute. + */ +CINDEX_LINKAGE +CXString clang_HTMLStartTag_getAttrValue(CXComment Comment, unsigned AttrIdx); + +/** + * \param Comment a \c CXComment_BlockCommand AST node. + * + * \returns name of the block command. + */ +CINDEX_LINKAGE +CXString clang_BlockCommandComment_getCommandName(CXComment Comment); + +/** + * \param Comment a \c CXComment_BlockCommand AST node. + * + * \returns number of word-like arguments. + */ +CINDEX_LINKAGE +unsigned clang_BlockCommandComment_getNumArgs(CXComment Comment); + +/** + * \param Comment a \c CXComment_BlockCommand AST node. + * + * \param ArgIdx argument index (zero-based). + * + * \returns text of the specified word-like argument. + */ +CINDEX_LINKAGE +CXString clang_BlockCommandComment_getArgText(CXComment Comment, + unsigned ArgIdx); + +/** + * \param Comment a \c CXComment_BlockCommand or + * \c CXComment_VerbatimBlockCommand AST node. + * + * \returns paragraph argument of the block command. + */ +CINDEX_LINKAGE +CXComment clang_BlockCommandComment_getParagraph(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns parameter name. + */ +CINDEX_LINKAGE +CXString clang_ParamCommandComment_getParamName(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns non-zero if the parameter that this AST node represents was found + * in the function prototype and \c clang_ParamCommandComment_getParamIndex + * function will return a meaningful value. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_isParamIndexValid(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns zero-based parameter index in function prototype. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_getParamIndex(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns non-zero if parameter passing direction was specified explicitly in + * the comment. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment Comment); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \returns parameter passing direction. + */ +CINDEX_LINKAGE +enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection( + CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns template parameter name. + */ +CINDEX_LINKAGE +CXString clang_TParamCommandComment_getParamName(CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns non-zero if the parameter that this AST node represents was found + * in the template parameter list and + * \c clang_TParamCommandComment_getDepth and + * \c clang_TParamCommandComment_getIndex functions will return a meaningful + * value. + */ +CINDEX_LINKAGE +unsigned clang_TParamCommandComment_isParamPositionValid(CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns zero-based nesting depth of this parameter in the template parameter list. + * + * For example, + * \verbatim + * template class TT> + * void test(TT aaa); + * \endverbatim + * for C and TT nesting depth is 0, + * for T nesting depth is 1. + */ +CINDEX_LINKAGE +unsigned clang_TParamCommandComment_getDepth(CXComment Comment); + +/** + * \param Comment a \c CXComment_TParamCommand AST node. + * + * \returns zero-based parameter index in the template parameter list at a + * given nesting depth. + * + * For example, + * \verbatim + * template class TT> + * void test(TT aaa); + * \endverbatim + * for C and TT nesting depth is 0, so we can ask for index at depth 0: + * at depth 0 C's index is 0, TT's index is 1. + * + * For T nesting depth is 1, so we can ask for index at depth 0 and 1: + * at depth 0 T's index is 1 (same as TT's), + * at depth 1 T's index is 0. + */ +CINDEX_LINKAGE +unsigned clang_TParamCommandComment_getIndex(CXComment Comment, unsigned Depth); + +/** + * \param Comment a \c CXComment_VerbatimBlockLine AST node. + * + * \returns text contained in the AST node. + */ +CINDEX_LINKAGE +CXString clang_VerbatimBlockLineComment_getText(CXComment Comment); + +/** + * \param Comment a \c CXComment_VerbatimLine AST node. + * + * \returns text contained in the AST node. + */ +CINDEX_LINKAGE CXString clang_VerbatimLineComment_getText(CXComment Comment); + +/** + * Convert an HTML tag AST node to string. + * + * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST + * node. + * + * \returns string containing an HTML tag. + */ +CINDEX_LINKAGE CXString clang_HTMLTagComment_getAsString(CXComment Comment); + +/** + * Convert a given full parsed comment to an HTML fragment. + * + * Specific details of HTML layout are subject to change. Don't try to parse + * this HTML back into an AST, use other APIs instead. + * + * Currently the following CSS classes are used: + * \li "para-brief" for \paragraph and equivalent commands; + * \li "para-returns" for \\returns paragraph and equivalent commands; + * \li "word-returns" for the "Returns" word in \\returns paragraph. + * + * Function argument documentation is rendered as a \ list with arguments + * sorted in function prototype order. CSS classes used: + * \li "param-name-index-NUMBER" for parameter name (\); + * \li "param-descr-index-NUMBER" for parameter description (\); + * \li "param-name-index-invalid" and "param-descr-index-invalid" are used if + * parameter index is invalid. + * + * Template parameter documentation is rendered as a \ list with + * parameters sorted in template parameter list order. CSS classes used: + * \li "tparam-name-index-NUMBER" for parameter name (\); + * \li "tparam-descr-index-NUMBER" for parameter description (\); + * \li "tparam-name-index-other" and "tparam-descr-index-other" are used for + * names inside template template parameters; + * \li "tparam-name-index-invalid" and "tparam-descr-index-invalid" are used if + * parameter position is invalid. + * + * \param Comment a \c CXComment_FullComment AST node. + * + * \returns string containing an HTML fragment. + */ +CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment); + +/** + * Convert a given full parsed comment to an XML document. + * + * A Relax NG schema for the XML can be found in comment-xml-schema.rng file + * inside clang source tree. + * + * \param Comment a \c CXComment_FullComment AST node. + * + * \returns string containing an XML document. + */ +CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment); + +/** + * CXAPISet is an opaque type that represents a data structure containing all + * the API information for a given translation unit. This can be used for a + * single symbol symbol graph for a given symbol. + */ +typedef struct CXAPISetImpl *CXAPISet; + +/** + * Traverses the translation unit to create a \c CXAPISet. + * + * \param tu is the \c CXTranslationUnit to build the \c CXAPISet for. + * + * \param out_api is a pointer to the output of this function. It is needs to be + * disposed of by calling clang_disposeAPISet. + * + * \returns Error code indicating success or failure of the APISet creation. + */ +CINDEX_LINKAGE enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, + CXAPISet *out_api); + +/** + * Dispose of an APISet. + * + * The provided \c CXAPISet can not be used after this function is called. + */ +CINDEX_LINKAGE void clang_disposeAPISet(CXAPISet api); + +/** + * Generate a single symbol symbol graph for the given USR. Returns a null + * string if the associated symbol can not be found in the provided \c CXAPISet. + * + * The output contains the symbol graph as well as some additional information + * about related symbols. + * + * \param usr is a string containing the USR of the symbol to generate the + * symbol graph for. + * + * \param api the \c CXAPISet to look for the symbol in. + * + * \returns a string containing the serialized symbol graph representation for + * the symbol being queried or a null string if it can not be found in the + * APISet. + */ +CINDEX_LINKAGE CXString clang_getSymbolGraphForUSR(const char *usr, + CXAPISet api); + +/** + * Generate a single symbol symbol graph for the declaration at the given + * cursor. Returns a null string if the AST node for the cursor isn't a + * declaration. + * + * The output contains the symbol graph as well as some additional information + * about related symbols. + * + * \param cursor the declaration for which to generate the single symbol symbol + * graph. + * + * \returns a string containing the serialized symbol graph representation for + * the symbol being queried or a null string if it can not be found in the + * APISet. + */ +CINDEX_LINKAGE CXString clang_getSymbolGraphForCursor(CXCursor cursor); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif /* CLANG_C_DOCUMENTATION_H */ + diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/ExternC.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/ExternC.h new file mode 100644 index 0000000000..384f24d47b --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/ExternC.h @@ -0,0 +1,39 @@ +/*===- clang-c/ExternC.h - Wrapper for 'extern "C"' ---------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines an 'extern "C"' wrapper. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_EXTERN_C_H +#define LLVM_CLANG_C_EXTERN_C_H + +#ifdef __clang__ +#define LLVM_CLANG_C_STRICT_PROTOTYPES_BEGIN \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic error \"-Wstrict-prototypes\"") +#define LLVM_CLANG_C_STRICT_PROTOTYPES_END _Pragma("clang diagnostic pop") +#else +#define LLVM_CLANG_C_STRICT_PROTOTYPES_BEGIN +#define LLVM_CLANG_C_STRICT_PROTOTYPES_END +#endif + +#ifdef __cplusplus +#define LLVM_CLANG_C_EXTERN_C_BEGIN \ + extern "C" { \ + LLVM_CLANG_C_STRICT_PROTOTYPES_BEGIN +#define LLVM_CLANG_C_EXTERN_C_END \ + LLVM_CLANG_C_STRICT_PROTOTYPES_END \ + } +#else +#define LLVM_CLANG_C_EXTERN_C_BEGIN LLVM_CLANG_C_STRICT_PROTOTYPES_BEGIN +#define LLVM_CLANG_C_EXTERN_C_END LLVM_CLANG_C_STRICT_PROTOTYPES_END +#endif + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/FatalErrorHandler.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/FatalErrorHandler.h new file mode 100644 index 0000000000..22f34fa815 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/FatalErrorHandler.h @@ -0,0 +1,32 @@ +/*===-- clang-c/FatalErrorHandler.h - Fatal Error Handling --------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_FATAL_ERROR_HANDLER_H +#define LLVM_CLANG_C_FATAL_ERROR_HANDLER_H + +#include "clang-c/ExternC.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * Installs error handler that prints error message to stderr and calls abort(). + * Replaces currently installed error handler (if any). + */ +void clang_install_aborting_llvm_fatal_error_handler(void); + +/** + * Removes currently installed error handler (if any). + * If no error handler is intalled, the default strategy is to print error + * message to stderr and call exit(1). + */ +void clang_uninstall_llvm_fatal_error_handler(void); + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/Index.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Index.h new file mode 100644 index 0000000000..64ab337895 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Index.h @@ -0,0 +1,6666 @@ +/*===-- clang-c/Index.h - Indexing Public C Interface -------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface to a Clang library for extracting *| +|* high-level symbol information from source files without exposing the full *| +|* Clang C++ API. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_INDEX_H +#define LLVM_CLANG_C_INDEX_H + +#include "clang-c/BuildSystem.h" +#include "clang-c/CXDiagnostic.h" +#include "clang-c/CXErrorCode.h" +#include "clang-c/CXFile.h" +#include "clang-c/CXSourceLocation.h" +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" + +/** + * The version constants for the libclang API. + * CINDEX_VERSION_MINOR should increase when there are API additions. + * CINDEX_VERSION_MAJOR is intended for "major" source/ABI breaking changes. + * + * The policy about the libclang API was always to keep it source and ABI + * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. + */ +#define CINDEX_VERSION_MAJOR 0 +#define CINDEX_VERSION_MINOR 64 + +#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1)) + +#define CINDEX_VERSION \ + CINDEX_VERSION_ENCODE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR) + +#define CINDEX_VERSION_STRINGIZE_(major, minor) #major "." #minor +#define CINDEX_VERSION_STRINGIZE(major, minor) \ + CINDEX_VERSION_STRINGIZE_(major, minor) + +#define CINDEX_VERSION_STRING \ + CINDEX_VERSION_STRINGIZE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR) + +#ifndef __has_feature +#define __has_feature(feature) 0 +#endif + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** \defgroup CINDEX libclang: C Interface to Clang + * + * The C Interface to Clang provides a relatively small API that exposes + * facilities for parsing source code into an abstract syntax tree (AST), + * loading already-parsed ASTs, traversing the AST, associating + * physical source locations with elements within the AST, and other + * facilities that support Clang-based development tools. + * + * This C interface to Clang will never provide all of the information + * representation stored in Clang's C++ AST, nor should it: the intent is to + * maintain an API that is relatively stable from one release to the next, + * providing only the basic functionality needed to support development tools. + * + * To avoid namespace pollution, data types are prefixed with "CX" and + * functions are prefixed with "clang_". + * + * @{ + */ + +/** + * An "index" that consists of a set of translation units that would + * typically be linked together into an executable or library. + */ +typedef void *CXIndex; + +/** + * An opaque type representing target information for a given translation + * unit. + */ +typedef struct CXTargetInfoImpl *CXTargetInfo; + +/** + * A single translation unit, which resides in an index. + */ +typedef struct CXTranslationUnitImpl *CXTranslationUnit; + +/** + * Opaque pointer representing client data that will be passed through + * to various callbacks and visitors. + */ +typedef void *CXClientData; + +/** + * Provides the contents of a file that has not yet been saved to disk. + * + * Each CXUnsavedFile instance provides the name of a file on the + * system along with the current contents of that file that have not + * yet been saved to disk. + */ +struct CXUnsavedFile { + /** + * The file whose contents have not yet been saved. + * + * This file must already exist in the file system. + */ + const char *Filename; + + /** + * A buffer containing the unsaved contents of this file. + */ + const char *Contents; + + /** + * The length of the unsaved contents of this buffer. + */ + unsigned long Length; +}; + +/** + * Describes the availability of a particular entity, which indicates + * whether the use of this entity will result in a warning or error due to + * it being deprecated or unavailable. + */ +enum CXAvailabilityKind { + /** + * The entity is available. + */ + CXAvailability_Available, + /** + * The entity is available, but has been deprecated (and its use is + * not recommended). + */ + CXAvailability_Deprecated, + /** + * The entity is not available; any use of it will be an error. + */ + CXAvailability_NotAvailable, + /** + * The entity is available, but not accessible; any use of it will be + * an error. + */ + CXAvailability_NotAccessible +}; + +/** + * Describes a version number of the form major.minor.subminor. + */ +typedef struct CXVersion { + /** + * The major version number, e.g., the '10' in '10.7.3'. A negative + * value indicates that there is no version number at all. + */ + int Major; + /** + * The minor version number, e.g., the '7' in '10.7.3'. This value + * will be negative if no minor version number was provided, e.g., for + * version '10'. + */ + int Minor; + /** + * The subminor version number, e.g., the '3' in '10.7.3'. This value + * will be negative if no minor or subminor version number was provided, + * e.g., in version '10' or '10.7'. + */ + int Subminor; +} CXVersion; + +/** + * Describes the exception specification of a cursor. + * + * A negative value indicates that the cursor is not a function declaration. + */ +enum CXCursor_ExceptionSpecificationKind { + /** + * The cursor has no exception specification. + */ + CXCursor_ExceptionSpecificationKind_None, + + /** + * The cursor has exception specification throw() + */ + CXCursor_ExceptionSpecificationKind_DynamicNone, + + /** + * The cursor has exception specification throw(T1, T2) + */ + CXCursor_ExceptionSpecificationKind_Dynamic, + + /** + * The cursor has exception specification throw(...). + */ + CXCursor_ExceptionSpecificationKind_MSAny, + + /** + * The cursor has exception specification basic noexcept. + */ + CXCursor_ExceptionSpecificationKind_BasicNoexcept, + + /** + * The cursor has exception specification computed noexcept. + */ + CXCursor_ExceptionSpecificationKind_ComputedNoexcept, + + /** + * The exception specification has not yet been evaluated. + */ + CXCursor_ExceptionSpecificationKind_Unevaluated, + + /** + * The exception specification has not yet been instantiated. + */ + CXCursor_ExceptionSpecificationKind_Uninstantiated, + + /** + * The exception specification has not been parsed yet. + */ + CXCursor_ExceptionSpecificationKind_Unparsed, + + /** + * The cursor has a __declspec(nothrow) exception specification. + */ + CXCursor_ExceptionSpecificationKind_NoThrow +}; + +/** + * Provides a shared context for creating translation units. + * + * It provides two options: + * + * - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local" + * declarations (when loading any new translation units). A "local" declaration + * is one that belongs in the translation unit itself and not in a precompiled + * header that was used by the translation unit. If zero, all declarations + * will be enumerated. + * + * Here is an example: + * + * \code + * // excludeDeclsFromPCH = 1, displayDiagnostics=1 + * Idx = clang_createIndex(1, 1); + * + * // IndexTest.pch was produced with the following command: + * // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch" + * TU = clang_createTranslationUnit(Idx, "IndexTest.pch"); + * + * // This will load all the symbols from 'IndexTest.pch' + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * + * // This will load all the symbols from 'IndexTest.c', excluding symbols + * // from 'IndexTest.pch'. + * char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" }; + * TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args, + * 0, 0); + * clang_visitChildren(clang_getTranslationUnitCursor(TU), + * TranslationUnitVisitor, 0); + * clang_disposeTranslationUnit(TU); + * \endcode + * + * This process of creating the 'pch', loading it separately, and using it (via + * -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks + * (which gives the indexer the same performance benefit as the compiler). + */ +CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics); + +/** + * Destroy the given index. + * + * The index must not be destroyed until all of the translation units created + * within that index have been destroyed. + */ +CINDEX_LINKAGE void clang_disposeIndex(CXIndex index); + +typedef enum { + /** + * Use the default value of an option that may depend on the process + * environment. + */ + CXChoice_Default = 0, + /** + * Enable the option. + */ + CXChoice_Enabled = 1, + /** + * Disable the option. + */ + CXChoice_Disabled = 2 +} CXChoice; + +typedef enum { + /** + * Used to indicate that no special CXIndex options are needed. + */ + CXGlobalOpt_None = 0x0, + + /** + * Used to indicate that threads that libclang creates for indexing + * purposes should use background priority. + * + * Affects #clang_indexSourceFile, #clang_indexTranslationUnit, + * #clang_parseTranslationUnit, #clang_saveTranslationUnit. + */ + CXGlobalOpt_ThreadBackgroundPriorityForIndexing = 0x1, + + /** + * Used to indicate that threads that libclang creates for editing + * purposes should use background priority. + * + * Affects #clang_reparseTranslationUnit, #clang_codeCompleteAt, + * #clang_annotateTokens + */ + CXGlobalOpt_ThreadBackgroundPriorityForEditing = 0x2, + + /** + * Used to indicate that all threads that libclang creates should use + * background priority. + */ + CXGlobalOpt_ThreadBackgroundPriorityForAll = + CXGlobalOpt_ThreadBackgroundPriorityForIndexing | + CXGlobalOpt_ThreadBackgroundPriorityForEditing + +} CXGlobalOptFlags; + +/** + * Index initialization options. + * + * 0 is the default value of each member of this struct except for Size. + * Initialize the struct in one of the following three ways to avoid adapting + * code each time a new member is added to it: + * \code + * CXIndexOptions Opts; + * memset(&Opts, 0, sizeof(Opts)); + * Opts.Size = sizeof(CXIndexOptions); + * \endcode + * or explicitly initialize the first data member and zero-initialize the rest: + * \code + * CXIndexOptions Opts = { sizeof(CXIndexOptions) }; + * \endcode + * or to prevent the -Wmissing-field-initializers warning for the above version: + * \code + * CXIndexOptions Opts{}; + * Opts.Size = sizeof(CXIndexOptions); + * \endcode + */ +typedef struct CXIndexOptions { + /** + * The size of struct CXIndexOptions used for option versioning. + * + * Always initialize this member to sizeof(CXIndexOptions), or assign + * sizeof(CXIndexOptions) to it right after creating a CXIndexOptions object. + */ + unsigned Size; + /** + * A CXChoice enumerator that specifies the indexing priority policy. + * \sa CXGlobalOpt_ThreadBackgroundPriorityForIndexing + */ + unsigned char ThreadBackgroundPriorityForIndexing; + /** + * A CXChoice enumerator that specifies the editing priority policy. + * \sa CXGlobalOpt_ThreadBackgroundPriorityForEditing + */ + unsigned char ThreadBackgroundPriorityForEditing; + /** + * \see clang_createIndex() + */ + unsigned ExcludeDeclarationsFromPCH : 1; + /** + * \see clang_createIndex() + */ + unsigned DisplayDiagnostics : 1; + /** + * Store PCH in memory. If zero, PCH are stored in temporary files. + */ + unsigned StorePreamblesInMemory : 1; + unsigned /*Reserved*/ : 13; + + /** + * The path to a directory, in which to store temporary PCH files. If null or + * empty, the default system temporary directory is used. These PCH files are + * deleted on clean exit but stay on disk if the program crashes or is killed. + * + * This option is ignored if \a StorePreamblesInMemory is non-zero. + * + * Libclang does not create the directory at the specified path in the file + * system. Therefore it must exist, or storing PCH files will fail. + */ + const char *PreambleStoragePath; + /** + * Specifies a path which will contain log files for certain libclang + * invocations. A null value implies that libclang invocations are not logged. + */ + const char *InvocationEmissionPath; +} CXIndexOptions; + +/** + * Provides a shared context for creating translation units. + * + * Call this function instead of clang_createIndex() if you need to configure + * the additional options in CXIndexOptions. + * + * \returns The created index or null in case of error, such as an unsupported + * value of options->Size. + * + * For example: + * \code + * CXIndex createIndex(const char *ApplicationTemporaryPath) { + * const int ExcludeDeclarationsFromPCH = 1; + * const int DisplayDiagnostics = 1; + * CXIndex Idx; + * #if CINDEX_VERSION_MINOR >= 64 + * CXIndexOptions Opts; + * memset(&Opts, 0, sizeof(Opts)); + * Opts.Size = sizeof(CXIndexOptions); + * Opts.ThreadBackgroundPriorityForIndexing = 1; + * Opts.ExcludeDeclarationsFromPCH = ExcludeDeclarationsFromPCH; + * Opts.DisplayDiagnostics = DisplayDiagnostics; + * Opts.PreambleStoragePath = ApplicationTemporaryPath; + * Idx = clang_createIndexWithOptions(&Opts); + * if (Idx) + * return Idx; + * fprintf(stderr, + * "clang_createIndexWithOptions() failed. " + * "CINDEX_VERSION_MINOR = %d, sizeof(CXIndexOptions) = %u\n", + * CINDEX_VERSION_MINOR, Opts.Size); + * #else + * (void)ApplicationTemporaryPath; + * #endif + * Idx = clang_createIndex(ExcludeDeclarationsFromPCH, DisplayDiagnostics); + * clang_CXIndex_setGlobalOptions( + * Idx, clang_CXIndex_getGlobalOptions(Idx) | + * CXGlobalOpt_ThreadBackgroundPriorityForIndexing); + * return Idx; + * } + * \endcode + * + * \sa clang_createIndex() + */ +CINDEX_LINKAGE CXIndex +clang_createIndexWithOptions(const CXIndexOptions *options); + +/** + * Sets general options associated with a CXIndex. + * + * This function is DEPRECATED. Set + * CXIndexOptions::ThreadBackgroundPriorityForIndexing and/or + * CXIndexOptions::ThreadBackgroundPriorityForEditing and call + * clang_createIndexWithOptions() instead. + * + * For example: + * \code + * CXIndex idx = ...; + * clang_CXIndex_setGlobalOptions(idx, + * clang_CXIndex_getGlobalOptions(idx) | + * CXGlobalOpt_ThreadBackgroundPriorityForIndexing); + * \endcode + * + * \param options A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags. + */ +CINDEX_LINKAGE void clang_CXIndex_setGlobalOptions(CXIndex, unsigned options); + +/** + * Gets the general options associated with a CXIndex. + * + * This function allows to obtain the final option values used by libclang after + * specifying the option policies via CXChoice enumerators. + * + * \returns A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags that + * are associated with the given CXIndex object. + */ +CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex); + +/** + * Sets the invocation emission path option in a CXIndex. + * + * This function is DEPRECATED. Set CXIndexOptions::InvocationEmissionPath and + * call clang_createIndexWithOptions() instead. + * + * The invocation emission path specifies a path which will contain log + * files for certain libclang invocations. A null value (default) implies that + * libclang invocations are not logged.. + */ +CINDEX_LINKAGE void +clang_CXIndex_setInvocationEmissionPathOption(CXIndex, const char *Path); + +/** + * Determine whether the given header is guarded against + * multiple inclusions, either with the conventional + * \#ifndef/\#define/\#endif macro guards or with \#pragma once. + */ +CINDEX_LINKAGE unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, + CXFile file); + +/** + * Retrieve a file handle within the given translation unit. + * + * \param tu the translation unit + * + * \param file_name the name of the file. + * + * \returns the file handle for the named file in the translation unit \p tu, + * or a NULL file handle if the file was not a part of this translation unit. + */ +CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu, + const char *file_name); + +/** + * Retrieve the buffer associated with the given file. + * + * \param tu the translation unit + * + * \param file the file for which to retrieve the buffer. + * + * \param size [out] if non-NULL, will be set to the size of the buffer. + * + * \returns a pointer to the buffer in memory that holds the contents of + * \p file, or a NULL pointer when the file is not loaded. + */ +CINDEX_LINKAGE const char *clang_getFileContents(CXTranslationUnit tu, + CXFile file, size_t *size); + +/** + * Retrieves the source location associated with a given file/line/column + * in a particular translation unit. + */ +CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, + CXFile file, unsigned line, + unsigned column); +/** + * Retrieves the source location associated with a given character offset + * in a particular translation unit. + */ +CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, + CXFile file, + unsigned offset); + +/** + * Retrieve all ranges that were skipped by the preprocessor. + * + * The preprocessor will skip lines when they are surrounded by an + * if/ifdef/ifndef directive whose condition does not evaluate to true. + */ +CINDEX_LINKAGE CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit tu, + CXFile file); + +/** + * Retrieve all ranges from all files that were skipped by the + * preprocessor. + * + * The preprocessor will skip lines when they are surrounded by an + * if/ifdef/ifndef directive whose condition does not evaluate to true. + */ +CINDEX_LINKAGE CXSourceRangeList * +clang_getAllSkippedRanges(CXTranslationUnit tu); + +/** + * Determine the number of diagnostics produced for the given + * translation unit. + */ +CINDEX_LINKAGE unsigned clang_getNumDiagnostics(CXTranslationUnit Unit); + +/** + * Retrieve a diagnostic associated with the given translation unit. + * + * \param Unit the translation unit to query. + * \param Index the zero-based diagnostic number to retrieve. + * + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). + */ +CINDEX_LINKAGE CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, + unsigned Index); + +/** + * Retrieve the complete set of diagnostics associated with a + * translation unit. + * + * \param Unit the translation unit to query. + */ +CINDEX_LINKAGE CXDiagnosticSet +clang_getDiagnosticSetFromTU(CXTranslationUnit Unit); + +/** + * \defgroup CINDEX_TRANSLATION_UNIT Translation unit manipulation + * + * The routines in this group provide the ability to create and destroy + * translation units from files, either by parsing the contents of the files or + * by reading in a serialized representation of a translation unit. + * + * @{ + */ + +/** + * Get the original translation unit source file name. + */ +CINDEX_LINKAGE CXString +clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); + +/** + * Return the CXTranslationUnit for a given source file and the provided + * command line arguments one would pass to the compiler. + * + * Note: The 'source_filename' argument is optional. If the caller provides a + * NULL pointer, the name of the source file is expected to reside in the + * specified command line arguments. + * + * Note: When encountered in 'clang_command_line_args', the following options + * are ignored: + * + * '-c' + * '-emit-ast' + * '-fsyntax-only' + * '-o \' (both '-o' and '\' are ignored) + * + * \param CIdx The index object with which the translation unit will be + * associated. + * + * \param source_filename The name of the source file to load, or NULL if the + * source file is included in \p clang_command_line_args. + * + * \param num_clang_command_line_args The number of command-line arguments in + * \p clang_command_line_args. + * + * \param clang_command_line_args The command-line arguments that would be + * passed to the \c clang executable if it were being invoked out-of-process. + * These command-line options will be parsed and will affect how the translation + * unit is parsed. Note that the following options are ignored: '-c', + * '-emit-ast', '-fsyntax-only' (which is the default), and '-o \'. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for code completion, including the contents of + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. + */ +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( + CXIndex CIdx, const char *source_filename, int num_clang_command_line_args, + const char *const *clang_command_line_args, unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files); + +/** + * Same as \c clang_createTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. + */ +CINDEX_LINKAGE CXTranslationUnit +clang_createTranslationUnit(CXIndex CIdx, const char *ast_filename); + +/** + * Create a translation unit from an AST file (\c -emit-ast). + * + * \param[out] out_TU A non-NULL pointer to store the created + * \c CXTranslationUnit. + * + * \returns Zero on success, otherwise returns an error code. + */ +CINDEX_LINKAGE enum CXErrorCode +clang_createTranslationUnit2(CXIndex CIdx, const char *ast_filename, + CXTranslationUnit *out_TU); + +/** + * Flags that control the creation of translation units. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * constructing the translation unit. + */ +enum CXTranslationUnit_Flags { + /** + * Used to indicate that no special translation-unit options are + * needed. + */ + CXTranslationUnit_None = 0x0, + + /** + * Used to indicate that the parser should construct a "detailed" + * preprocessing record, including all macro definitions and instantiations. + * + * Constructing a detailed preprocessing record requires more memory + * and time to parse, since the information contained in the record + * is usually not retained. However, it can be useful for + * applications that require more detailed information about the + * behavior of the preprocessor. + */ + CXTranslationUnit_DetailedPreprocessingRecord = 0x01, + + /** + * Used to indicate that the translation unit is incomplete. + * + * When a translation unit is considered "incomplete", semantic + * analysis that is typically performed at the end of the + * translation unit will be suppressed. For example, this suppresses + * the completion of tentative declarations in C and of + * instantiation of implicitly-instantiation function templates in + * C++. This option is typically used when parsing a header with the + * intent of producing a precompiled header. + */ + CXTranslationUnit_Incomplete = 0x02, + + /** + * Used to indicate that the translation unit should be built with an + * implicit precompiled header for the preamble. + * + * An implicit precompiled header is used as an optimization when a + * particular translation unit is likely to be reparsed many times + * when the sources aren't changing that often. In this case, an + * implicit precompiled header will be built containing all of the + * initial includes at the top of the main file (what we refer to as + * the "preamble" of the file). In subsequent parses, if the + * preamble or the files in it have not changed, \c + * clang_reparseTranslationUnit() will re-use the implicit + * precompiled header to improve parsing performance. + */ + CXTranslationUnit_PrecompiledPreamble = 0x04, + + /** + * Used to indicate that the translation unit should cache some + * code-completion results with each reparse of the source file. + * + * Caching of code-completion results is a performance optimization that + * introduces some overhead to reparsing but improves the performance of + * code-completion operations. + */ + CXTranslationUnit_CacheCompletionResults = 0x08, + + /** + * Used to indicate that the translation unit will be serialized with + * \c clang_saveTranslationUnit. + * + * This option is typically used when parsing a header with the intent of + * producing a precompiled header. + */ + CXTranslationUnit_ForSerialization = 0x10, + + /** + * DEPRECATED: Enabled chained precompiled preambles in C++. + * + * Note: this is a *temporary* option that is available only while + * we are testing C++ precompiled preamble support. It is deprecated. + */ + CXTranslationUnit_CXXChainedPCH = 0x20, + + /** + * Used to indicate that function/method bodies should be skipped while + * parsing. + * + * This option can be used to search for declarations/definitions while + * ignoring the usages. + */ + CXTranslationUnit_SkipFunctionBodies = 0x40, + + /** + * Used to indicate that brief documentation comments should be + * included into the set of code completions returned from this translation + * unit. + */ + CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80, + + /** + * Used to indicate that the precompiled preamble should be created on + * the first parse. Otherwise it will be created on the first reparse. This + * trades runtime on the first parse (serializing the preamble takes time) for + * reduced runtime on the second parse (can now reuse the preamble). + */ + CXTranslationUnit_CreatePreambleOnFirstParse = 0x100, + + /** + * Do not stop processing when fatal errors are encountered. + * + * When fatal errors are encountered while parsing a translation unit, + * semantic analysis is typically stopped early when compiling code. A common + * source for fatal errors are unresolvable include files. For the + * purposes of an IDE, this is undesirable behavior and as much information + * as possible should be reported. Use this flag to enable this behavior. + */ + CXTranslationUnit_KeepGoing = 0x200, + + /** + * Sets the preprocessor in a mode for parsing a single file only. + */ + CXTranslationUnit_SingleFileParse = 0x400, + + /** + * Used in combination with CXTranslationUnit_SkipFunctionBodies to + * constrain the skipping of function bodies to the preamble. + * + * The function bodies of the main file are not skipped. + */ + CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 0x800, + + /** + * Used to indicate that attributed types should be included in CXType. + */ + CXTranslationUnit_IncludeAttributedTypes = 0x1000, + + /** + * Used to indicate that implicit attributes should be visited. + */ + CXTranslationUnit_VisitImplicitAttributes = 0x2000, + + /** + * Used to indicate that non-errors from included files should be ignored. + * + * If set, clang_getDiagnosticSetFromTU() will not report e.g. warnings from + * included files anymore. This speeds up clang_getDiagnosticSetFromTU() for + * the case where these warnings are not of interest, as for an IDE for + * example, which typically shows only the diagnostics in the main file. + */ + CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles = 0x4000, + + /** + * Tells the preprocessor not to skip excluded conditional blocks. + */ + CXTranslationUnit_RetainExcludedConditionalBlocks = 0x8000 +}; + +/** + * Returns the set of flags that is suitable for parsing a translation + * unit that is being edited. + * + * The set of flags returned provide options for \c clang_parseTranslationUnit() + * to indicate that the translation unit is likely to be reparsed many times, + * either explicitly (via \c clang_reparseTranslationUnit()) or implicitly + * (e.g., by code completion (\c clang_codeCompletionAt())). The returned flag + * set contains an unspecified set of optimizations (e.g., the precompiled + * preamble) geared toward improving the performance of these routines. The + * set of optimizations enabled may change from one version to the next. + */ +CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); + +/** + * Same as \c clang_parseTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. + */ +CINDEX_LINKAGE CXTranslationUnit clang_parseTranslationUnit( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options); + +/** + * Parse the given source file and the translation unit corresponding + * to that file. + * + * This routine is the main entry point for the Clang C API, providing the + * ability to parse a source file into a translation unit that can then be + * queried by other functions in the API. This routine accepts a set of + * command-line arguments so that the compilation can be configured in the same + * way that the compiler is configured on the command line. + * + * \param CIdx The index object with which the translation unit will be + * associated. + * + * \param source_filename The name of the source file to load, or NULL if the + * source file is included in \c command_line_args. + * + * \param command_line_args The command-line arguments that would be + * passed to the \c clang executable if it were being invoked out-of-process. + * These command-line options will be parsed and will affect how the translation + * unit is parsed. Note that the following options are ignored: '-c', + * '-emit-ast', '-fsyntax-only' (which is the default), and '-o \'. + * + * \param num_command_line_args The number of command-line arguments in + * \c command_line_args. + * + * \param unsaved_files the files that have not yet been saved to disk + * but may be required for parsing, including the contents of + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. + * + * \param num_unsaved_files the number of unsaved file entries in \p + * unsaved_files. + * + * \param options A bitmask of options that affects how the translation unit + * is managed but not its compilation. This should be a bitwise OR of the + * CXTranslationUnit_XXX flags. + * + * \param[out] out_TU A non-NULL pointer to store the created + * \c CXTranslationUnit, describing the parsed code and containing any + * diagnostics produced by the compiler. + * + * \returns Zero on success, otherwise returns an error code. + */ +CINDEX_LINKAGE enum CXErrorCode clang_parseTranslationUnit2( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU); + +/** + * Same as clang_parseTranslationUnit2 but requires a full command line + * for \c command_line_args including argv[0]. This is useful if the standard + * library paths are relative to the binary. + */ +CINDEX_LINKAGE enum CXErrorCode clang_parseTranslationUnit2FullArgv( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU); + +/** + * Flags that control how translation units are saved. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * saving the translation unit. + */ +enum CXSaveTranslationUnit_Flags { + /** + * Used to indicate that no special saving options are needed. + */ + CXSaveTranslationUnit_None = 0x0 +}; + +/** + * Returns the set of flags that is suitable for saving a translation + * unit. + * + * The set of flags returned provide options for + * \c clang_saveTranslationUnit() by default. The returned flag + * set contains an unspecified set of options that save translation units with + * the most commonly-requested data. + */ +CINDEX_LINKAGE unsigned clang_defaultSaveOptions(CXTranslationUnit TU); + +/** + * Describes the kind of error that occurred (if any) in a call to + * \c clang_saveTranslationUnit(). + */ +enum CXSaveError { + /** + * Indicates that no error occurred while saving a translation unit. + */ + CXSaveError_None = 0, + + /** + * Indicates that an unknown error occurred while attempting to save + * the file. + * + * This error typically indicates that file I/O failed when attempting to + * write the file. + */ + CXSaveError_Unknown = 1, + + /** + * Indicates that errors during translation prevented this attempt + * to save the translation unit. + * + * Errors that prevent the translation unit from being saved can be + * extracted using \c clang_getNumDiagnostics() and \c clang_getDiagnostic(). + */ + CXSaveError_TranslationErrors = 2, + + /** + * Indicates that the translation unit to be saved was somehow + * invalid (e.g., NULL). + */ + CXSaveError_InvalidTU = 3 +}; + +/** + * Saves a translation unit into a serialized representation of + * that translation unit on disk. + * + * Any translation unit that was parsed without error can be saved + * into a file. The translation unit can then be deserialized into a + * new \c CXTranslationUnit with \c clang_createTranslationUnit() or, + * if it is an incomplete translation unit that corresponds to a + * header, used as a precompiled header when parsing other translation + * units. + * + * \param TU The translation unit to save. + * + * \param FileName The file to which the translation unit will be saved. + * + * \param options A bitmask of options that affects how the translation unit + * is saved. This should be a bitwise OR of the + * CXSaveTranslationUnit_XXX flags. + * + * \returns A value that will match one of the enumerators of the CXSaveError + * enumeration. Zero (CXSaveError_None) indicates that the translation unit was + * saved successfully, while a non-zero value indicates that a problem occurred. + */ +CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU, + const char *FileName, + unsigned options); + +/** + * Suspend a translation unit in order to free memory associated with it. + * + * A suspended translation unit uses significantly less memory but on the other + * side does not support any other calls than \c clang_reparseTranslationUnit + * to resume it or \c clang_disposeTranslationUnit to dispose it completely. + */ +CINDEX_LINKAGE unsigned clang_suspendTranslationUnit(CXTranslationUnit); + +/** + * Destroy the specified CXTranslationUnit object. + */ +CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); + +/** + * Flags that control the reparsing of translation units. + * + * The enumerators in this enumeration type are meant to be bitwise + * ORed together to specify which options should be used when + * reparsing the translation unit. + */ +enum CXReparse_Flags { + /** + * Used to indicate that no special reparsing options are needed. + */ + CXReparse_None = 0x0 +}; + +/** + * Returns the set of flags that is suitable for reparsing a translation + * unit. + * + * The set of flags returned provide options for + * \c clang_reparseTranslationUnit() by default. The returned flag + * set contains an unspecified set of optimizations geared toward common uses + * of reparsing. The set of optimizations enabled may change from one version + * to the next. + */ +CINDEX_LINKAGE unsigned clang_defaultReparseOptions(CXTranslationUnit TU); + +/** + * Reparse the source files that produced this translation unit. + * + * This routine can be used to re-parse the source files that originally + * created the given translation unit, for example because those source files + * have changed (either on disk or as passed via \p unsaved_files). The + * source code will be reparsed with the same command-line options as it + * was originally parsed. + * + * Reparsing a translation unit invalidates all cursors and source locations + * that refer into that translation unit. This makes reparsing a translation + * unit semantically equivalent to destroying the translation unit and then + * creating a new translation unit with the same command-line arguments. + * However, it may be more efficient to reparse a translation + * unit using this routine. + * + * \param TU The translation unit whose contents will be re-parsed. The + * translation unit must originally have been built with + * \c clang_createTranslationUnitFromSourceFile(). + * + * \param num_unsaved_files The number of unsaved file entries in \p + * unsaved_files. + * + * \param unsaved_files The files that have not yet been saved to disk + * but may be required for parsing, including the contents of + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. + * + * \param options A bitset of options composed of the flags in CXReparse_Flags. + * The function \c clang_defaultReparseOptions() produces a default set of + * options recommended for most uses, based on the translation unit. + * + * \returns 0 if the sources could be reparsed. A non-zero error code will be + * returned if reparsing was impossible, such that the translation unit is + * invalid. In such cases, the only valid call for \c TU is + * \c clang_disposeTranslationUnit(TU). The error codes returned by this + * routine are described by the \c CXErrorCode enum. + */ +CINDEX_LINKAGE int +clang_reparseTranslationUnit(CXTranslationUnit TU, unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options); + +/** + * Categorizes how memory is being used by a translation unit. + */ +enum CXTUResourceUsageKind { + CXTUResourceUsage_AST = 1, + CXTUResourceUsage_Identifiers = 2, + CXTUResourceUsage_Selectors = 3, + CXTUResourceUsage_GlobalCompletionResults = 4, + CXTUResourceUsage_SourceManagerContentCache = 5, + CXTUResourceUsage_AST_SideTables = 6, + CXTUResourceUsage_SourceManager_Membuffer_Malloc = 7, + CXTUResourceUsage_SourceManager_Membuffer_MMap = 8, + CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc = 9, + CXTUResourceUsage_ExternalASTSource_Membuffer_MMap = 10, + CXTUResourceUsage_Preprocessor = 11, + CXTUResourceUsage_PreprocessingRecord = 12, + CXTUResourceUsage_SourceManager_DataStructures = 13, + CXTUResourceUsage_Preprocessor_HeaderSearch = 14, + CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST, + CXTUResourceUsage_MEMORY_IN_BYTES_END = + CXTUResourceUsage_Preprocessor_HeaderSearch, + + CXTUResourceUsage_First = CXTUResourceUsage_AST, + CXTUResourceUsage_Last = CXTUResourceUsage_Preprocessor_HeaderSearch +}; + +/** + * Returns the human-readable null-terminated C string that represents + * the name of the memory category. This string should never be freed. + */ +CINDEX_LINKAGE +const char *clang_getTUResourceUsageName(enum CXTUResourceUsageKind kind); + +typedef struct CXTUResourceUsageEntry { + /* The memory usage category. */ + enum CXTUResourceUsageKind kind; + /* Amount of resources used. + The units will depend on the resource kind. */ + unsigned long amount; +} CXTUResourceUsageEntry; + +/** + * The memory usage of a CXTranslationUnit, broken into categories. + */ +typedef struct CXTUResourceUsage { + /* Private data member, used for queries. */ + void *data; + + /* The number of entries in the 'entries' array. */ + unsigned numEntries; + + /* An array of key-value pairs, representing the breakdown of memory + usage. */ + CXTUResourceUsageEntry *entries; + +} CXTUResourceUsage; + +/** + * Return the memory usage of a translation unit. This object + * should be released with clang_disposeCXTUResourceUsage(). + */ +CINDEX_LINKAGE CXTUResourceUsage +clang_getCXTUResourceUsage(CXTranslationUnit TU); + +CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage); + +/** + * Get target information for this translation unit. + * + * The CXTargetInfo object cannot outlive the CXTranslationUnit object. + */ +CINDEX_LINKAGE CXTargetInfo +clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit); + +/** + * Destroy the CXTargetInfo object. + */ +CINDEX_LINKAGE void clang_TargetInfo_dispose(CXTargetInfo Info); + +/** + * Get the normalized target triple as a string. + * + * Returns the empty string in case of any error. + */ +CINDEX_LINKAGE CXString clang_TargetInfo_getTriple(CXTargetInfo Info); + +/** + * Get the pointer width of the target in bits. + * + * Returns -1 in case of error. + */ +CINDEX_LINKAGE int clang_TargetInfo_getPointerWidth(CXTargetInfo Info); + +/** + * @} + */ + +/** + * Describes the kind of entity that a cursor refers to. + */ +enum CXCursorKind { + /* Declarations */ + /** + * A declaration whose specific kind is not exposed via this + * interface. + * + * Unexposed declarations have the same operations as any other kind + * of declaration; one can extract their location information, + * spelling, find their definitions, etc. However, the specific kind + * of the declaration is not reported. + */ + CXCursor_UnexposedDecl = 1, + /** A C or C++ struct. */ + CXCursor_StructDecl = 2, + /** A C or C++ union. */ + CXCursor_UnionDecl = 3, + /** A C++ class. */ + CXCursor_ClassDecl = 4, + /** An enumeration. */ + CXCursor_EnumDecl = 5, + /** + * A field (in C) or non-static data member (in C++) in a + * struct, union, or C++ class. + */ + CXCursor_FieldDecl = 6, + /** An enumerator constant. */ + CXCursor_EnumConstantDecl = 7, + /** A function. */ + CXCursor_FunctionDecl = 8, + /** A variable. */ + CXCursor_VarDecl = 9, + /** A function or method parameter. */ + CXCursor_ParmDecl = 10, + /** An Objective-C \@interface. */ + CXCursor_ObjCInterfaceDecl = 11, + /** An Objective-C \@interface for a category. */ + CXCursor_ObjCCategoryDecl = 12, + /** An Objective-C \@protocol declaration. */ + CXCursor_ObjCProtocolDecl = 13, + /** An Objective-C \@property declaration. */ + CXCursor_ObjCPropertyDecl = 14, + /** An Objective-C instance variable. */ + CXCursor_ObjCIvarDecl = 15, + /** An Objective-C instance method. */ + CXCursor_ObjCInstanceMethodDecl = 16, + /** An Objective-C class method. */ + CXCursor_ObjCClassMethodDecl = 17, + /** An Objective-C \@implementation. */ + CXCursor_ObjCImplementationDecl = 18, + /** An Objective-C \@implementation for a category. */ + CXCursor_ObjCCategoryImplDecl = 19, + /** A typedef. */ + CXCursor_TypedefDecl = 20, + /** A C++ class method. */ + CXCursor_CXXMethod = 21, + /** A C++ namespace. */ + CXCursor_Namespace = 22, + /** A linkage specification, e.g. 'extern "C"'. */ + CXCursor_LinkageSpec = 23, + /** A C++ constructor. */ + CXCursor_Constructor = 24, + /** A C++ destructor. */ + CXCursor_Destructor = 25, + /** A C++ conversion function. */ + CXCursor_ConversionFunction = 26, + /** A C++ template type parameter. */ + CXCursor_TemplateTypeParameter = 27, + /** A C++ non-type template parameter. */ + CXCursor_NonTypeTemplateParameter = 28, + /** A C++ template template parameter. */ + CXCursor_TemplateTemplateParameter = 29, + /** A C++ function template. */ + CXCursor_FunctionTemplate = 30, + /** A C++ class template. */ + CXCursor_ClassTemplate = 31, + /** A C++ class template partial specialization. */ + CXCursor_ClassTemplatePartialSpecialization = 32, + /** A C++ namespace alias declaration. */ + CXCursor_NamespaceAlias = 33, + /** A C++ using directive. */ + CXCursor_UsingDirective = 34, + /** A C++ using declaration. */ + CXCursor_UsingDeclaration = 35, + /** A C++ alias declaration */ + CXCursor_TypeAliasDecl = 36, + /** An Objective-C \@synthesize definition. */ + CXCursor_ObjCSynthesizeDecl = 37, + /** An Objective-C \@dynamic definition. */ + CXCursor_ObjCDynamicDecl = 38, + /** An access specifier. */ + CXCursor_CXXAccessSpecifier = 39, + + CXCursor_FirstDecl = CXCursor_UnexposedDecl, + CXCursor_LastDecl = CXCursor_CXXAccessSpecifier, + + /* References */ + CXCursor_FirstRef = 40, /* Decl references */ + CXCursor_ObjCSuperClassRef = 40, + CXCursor_ObjCProtocolRef = 41, + CXCursor_ObjCClassRef = 42, + /** + * A reference to a type declaration. + * + * A type reference occurs anywhere where a type is named but not + * declared. For example, given: + * + * \code + * typedef unsigned size_type; + * size_type size; + * \endcode + * + * The typedef is a declaration of size_type (CXCursor_TypedefDecl), + * while the type of the variable "size" is referenced. The cursor + * referenced by the type of size is the typedef for size_type. + */ + CXCursor_TypeRef = 43, + CXCursor_CXXBaseSpecifier = 44, + /** + * A reference to a class template, function template, template + * template parameter, or class template partial specialization. + */ + CXCursor_TemplateRef = 45, + /** + * A reference to a namespace or namespace alias. + */ + CXCursor_NamespaceRef = 46, + /** + * A reference to a member of a struct, union, or class that occurs in + * some non-expression context, e.g., a designated initializer. + */ + CXCursor_MemberRef = 47, + /** + * A reference to a labeled statement. + * + * This cursor kind is used to describe the jump to "start_over" in the + * goto statement in the following example: + * + * \code + * start_over: + * ++counter; + * + * goto start_over; + * \endcode + * + * A label reference cursor refers to a label statement. + */ + CXCursor_LabelRef = 48, + + /** + * A reference to a set of overloaded functions or function templates + * that has not yet been resolved to a specific function or function template. + * + * An overloaded declaration reference cursor occurs in C++ templates where + * a dependent name refers to a function. For example: + * + * \code + * template void swap(T&, T&); + * + * struct X { ... }; + * void swap(X&, X&); + * + * template + * void reverse(T* first, T* last) { + * while (first < last - 1) { + * swap(*first, *--last); + * ++first; + * } + * } + * + * struct Y { }; + * void swap(Y&, Y&); + * \endcode + * + * Here, the identifier "swap" is associated with an overloaded declaration + * reference. In the template definition, "swap" refers to either of the two + * "swap" functions declared above, so both results will be available. At + * instantiation time, "swap" may also refer to other functions found via + * argument-dependent lookup (e.g., the "swap" function at the end of the + * example). + * + * The functions \c clang_getNumOverloadedDecls() and + * \c clang_getOverloadedDecl() can be used to retrieve the definitions + * referenced by this cursor. + */ + CXCursor_OverloadedDeclRef = 49, + + /** + * A reference to a variable that occurs in some non-expression + * context, e.g., a C++ lambda capture list. + */ + CXCursor_VariableRef = 50, + + CXCursor_LastRef = CXCursor_VariableRef, + + /* Error conditions */ + CXCursor_FirstInvalid = 70, + CXCursor_InvalidFile = 70, + CXCursor_NoDeclFound = 71, + CXCursor_NotImplemented = 72, + CXCursor_InvalidCode = 73, + CXCursor_LastInvalid = CXCursor_InvalidCode, + + /* Expressions */ + CXCursor_FirstExpr = 100, + + /** + * An expression whose specific kind is not exposed via this + * interface. + * + * Unexposed expressions have the same operations as any other kind + * of expression; one can extract their location information, + * spelling, children, etc. However, the specific kind of the + * expression is not reported. + */ + CXCursor_UnexposedExpr = 100, + + /** + * An expression that refers to some value declaration, such + * as a function, variable, or enumerator. + */ + CXCursor_DeclRefExpr = 101, + + /** + * An expression that refers to a member of a struct, union, + * class, Objective-C class, etc. + */ + CXCursor_MemberRefExpr = 102, + + /** An expression that calls a function. */ + CXCursor_CallExpr = 103, + + /** An expression that sends a message to an Objective-C + object or class. */ + CXCursor_ObjCMessageExpr = 104, + + /** An expression that represents a block literal. */ + CXCursor_BlockExpr = 105, + + /** An integer literal. + */ + CXCursor_IntegerLiteral = 106, + + /** A floating point number literal. + */ + CXCursor_FloatingLiteral = 107, + + /** An imaginary number literal. + */ + CXCursor_ImaginaryLiteral = 108, + + /** A string literal. + */ + CXCursor_StringLiteral = 109, + + /** A character literal. + */ + CXCursor_CharacterLiteral = 110, + + /** A parenthesized expression, e.g. "(1)". + * + * This AST node is only formed if full location information is requested. + */ + CXCursor_ParenExpr = 111, + + /** This represents the unary-expression's (except sizeof and + * alignof). + */ + CXCursor_UnaryOperator = 112, + + /** [C99 6.5.2.1] Array Subscripting. + */ + CXCursor_ArraySubscriptExpr = 113, + + /** A builtin binary operation expression such as "x + y" or + * "x <= y". + */ + CXCursor_BinaryOperator = 114, + + /** Compound assignment such as "+=". + */ + CXCursor_CompoundAssignOperator = 115, + + /** The ?: ternary operator. + */ + CXCursor_ConditionalOperator = 116, + + /** An explicit cast in C (C99 6.5.4) or a C-style cast in C++ + * (C++ [expr.cast]), which uses the syntax (Type)expr. + * + * For example: (int)f. + */ + CXCursor_CStyleCastExpr = 117, + + /** [C99 6.5.2.5] + */ + CXCursor_CompoundLiteralExpr = 118, + + /** Describes an C or C++ initializer list. + */ + CXCursor_InitListExpr = 119, + + /** The GNU address of label extension, representing &&label. + */ + CXCursor_AddrLabelExpr = 120, + + /** This is the GNU Statement Expression extension: ({int X=4; X;}) + */ + CXCursor_StmtExpr = 121, + + /** Represents a C11 generic selection. + */ + CXCursor_GenericSelectionExpr = 122, + + /** Implements the GNU __null extension, which is a name for a null + * pointer constant that has integral type (e.g., int or long) and is the same + * size and alignment as a pointer. + * + * The __null extension is typically only used by system headers, which define + * NULL as __null in C++ rather than using 0 (which is an integer that may not + * match the size of a pointer). + */ + CXCursor_GNUNullExpr = 123, + + /** C++'s static_cast<> expression. + */ + CXCursor_CXXStaticCastExpr = 124, + + /** C++'s dynamic_cast<> expression. + */ + CXCursor_CXXDynamicCastExpr = 125, + + /** C++'s reinterpret_cast<> expression. + */ + CXCursor_CXXReinterpretCastExpr = 126, + + /** C++'s const_cast<> expression. + */ + CXCursor_CXXConstCastExpr = 127, + + /** Represents an explicit C++ type conversion that uses "functional" + * notion (C++ [expr.type.conv]). + * + * Example: + * \code + * x = int(0.5); + * \endcode + */ + CXCursor_CXXFunctionalCastExpr = 128, + + /** A C++ typeid expression (C++ [expr.typeid]). + */ + CXCursor_CXXTypeidExpr = 129, + + /** [C++ 2.13.5] C++ Boolean Literal. + */ + CXCursor_CXXBoolLiteralExpr = 130, + + /** [C++0x 2.14.7] C++ Pointer Literal. + */ + CXCursor_CXXNullPtrLiteralExpr = 131, + + /** Represents the "this" expression in C++ + */ + CXCursor_CXXThisExpr = 132, + + /** [C++ 15] C++ Throw Expression. + * + * This handles 'throw' and 'throw' assignment-expression. When + * assignment-expression isn't present, Op will be null. + */ + CXCursor_CXXThrowExpr = 133, + + /** A new expression for memory allocation and constructor calls, e.g: + * "new CXXNewExpr(foo)". + */ + CXCursor_CXXNewExpr = 134, + + /** A delete expression for memory deallocation and destructor calls, + * e.g. "delete[] pArray". + */ + CXCursor_CXXDeleteExpr = 135, + + /** A unary expression. (noexcept, sizeof, or other traits) + */ + CXCursor_UnaryExpr = 136, + + /** An Objective-C string literal i.e. @"foo". + */ + CXCursor_ObjCStringLiteral = 137, + + /** An Objective-C \@encode expression. + */ + CXCursor_ObjCEncodeExpr = 138, + + /** An Objective-C \@selector expression. + */ + CXCursor_ObjCSelectorExpr = 139, + + /** An Objective-C \@protocol expression. + */ + CXCursor_ObjCProtocolExpr = 140, + + /** An Objective-C "bridged" cast expression, which casts between + * Objective-C pointers and C pointers, transferring ownership in the process. + * + * \code + * NSString *str = (__bridge_transfer NSString *)CFCreateString(); + * \endcode + */ + CXCursor_ObjCBridgedCastExpr = 141, + + /** Represents a C++0x pack expansion that produces a sequence of + * expressions. + * + * A pack expansion expression contains a pattern (which itself is an + * expression) followed by an ellipsis. For example: + * + * \code + * template + * void forward(F f, Types &&...args) { + * f(static_cast(args)...); + * } + * \endcode + */ + CXCursor_PackExpansionExpr = 142, + + /** Represents an expression that computes the length of a parameter + * pack. + * + * \code + * template + * struct count { + * static const unsigned value = sizeof...(Types); + * }; + * \endcode + */ + CXCursor_SizeOfPackExpr = 143, + + /* Represents a C++ lambda expression that produces a local function + * object. + * + * \code + * void abssort(float *x, unsigned N) { + * std::sort(x, x + N, + * [](float a, float b) { + * return std::abs(a) < std::abs(b); + * }); + * } + * \endcode + */ + CXCursor_LambdaExpr = 144, + + /** Objective-c Boolean Literal. + */ + CXCursor_ObjCBoolLiteralExpr = 145, + + /** Represents the "self" expression in an Objective-C method. + */ + CXCursor_ObjCSelfExpr = 146, + + /** OpenMP 5.0 [2.1.5, Array Section]. + */ + CXCursor_OMPArraySectionExpr = 147, + + /** Represents an @available(...) check. + */ + CXCursor_ObjCAvailabilityCheckExpr = 148, + + /** + * Fixed point literal + */ + CXCursor_FixedPointLiteral = 149, + + /** OpenMP 5.0 [2.1.4, Array Shaping]. + */ + CXCursor_OMPArrayShapingExpr = 150, + + /** + * OpenMP 5.0 [2.1.6 Iterators] + */ + CXCursor_OMPIteratorExpr = 151, + + /** OpenCL's addrspace_cast<> expression. + */ + CXCursor_CXXAddrspaceCastExpr = 152, + + /** + * Expression that references a C++20 concept. + */ + CXCursor_ConceptSpecializationExpr = 153, + + /** + * Expression that references a C++20 concept. + */ + CXCursor_RequiresExpr = 154, + + /** + * Expression that references a C++20 parenthesized list aggregate + * initializer. + */ + CXCursor_CXXParenListInitExpr = 155, + + CXCursor_LastExpr = CXCursor_CXXParenListInitExpr, + + /* Statements */ + CXCursor_FirstStmt = 200, + /** + * A statement whose specific kind is not exposed via this + * interface. + * + * Unexposed statements have the same operations as any other kind of + * statement; one can extract their location information, spelling, + * children, etc. However, the specific kind of the statement is not + * reported. + */ + CXCursor_UnexposedStmt = 200, + + /** A labelled statement in a function. + * + * This cursor kind is used to describe the "start_over:" label statement in + * the following example: + * + * \code + * start_over: + * ++counter; + * \endcode + * + */ + CXCursor_LabelStmt = 201, + + /** A group of statements like { stmt stmt }. + * + * This cursor kind is used to describe compound statements, e.g. function + * bodies. + */ + CXCursor_CompoundStmt = 202, + + /** A case statement. + */ + CXCursor_CaseStmt = 203, + + /** A default statement. + */ + CXCursor_DefaultStmt = 204, + + /** An if statement + */ + CXCursor_IfStmt = 205, + + /** A switch statement. + */ + CXCursor_SwitchStmt = 206, + + /** A while statement. + */ + CXCursor_WhileStmt = 207, + + /** A do statement. + */ + CXCursor_DoStmt = 208, + + /** A for statement. + */ + CXCursor_ForStmt = 209, + + /** A goto statement. + */ + CXCursor_GotoStmt = 210, + + /** An indirect goto statement. + */ + CXCursor_IndirectGotoStmt = 211, + + /** A continue statement. + */ + CXCursor_ContinueStmt = 212, + + /** A break statement. + */ + CXCursor_BreakStmt = 213, + + /** A return statement. + */ + CXCursor_ReturnStmt = 214, + + /** A GCC inline assembly statement extension. + */ + CXCursor_GCCAsmStmt = 215, + CXCursor_AsmStmt = CXCursor_GCCAsmStmt, + + /** Objective-C's overall \@try-\@catch-\@finally statement. + */ + CXCursor_ObjCAtTryStmt = 216, + + /** Objective-C's \@catch statement. + */ + CXCursor_ObjCAtCatchStmt = 217, + + /** Objective-C's \@finally statement. + */ + CXCursor_ObjCAtFinallyStmt = 218, + + /** Objective-C's \@throw statement. + */ + CXCursor_ObjCAtThrowStmt = 219, + + /** Objective-C's \@synchronized statement. + */ + CXCursor_ObjCAtSynchronizedStmt = 220, + + /** Objective-C's autorelease pool statement. + */ + CXCursor_ObjCAutoreleasePoolStmt = 221, + + /** Objective-C's collection statement. + */ + CXCursor_ObjCForCollectionStmt = 222, + + /** C++'s catch statement. + */ + CXCursor_CXXCatchStmt = 223, + + /** C++'s try statement. + */ + CXCursor_CXXTryStmt = 224, + + /** C++'s for (* : *) statement. + */ + CXCursor_CXXForRangeStmt = 225, + + /** Windows Structured Exception Handling's try statement. + */ + CXCursor_SEHTryStmt = 226, + + /** Windows Structured Exception Handling's except statement. + */ + CXCursor_SEHExceptStmt = 227, + + /** Windows Structured Exception Handling's finally statement. + */ + CXCursor_SEHFinallyStmt = 228, + + /** A MS inline assembly statement extension. + */ + CXCursor_MSAsmStmt = 229, + + /** The null statement ";": C99 6.8.3p3. + * + * This cursor kind is used to describe the null statement. + */ + CXCursor_NullStmt = 230, + + /** Adaptor class for mixing declarations with statements and + * expressions. + */ + CXCursor_DeclStmt = 231, + + /** OpenMP parallel directive. + */ + CXCursor_OMPParallelDirective = 232, + + /** OpenMP SIMD directive. + */ + CXCursor_OMPSimdDirective = 233, + + /** OpenMP for directive. + */ + CXCursor_OMPForDirective = 234, + + /** OpenMP sections directive. + */ + CXCursor_OMPSectionsDirective = 235, + + /** OpenMP section directive. + */ + CXCursor_OMPSectionDirective = 236, + + /** OpenMP single directive. + */ + CXCursor_OMPSingleDirective = 237, + + /** OpenMP parallel for directive. + */ + CXCursor_OMPParallelForDirective = 238, + + /** OpenMP parallel sections directive. + */ + CXCursor_OMPParallelSectionsDirective = 239, + + /** OpenMP task directive. + */ + CXCursor_OMPTaskDirective = 240, + + /** OpenMP master directive. + */ + CXCursor_OMPMasterDirective = 241, + + /** OpenMP critical directive. + */ + CXCursor_OMPCriticalDirective = 242, + + /** OpenMP taskyield directive. + */ + CXCursor_OMPTaskyieldDirective = 243, + + /** OpenMP barrier directive. + */ + CXCursor_OMPBarrierDirective = 244, + + /** OpenMP taskwait directive. + */ + CXCursor_OMPTaskwaitDirective = 245, + + /** OpenMP flush directive. + */ + CXCursor_OMPFlushDirective = 246, + + /** Windows Structured Exception Handling's leave statement. + */ + CXCursor_SEHLeaveStmt = 247, + + /** OpenMP ordered directive. + */ + CXCursor_OMPOrderedDirective = 248, + + /** OpenMP atomic directive. + */ + CXCursor_OMPAtomicDirective = 249, + + /** OpenMP for SIMD directive. + */ + CXCursor_OMPForSimdDirective = 250, + + /** OpenMP parallel for SIMD directive. + */ + CXCursor_OMPParallelForSimdDirective = 251, + + /** OpenMP target directive. + */ + CXCursor_OMPTargetDirective = 252, + + /** OpenMP teams directive. + */ + CXCursor_OMPTeamsDirective = 253, + + /** OpenMP taskgroup directive. + */ + CXCursor_OMPTaskgroupDirective = 254, + + /** OpenMP cancellation point directive. + */ + CXCursor_OMPCancellationPointDirective = 255, + + /** OpenMP cancel directive. + */ + CXCursor_OMPCancelDirective = 256, + + /** OpenMP target data directive. + */ + CXCursor_OMPTargetDataDirective = 257, + + /** OpenMP taskloop directive. + */ + CXCursor_OMPTaskLoopDirective = 258, + + /** OpenMP taskloop simd directive. + */ + CXCursor_OMPTaskLoopSimdDirective = 259, + + /** OpenMP distribute directive. + */ + CXCursor_OMPDistributeDirective = 260, + + /** OpenMP target enter data directive. + */ + CXCursor_OMPTargetEnterDataDirective = 261, + + /** OpenMP target exit data directive. + */ + CXCursor_OMPTargetExitDataDirective = 262, + + /** OpenMP target parallel directive. + */ + CXCursor_OMPTargetParallelDirective = 263, + + /** OpenMP target parallel for directive. + */ + CXCursor_OMPTargetParallelForDirective = 264, + + /** OpenMP target update directive. + */ + CXCursor_OMPTargetUpdateDirective = 265, + + /** OpenMP distribute parallel for directive. + */ + CXCursor_OMPDistributeParallelForDirective = 266, + + /** OpenMP distribute parallel for simd directive. + */ + CXCursor_OMPDistributeParallelForSimdDirective = 267, + + /** OpenMP distribute simd directive. + */ + CXCursor_OMPDistributeSimdDirective = 268, + + /** OpenMP target parallel for simd directive. + */ + CXCursor_OMPTargetParallelForSimdDirective = 269, + + /** OpenMP target simd directive. + */ + CXCursor_OMPTargetSimdDirective = 270, + + /** OpenMP teams distribute directive. + */ + CXCursor_OMPTeamsDistributeDirective = 271, + + /** OpenMP teams distribute simd directive. + */ + CXCursor_OMPTeamsDistributeSimdDirective = 272, + + /** OpenMP teams distribute parallel for simd directive. + */ + CXCursor_OMPTeamsDistributeParallelForSimdDirective = 273, + + /** OpenMP teams distribute parallel for directive. + */ + CXCursor_OMPTeamsDistributeParallelForDirective = 274, + + /** OpenMP target teams directive. + */ + CXCursor_OMPTargetTeamsDirective = 275, + + /** OpenMP target teams distribute directive. + */ + CXCursor_OMPTargetTeamsDistributeDirective = 276, + + /** OpenMP target teams distribute parallel for directive. + */ + CXCursor_OMPTargetTeamsDistributeParallelForDirective = 277, + + /** OpenMP target teams distribute parallel for simd directive. + */ + CXCursor_OMPTargetTeamsDistributeParallelForSimdDirective = 278, + + /** OpenMP target teams distribute simd directive. + */ + CXCursor_OMPTargetTeamsDistributeSimdDirective = 279, + + /** C++2a std::bit_cast expression. + */ + CXCursor_BuiltinBitCastExpr = 280, + + /** OpenMP master taskloop directive. + */ + CXCursor_OMPMasterTaskLoopDirective = 281, + + /** OpenMP parallel master taskloop directive. + */ + CXCursor_OMPParallelMasterTaskLoopDirective = 282, + + /** OpenMP master taskloop simd directive. + */ + CXCursor_OMPMasterTaskLoopSimdDirective = 283, + + /** OpenMP parallel master taskloop simd directive. + */ + CXCursor_OMPParallelMasterTaskLoopSimdDirective = 284, + + /** OpenMP parallel master directive. + */ + CXCursor_OMPParallelMasterDirective = 285, + + /** OpenMP depobj directive. + */ + CXCursor_OMPDepobjDirective = 286, + + /** OpenMP scan directive. + */ + CXCursor_OMPScanDirective = 287, + + /** OpenMP tile directive. + */ + CXCursor_OMPTileDirective = 288, + + /** OpenMP canonical loop. + */ + CXCursor_OMPCanonicalLoop = 289, + + /** OpenMP interop directive. + */ + CXCursor_OMPInteropDirective = 290, + + /** OpenMP dispatch directive. + */ + CXCursor_OMPDispatchDirective = 291, + + /** OpenMP masked directive. + */ + CXCursor_OMPMaskedDirective = 292, + + /** OpenMP unroll directive. + */ + CXCursor_OMPUnrollDirective = 293, + + /** OpenMP metadirective directive. + */ + CXCursor_OMPMetaDirective = 294, + + /** OpenMP loop directive. + */ + CXCursor_OMPGenericLoopDirective = 295, + + /** OpenMP teams loop directive. + */ + CXCursor_OMPTeamsGenericLoopDirective = 296, + + /** OpenMP target teams loop directive. + */ + CXCursor_OMPTargetTeamsGenericLoopDirective = 297, + + /** OpenMP parallel loop directive. + */ + CXCursor_OMPParallelGenericLoopDirective = 298, + + /** OpenMP target parallel loop directive. + */ + CXCursor_OMPTargetParallelGenericLoopDirective = 299, + + /** OpenMP parallel masked directive. + */ + CXCursor_OMPParallelMaskedDirective = 300, + + /** OpenMP masked taskloop directive. + */ + CXCursor_OMPMaskedTaskLoopDirective = 301, + + /** OpenMP masked taskloop simd directive. + */ + CXCursor_OMPMaskedTaskLoopSimdDirective = 302, + + /** OpenMP parallel masked taskloop directive. + */ + CXCursor_OMPParallelMaskedTaskLoopDirective = 303, + + /** OpenMP parallel masked taskloop simd directive. + */ + CXCursor_OMPParallelMaskedTaskLoopSimdDirective = 304, + + /** OpenMP error directive. + */ + CXCursor_OMPErrorDirective = 305, + + /** OpenMP scope directive. + */ + CXCursor_OMPScopeDirective = 306, + + CXCursor_LastStmt = CXCursor_OMPScopeDirective, + + /** + * Cursor that represents the translation unit itself. + * + * The translation unit cursor exists primarily to act as the root + * cursor for traversing the contents of a translation unit. + */ + CXCursor_TranslationUnit = 350, + + /* Attributes */ + CXCursor_FirstAttr = 400, + /** + * An attribute whose specific kind is not exposed via this + * interface. + */ + CXCursor_UnexposedAttr = 400, + + CXCursor_IBActionAttr = 401, + CXCursor_IBOutletAttr = 402, + CXCursor_IBOutletCollectionAttr = 403, + CXCursor_CXXFinalAttr = 404, + CXCursor_CXXOverrideAttr = 405, + CXCursor_AnnotateAttr = 406, + CXCursor_AsmLabelAttr = 407, + CXCursor_PackedAttr = 408, + CXCursor_PureAttr = 409, + CXCursor_ConstAttr = 410, + CXCursor_NoDuplicateAttr = 411, + CXCursor_CUDAConstantAttr = 412, + CXCursor_CUDADeviceAttr = 413, + CXCursor_CUDAGlobalAttr = 414, + CXCursor_CUDAHostAttr = 415, + CXCursor_CUDASharedAttr = 416, + CXCursor_VisibilityAttr = 417, + CXCursor_DLLExport = 418, + CXCursor_DLLImport = 419, + CXCursor_NSReturnsRetained = 420, + CXCursor_NSReturnsNotRetained = 421, + CXCursor_NSReturnsAutoreleased = 422, + CXCursor_NSConsumesSelf = 423, + CXCursor_NSConsumed = 424, + CXCursor_ObjCException = 425, + CXCursor_ObjCNSObject = 426, + CXCursor_ObjCIndependentClass = 427, + CXCursor_ObjCPreciseLifetime = 428, + CXCursor_ObjCReturnsInnerPointer = 429, + CXCursor_ObjCRequiresSuper = 430, + CXCursor_ObjCRootClass = 431, + CXCursor_ObjCSubclassingRestricted = 432, + CXCursor_ObjCExplicitProtocolImpl = 433, + CXCursor_ObjCDesignatedInitializer = 434, + CXCursor_ObjCRuntimeVisible = 435, + CXCursor_ObjCBoxable = 436, + CXCursor_FlagEnum = 437, + CXCursor_ConvergentAttr = 438, + CXCursor_WarnUnusedAttr = 439, + CXCursor_WarnUnusedResultAttr = 440, + CXCursor_AlignedAttr = 441, + CXCursor_LastAttr = CXCursor_AlignedAttr, + + /* Preprocessing */ + CXCursor_PreprocessingDirective = 500, + CXCursor_MacroDefinition = 501, + CXCursor_MacroExpansion = 502, + CXCursor_MacroInstantiation = CXCursor_MacroExpansion, + CXCursor_InclusionDirective = 503, + CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective, + CXCursor_LastPreprocessing = CXCursor_InclusionDirective, + + /* Extra Declarations */ + /** + * A module import declaration. + */ + CXCursor_ModuleImportDecl = 600, + CXCursor_TypeAliasTemplateDecl = 601, + /** + * A static_assert or _Static_assert node + */ + CXCursor_StaticAssert = 602, + /** + * a friend declaration. + */ + CXCursor_FriendDecl = 603, + /** + * a concept declaration. + */ + CXCursor_ConceptDecl = 604, + + CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl, + CXCursor_LastExtraDecl = CXCursor_ConceptDecl, + + /** + * A code completion overload candidate. + */ + CXCursor_OverloadCandidate = 700 +}; + +/** + * A cursor representing some element in the abstract syntax tree for + * a translation unit. + * + * The cursor abstraction unifies the different kinds of entities in a + * program--declaration, statements, expressions, references to declarations, + * etc.--under a single "cursor" abstraction with a common set of operations. + * Common operation for a cursor include: getting the physical location in + * a source file where the cursor points, getting the name associated with a + * cursor, and retrieving cursors for any child nodes of a particular cursor. + * + * Cursors can be produced in two specific ways. + * clang_getTranslationUnitCursor() produces a cursor for a translation unit, + * from which one can use clang_visitChildren() to explore the rest of the + * translation unit. clang_getCursor() maps from a physical source location + * to the entity that resides at that location, allowing one to map from the + * source code into the AST. + */ +typedef struct { + enum CXCursorKind kind; + int xdata; + const void *data[3]; +} CXCursor; + +/** + * \defgroup CINDEX_CURSOR_MANIP Cursor manipulations + * + * @{ + */ + +/** + * Retrieve the NULL cursor, which represents no entity. + */ +CINDEX_LINKAGE CXCursor clang_getNullCursor(void); + +/** + * Retrieve the cursor that represents the given translation unit. + * + * The translation unit cursor can be used to start traversing the + * various declarations within the given translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit); + +/** + * Determine whether two cursors are equivalent. + */ +CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor); + +/** + * Returns non-zero if \p cursor is null. + */ +CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor cursor); + +/** + * Compute a hash value for the given cursor. + */ +CINDEX_LINKAGE unsigned clang_hashCursor(CXCursor); + +/** + * Retrieve the kind of the given cursor. + */ +CINDEX_LINKAGE enum CXCursorKind clang_getCursorKind(CXCursor); + +/** + * Determine whether the given cursor kind represents a declaration. + */ +CINDEX_LINKAGE unsigned clang_isDeclaration(enum CXCursorKind); + +/** + * Determine whether the given declaration is invalid. + * + * A declaration is invalid if it could not be parsed successfully. + * + * \returns non-zero if the cursor represents a declaration and it is + * invalid, otherwise NULL. + */ +CINDEX_LINKAGE unsigned clang_isInvalidDeclaration(CXCursor); + +/** + * Determine whether the given cursor kind represents a simple + * reference. + * + * Note that other kinds of cursors (such as expressions) can also refer to + * other cursors. Use clang_getCursorReferenced() to determine whether a + * particular cursor refers to another entity. + */ +CINDEX_LINKAGE unsigned clang_isReference(enum CXCursorKind); + +/** + * Determine whether the given cursor kind represents an expression. + */ +CINDEX_LINKAGE unsigned clang_isExpression(enum CXCursorKind); + +/** + * Determine whether the given cursor kind represents a statement. + */ +CINDEX_LINKAGE unsigned clang_isStatement(enum CXCursorKind); + +/** + * Determine whether the given cursor kind represents an attribute. + */ +CINDEX_LINKAGE unsigned clang_isAttribute(enum CXCursorKind); + +/** + * Determine whether the given cursor has any attributes. + */ +CINDEX_LINKAGE unsigned clang_Cursor_hasAttrs(CXCursor C); + +/** + * Determine whether the given cursor kind represents an invalid + * cursor. + */ +CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind); + +/** + * Determine whether the given cursor kind represents a translation + * unit. + */ +CINDEX_LINKAGE unsigned clang_isTranslationUnit(enum CXCursorKind); + +/*** + * Determine whether the given cursor represents a preprocessing + * element, such as a preprocessor directive or macro instantiation. + */ +CINDEX_LINKAGE unsigned clang_isPreprocessing(enum CXCursorKind); + +/*** + * Determine whether the given cursor represents a currently + * unexposed piece of the AST (e.g., CXCursor_UnexposedStmt). + */ +CINDEX_LINKAGE unsigned clang_isUnexposed(enum CXCursorKind); + +/** + * Describe the linkage of the entity referred to by a cursor. + */ +enum CXLinkageKind { + /** This value indicates that no linkage information is available + * for a provided CXCursor. */ + CXLinkage_Invalid, + /** + * This is the linkage for variables, parameters, and so on that + * have automatic storage. This covers normal (non-extern) local variables. + */ + CXLinkage_NoLinkage, + /** This is the linkage for static variables and static functions. */ + CXLinkage_Internal, + /** This is the linkage for entities with external linkage that live + * in C++ anonymous namespaces.*/ + CXLinkage_UniqueExternal, + /** This is the linkage for entities with true, external linkage. */ + CXLinkage_External +}; + +/** + * Determine the linkage of the entity referred to by a given cursor. + */ +CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor); + +enum CXVisibilityKind { + /** This value indicates that no visibility information is available + * for a provided CXCursor. */ + CXVisibility_Invalid, + + /** Symbol not seen by the linker. */ + CXVisibility_Hidden, + /** Symbol seen by the linker but resolves to a symbol inside this object. */ + CXVisibility_Protected, + /** Symbol seen by the linker and acts like a normal symbol. */ + CXVisibility_Default +}; + +/** + * Describe the visibility of the entity referred to by a cursor. + * + * This returns the default visibility if not explicitly specified by + * a visibility attribute. The default visibility may be changed by + * commandline arguments. + * + * \param cursor The cursor to query. + * + * \returns The visibility of the cursor. + */ +CINDEX_LINKAGE enum CXVisibilityKind clang_getCursorVisibility(CXCursor cursor); + +/** + * Determine the availability of the entity that this cursor refers to, + * taking the current target platform into account. + * + * \param cursor The cursor to query. + * + * \returns The availability of the cursor. + */ +CINDEX_LINKAGE enum CXAvailabilityKind +clang_getCursorAvailability(CXCursor cursor); + +/** + * Describes the availability of a given entity on a particular platform, e.g., + * a particular class might only be available on Mac OS 10.7 or newer. + */ +typedef struct CXPlatformAvailability { + /** + * A string that describes the platform for which this structure + * provides availability information. + * + * Possible values are "ios" or "macos". + */ + CXString Platform; + /** + * The version number in which this entity was introduced. + */ + CXVersion Introduced; + /** + * The version number in which this entity was deprecated (but is + * still available). + */ + CXVersion Deprecated; + /** + * The version number in which this entity was obsoleted, and therefore + * is no longer available. + */ + CXVersion Obsoleted; + /** + * Whether the entity is unconditionally unavailable on this platform. + */ + int Unavailable; + /** + * An optional message to provide to a user of this API, e.g., to + * suggest replacement APIs. + */ + CXString Message; +} CXPlatformAvailability; + +/** + * Determine the availability of the entity that this cursor refers to + * on any platforms for which availability information is known. + * + * \param cursor The cursor to query. + * + * \param always_deprecated If non-NULL, will be set to indicate whether the + * entity is deprecated on all platforms. + * + * \param deprecated_message If non-NULL, will be set to the message text + * provided along with the unconditional deprecation of this entity. The client + * is responsible for deallocating this string. + * + * \param always_unavailable If non-NULL, will be set to indicate whether the + * entity is unavailable on all platforms. + * + * \param unavailable_message If non-NULL, will be set to the message text + * provided along with the unconditional unavailability of this entity. The + * client is responsible for deallocating this string. + * + * \param availability If non-NULL, an array of CXPlatformAvailability instances + * that will be populated with platform availability information, up to either + * the number of platforms for which availability information is available (as + * returned by this function) or \c availability_size, whichever is smaller. + * + * \param availability_size The number of elements available in the + * \c availability array. + * + * \returns The number of platforms (N) for which availability information is + * available (which is unrelated to \c availability_size). + * + * Note that the client is responsible for calling + * \c clang_disposeCXPlatformAvailability to free each of the + * platform-availability structures returned. There are + * \c min(N, availability_size) such structures. + */ +CINDEX_LINKAGE int clang_getCursorPlatformAvailability( + CXCursor cursor, int *always_deprecated, CXString *deprecated_message, + int *always_unavailable, CXString *unavailable_message, + CXPlatformAvailability *availability, int availability_size); + +/** + * Free the memory associated with a \c CXPlatformAvailability structure. + */ +CINDEX_LINKAGE void +clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability); + +/** + * If cursor refers to a variable declaration and it has initializer returns + * cursor referring to the initializer otherwise return null cursor. + */ +CINDEX_LINKAGE CXCursor clang_Cursor_getVarDeclInitializer(CXCursor cursor); + +/** + * If cursor refers to a variable declaration that has global storage returns 1. + * If cursor refers to a variable declaration that doesn't have global storage + * returns 0. Otherwise returns -1. + */ +CINDEX_LINKAGE int clang_Cursor_hasVarDeclGlobalStorage(CXCursor cursor); + +/** + * If cursor refers to a variable declaration that has external storage + * returns 1. If cursor refers to a variable declaration that doesn't have + * external storage returns 0. Otherwise returns -1. + */ +CINDEX_LINKAGE int clang_Cursor_hasVarDeclExternalStorage(CXCursor cursor); + +/** + * Describe the "language" of the entity referred to by a cursor. + */ +enum CXLanguageKind { + CXLanguage_Invalid = 0, + CXLanguage_C, + CXLanguage_ObjC, + CXLanguage_CPlusPlus +}; + +/** + * Determine the "language" of the entity referred to by a given cursor. + */ +CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor); + +/** + * Describe the "thread-local storage (TLS) kind" of the declaration + * referred to by a cursor. + */ +enum CXTLSKind { CXTLS_None = 0, CXTLS_Dynamic, CXTLS_Static }; + +/** + * Determine the "thread-local storage (TLS) kind" of the declaration + * referred to by a cursor. + */ +CINDEX_LINKAGE enum CXTLSKind clang_getCursorTLSKind(CXCursor cursor); + +/** + * Returns the translation unit that a cursor originated from. + */ +CINDEX_LINKAGE CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor); + +/** + * A fast container representing a set of CXCursors. + */ +typedef struct CXCursorSetImpl *CXCursorSet; + +/** + * Creates an empty CXCursorSet. + */ +CINDEX_LINKAGE CXCursorSet clang_createCXCursorSet(void); + +/** + * Disposes a CXCursorSet and releases its associated memory. + */ +CINDEX_LINKAGE void clang_disposeCXCursorSet(CXCursorSet cset); + +/** + * Queries a CXCursorSet to see if it contains a specific CXCursor. + * + * \returns non-zero if the set contains the specified cursor. + */ +CINDEX_LINKAGE unsigned clang_CXCursorSet_contains(CXCursorSet cset, + CXCursor cursor); + +/** + * Inserts a CXCursor into a CXCursorSet. + * + * \returns zero if the CXCursor was already in the set, and non-zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_CXCursorSet_insert(CXCursorSet cset, + CXCursor cursor); + +/** + * Determine the semantic parent of the given cursor. + * + * The semantic parent of a cursor is the cursor that semantically contains + * the given \p cursor. For many declarations, the lexical and semantic parents + * are equivalent (the lexical parent is returned by + * \c clang_getCursorLexicalParent()). They diverge when declarations or + * definitions are provided out-of-line. For example: + * + * \code + * class C { + * void f(); + * }; + * + * void C::f() { } + * \endcode + * + * In the out-of-line definition of \c C::f, the semantic parent is + * the class \c C, of which this function is a member. The lexical parent is + * the place where the declaration actually occurs in the source code; in this + * case, the definition occurs in the translation unit. In general, the + * lexical parent for a given entity can change without affecting the semantics + * of the program, and the lexical parent of different declarations of the + * same entity may be different. Changing the semantic parent of a declaration, + * on the other hand, can have a major impact on semantics, and redeclarations + * of a particular entity should all have the same semantic context. + * + * In the example above, both declarations of \c C::f have \c C as their + * semantic context, while the lexical context of the first \c C::f is \c C + * and the lexical context of the second \c C::f is the translation unit. + * + * For global declarations, the semantic parent is the translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getCursorSemanticParent(CXCursor cursor); + +/** + * Determine the lexical parent of the given cursor. + * + * The lexical parent of a cursor is the cursor in which the given \p cursor + * was actually written. For many declarations, the lexical and semantic parents + * are equivalent (the semantic parent is returned by + * \c clang_getCursorSemanticParent()). They diverge when declarations or + * definitions are provided out-of-line. For example: + * + * \code + * class C { + * void f(); + * }; + * + * void C::f() { } + * \endcode + * + * In the out-of-line definition of \c C::f, the semantic parent is + * the class \c C, of which this function is a member. The lexical parent is + * the place where the declaration actually occurs in the source code; in this + * case, the definition occurs in the translation unit. In general, the + * lexical parent for a given entity can change without affecting the semantics + * of the program, and the lexical parent of different declarations of the + * same entity may be different. Changing the semantic parent of a declaration, + * on the other hand, can have a major impact on semantics, and redeclarations + * of a particular entity should all have the same semantic context. + * + * In the example above, both declarations of \c C::f have \c C as their + * semantic context, while the lexical context of the first \c C::f is \c C + * and the lexical context of the second \c C::f is the translation unit. + * + * For declarations written in the global scope, the lexical parent is + * the translation unit. + */ +CINDEX_LINKAGE CXCursor clang_getCursorLexicalParent(CXCursor cursor); + +/** + * Determine the set of methods that are overridden by the given + * method. + * + * In both Objective-C and C++, a method (aka virtual member function, + * in C++) can override a virtual method in a base class. For + * Objective-C, a method is said to override any method in the class's + * base class, its protocols, or its categories' protocols, that has the same + * selector and is of the same kind (class or instance). + * If no such method exists, the search continues to the class's superclass, + * its protocols, and its categories, and so on. A method from an Objective-C + * implementation is considered to override the same methods as its + * corresponding method in the interface. + * + * For C++, a virtual member function overrides any virtual member + * function with the same signature that occurs in its base + * classes. With multiple inheritance, a virtual member function can + * override several virtual member functions coming from different + * base classes. + * + * In all cases, this function determines the immediate overridden + * method, rather than all of the overridden methods. For example, if + * a method is originally declared in a class A, then overridden in B + * (which in inherits from A) and also in C (which inherited from B), + * then the only overridden method returned from this function when + * invoked on C's method will be B's method. The client may then + * invoke this function again, given the previously-found overridden + * methods, to map out the complete method-override set. + * + * \param cursor A cursor representing an Objective-C or C++ + * method. This routine will compute the set of methods that this + * method overrides. + * + * \param overridden A pointer whose pointee will be replaced with a + * pointer to an array of cursors, representing the set of overridden + * methods. If there are no overridden methods, the pointee will be + * set to NULL. The pointee must be freed via a call to + * \c clang_disposeOverriddenCursors(). + * + * \param num_overridden A pointer to the number of overridden + * functions, will be set to the number of overridden functions in the + * array pointed to by \p overridden. + */ +CINDEX_LINKAGE void clang_getOverriddenCursors(CXCursor cursor, + CXCursor **overridden, + unsigned *num_overridden); + +/** + * Free the set of overridden cursors returned by \c + * clang_getOverriddenCursors(). + */ +CINDEX_LINKAGE void clang_disposeOverriddenCursors(CXCursor *overridden); + +/** + * Retrieve the file that is included by the given inclusion directive + * cursor. + */ +CINDEX_LINKAGE CXFile clang_getIncludedFile(CXCursor cursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_SOURCE Mapping between cursors and source code + * + * Cursors represent a location within the Abstract Syntax Tree (AST). These + * routines help map between cursors and the physical locations where the + * described entities occur in the source code. The mapping is provided in + * both directions, so one can map from source code to the AST and back. + * + * @{ + */ + +/** + * Map a source location to the cursor that describes the entity at that + * location in the source code. + * + * clang_getCursor() maps an arbitrary source location within a translation + * unit down to the most specific cursor that describes the entity at that + * location. For example, given an expression \c x + y, invoking + * clang_getCursor() with a source location pointing to "x" will return the + * cursor for "x"; similarly for "y". If the cursor points anywhere between + * "x" or "y" (e.g., on the + or the whitespace around it), clang_getCursor() + * will return a cursor referring to the "+" expression. + * + * \returns a cursor representing the entity at the given source location, or + * a NULL cursor if no such entity can be found. + */ +CINDEX_LINKAGE CXCursor clang_getCursor(CXTranslationUnit, CXSourceLocation); + +/** + * Retrieve the physical location of the source constructor referenced + * by the given cursor. + * + * The location of a declaration is typically the location of the name of that + * declaration, where the name of that declaration would occur if it is + * unnamed, or some keyword that introduces that particular declaration. + * The location of a reference is where that reference occurs within the + * source code. + */ +CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor); + +/** + * Retrieve the physical extent of the source construct referenced by + * the given cursor. + * + * The extent of a cursor starts with the file/line/column pointing at the + * first character within the source construct that the cursor refers to and + * ends with the last character within that source construct. For a + * declaration, the extent covers the declaration itself. For a reference, + * the extent covers the location of the reference (e.g., where the referenced + * entity was actually used). + */ +CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_TYPES Type information for CXCursors + * + * @{ + */ + +/** + * Describes the kind of type + */ +enum CXTypeKind { + /** + * Represents an invalid type (e.g., where no type is available). + */ + CXType_Invalid = 0, + + /** + * A type whose specific kind is not exposed via this + * interface. + */ + CXType_Unexposed = 1, + + /* Builtin types */ + CXType_Void = 2, + CXType_Bool = 3, + CXType_Char_U = 4, + CXType_UChar = 5, + CXType_Char16 = 6, + CXType_Char32 = 7, + CXType_UShort = 8, + CXType_UInt = 9, + CXType_ULong = 10, + CXType_ULongLong = 11, + CXType_UInt128 = 12, + CXType_Char_S = 13, + CXType_SChar = 14, + CXType_WChar = 15, + CXType_Short = 16, + CXType_Int = 17, + CXType_Long = 18, + CXType_LongLong = 19, + CXType_Int128 = 20, + CXType_Float = 21, + CXType_Double = 22, + CXType_LongDouble = 23, + CXType_NullPtr = 24, + CXType_Overload = 25, + CXType_Dependent = 26, + CXType_ObjCId = 27, + CXType_ObjCClass = 28, + CXType_ObjCSel = 29, + CXType_Float128 = 30, + CXType_Half = 31, + CXType_Float16 = 32, + CXType_ShortAccum = 33, + CXType_Accum = 34, + CXType_LongAccum = 35, + CXType_UShortAccum = 36, + CXType_UAccum = 37, + CXType_ULongAccum = 38, + CXType_BFloat16 = 39, + CXType_Ibm128 = 40, + CXType_FirstBuiltin = CXType_Void, + CXType_LastBuiltin = CXType_Ibm128, + + CXType_Complex = 100, + CXType_Pointer = 101, + CXType_BlockPointer = 102, + CXType_LValueReference = 103, + CXType_RValueReference = 104, + CXType_Record = 105, + CXType_Enum = 106, + CXType_Typedef = 107, + CXType_ObjCInterface = 108, + CXType_ObjCObjectPointer = 109, + CXType_FunctionNoProto = 110, + CXType_FunctionProto = 111, + CXType_ConstantArray = 112, + CXType_Vector = 113, + CXType_IncompleteArray = 114, + CXType_VariableArray = 115, + CXType_DependentSizedArray = 116, + CXType_MemberPointer = 117, + CXType_Auto = 118, + + /** + * Represents a type that was referred to using an elaborated type keyword. + * + * E.g., struct S, or via a qualified name, e.g., N::M::type, or both. + */ + CXType_Elaborated = 119, + + /* OpenCL PipeType. */ + CXType_Pipe = 120, + + /* OpenCL builtin types. */ + CXType_OCLImage1dRO = 121, + CXType_OCLImage1dArrayRO = 122, + CXType_OCLImage1dBufferRO = 123, + CXType_OCLImage2dRO = 124, + CXType_OCLImage2dArrayRO = 125, + CXType_OCLImage2dDepthRO = 126, + CXType_OCLImage2dArrayDepthRO = 127, + CXType_OCLImage2dMSAARO = 128, + CXType_OCLImage2dArrayMSAARO = 129, + CXType_OCLImage2dMSAADepthRO = 130, + CXType_OCLImage2dArrayMSAADepthRO = 131, + CXType_OCLImage3dRO = 132, + CXType_OCLImage1dWO = 133, + CXType_OCLImage1dArrayWO = 134, + CXType_OCLImage1dBufferWO = 135, + CXType_OCLImage2dWO = 136, + CXType_OCLImage2dArrayWO = 137, + CXType_OCLImage2dDepthWO = 138, + CXType_OCLImage2dArrayDepthWO = 139, + CXType_OCLImage2dMSAAWO = 140, + CXType_OCLImage2dArrayMSAAWO = 141, + CXType_OCLImage2dMSAADepthWO = 142, + CXType_OCLImage2dArrayMSAADepthWO = 143, + CXType_OCLImage3dWO = 144, + CXType_OCLImage1dRW = 145, + CXType_OCLImage1dArrayRW = 146, + CXType_OCLImage1dBufferRW = 147, + CXType_OCLImage2dRW = 148, + CXType_OCLImage2dArrayRW = 149, + CXType_OCLImage2dDepthRW = 150, + CXType_OCLImage2dArrayDepthRW = 151, + CXType_OCLImage2dMSAARW = 152, + CXType_OCLImage2dArrayMSAARW = 153, + CXType_OCLImage2dMSAADepthRW = 154, + CXType_OCLImage2dArrayMSAADepthRW = 155, + CXType_OCLImage3dRW = 156, + CXType_OCLSampler = 157, + CXType_OCLEvent = 158, + CXType_OCLQueue = 159, + CXType_OCLReserveID = 160, + + CXType_ObjCObject = 161, + CXType_ObjCTypeParam = 162, + CXType_Attributed = 163, + + CXType_OCLIntelSubgroupAVCMcePayload = 164, + CXType_OCLIntelSubgroupAVCImePayload = 165, + CXType_OCLIntelSubgroupAVCRefPayload = 166, + CXType_OCLIntelSubgroupAVCSicPayload = 167, + CXType_OCLIntelSubgroupAVCMceResult = 168, + CXType_OCLIntelSubgroupAVCImeResult = 169, + CXType_OCLIntelSubgroupAVCRefResult = 170, + CXType_OCLIntelSubgroupAVCSicResult = 171, + CXType_OCLIntelSubgroupAVCImeResultSingleReferenceStreamout = 172, + CXType_OCLIntelSubgroupAVCImeResultDualReferenceStreamout = 173, + CXType_OCLIntelSubgroupAVCImeSingleReferenceStreamin = 174, + CXType_OCLIntelSubgroupAVCImeDualReferenceStreamin = 175, + + /* Old aliases for AVC OpenCL extension types. */ + CXType_OCLIntelSubgroupAVCImeResultSingleRefStreamout = 172, + CXType_OCLIntelSubgroupAVCImeResultDualRefStreamout = 173, + CXType_OCLIntelSubgroupAVCImeSingleRefStreamin = 174, + CXType_OCLIntelSubgroupAVCImeDualRefStreamin = 175, + + CXType_ExtVector = 176, + CXType_Atomic = 177, + CXType_BTFTagAttributed = 178 +}; + +/** + * Describes the calling convention of a function type + */ +enum CXCallingConv { + CXCallingConv_Default = 0, + CXCallingConv_C = 1, + CXCallingConv_X86StdCall = 2, + CXCallingConv_X86FastCall = 3, + CXCallingConv_X86ThisCall = 4, + CXCallingConv_X86Pascal = 5, + CXCallingConv_AAPCS = 6, + CXCallingConv_AAPCS_VFP = 7, + CXCallingConv_X86RegCall = 8, + CXCallingConv_IntelOclBicc = 9, + CXCallingConv_Win64 = 10, + /* Alias for compatibility with older versions of API. */ + CXCallingConv_X86_64Win64 = CXCallingConv_Win64, + CXCallingConv_X86_64SysV = 11, + CXCallingConv_X86VectorCall = 12, + CXCallingConv_Swift = 13, + CXCallingConv_PreserveMost = 14, + CXCallingConv_PreserveAll = 15, + CXCallingConv_AArch64VectorCall = 16, + CXCallingConv_SwiftAsync = 17, + CXCallingConv_AArch64SVEPCS = 18, + CXCallingConv_M68kRTD = 19, + + CXCallingConv_Invalid = 100, + CXCallingConv_Unexposed = 200 +}; + +/** + * The type of an element in the abstract syntax tree. + * + */ +typedef struct { + enum CXTypeKind kind; + void *data[2]; +} CXType; + +/** + * Retrieve the type of a CXCursor (if any). + */ +CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); + +/** + * Pretty-print the underlying type using the rules of the + * language of the translation unit from which it came. + * + * If the type is invalid, an empty string is returned. + */ +CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT); + +/** + * Retrieve the underlying type of a typedef declaration. + * + * If the cursor does not reference a typedef declaration, an invalid type is + * returned. + */ +CINDEX_LINKAGE CXType clang_getTypedefDeclUnderlyingType(CXCursor C); + +/** + * Retrieve the integer type of an enum declaration. + * + * If the cursor does not reference an enum declaration, an invalid type is + * returned. + */ +CINDEX_LINKAGE CXType clang_getEnumDeclIntegerType(CXCursor C); + +/** + * Retrieve the integer value of an enum constant declaration as a signed + * long long. + * + * If the cursor does not reference an enum constant declaration, LLONG_MIN is + * returned. Since this is also potentially a valid constant value, the kind of + * the cursor must be verified before calling this function. + */ +CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C); + +/** + * Retrieve the integer value of an enum constant declaration as an unsigned + * long long. + * + * If the cursor does not reference an enum constant declaration, ULLONG_MAX is + * returned. Since this is also potentially a valid constant value, the kind of + * the cursor must be verified before calling this function. + */ +CINDEX_LINKAGE unsigned long long +clang_getEnumConstantDeclUnsignedValue(CXCursor C); + +/** + * Returns non-zero if the cursor specifies a Record member that is a bit-field. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isBitField(CXCursor C); + +/** + * Retrieve the bit width of a bit-field declaration as an integer. + * + * If the cursor does not reference a bit-field, or if the bit-field's width + * expression cannot be evaluated, -1 is returned. + * + * For example: + * \code + * if (clang_Cursor_isBitField(Cursor)) { + * int Width = clang_getFieldDeclBitWidth(Cursor); + * if (Width != -1) { + * // The bit-field width is not value-dependent. + * } + * } + * \endcode + */ +CINDEX_LINKAGE int clang_getFieldDeclBitWidth(CXCursor C); + +/** + * Retrieve the number of non-variadic arguments associated with a given + * cursor. + * + * The number of arguments can be determined for calls as well as for + * declarations of functions or methods. For other cursors -1 is returned. + */ +CINDEX_LINKAGE int clang_Cursor_getNumArguments(CXCursor C); + +/** + * Retrieve the argument cursor of a function or method. + * + * The argument cursor can be determined for calls as well as for declarations + * of functions or methods. For other cursors and for invalid indices, an + * invalid cursor is returned. + */ +CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i); + +/** + * Describes the kind of a template argument. + * + * See the definition of llvm::clang::TemplateArgument::ArgKind for full + * element descriptions. + */ +enum CXTemplateArgumentKind { + CXTemplateArgumentKind_Null, + CXTemplateArgumentKind_Type, + CXTemplateArgumentKind_Declaration, + CXTemplateArgumentKind_NullPtr, + CXTemplateArgumentKind_Integral, + CXTemplateArgumentKind_Template, + CXTemplateArgumentKind_TemplateExpansion, + CXTemplateArgumentKind_Expression, + CXTemplateArgumentKind_Pack, + /* Indicates an error case, preventing the kind from being deduced. */ + CXTemplateArgumentKind_Invalid +}; + +/** + * Returns the number of template args of a function, struct, or class decl + * representing a template specialization. + * + * If the argument cursor cannot be converted into a template function + * declaration, -1 is returned. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * The value 3 would be returned from this call. + */ +CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C); + +/** + * Retrieve the kind of the I'th template argument of the CXCursor C. + * + * If the argument CXCursor does not represent a FunctionDecl, StructDecl, or + * ClassTemplatePartialSpecialization, an invalid template argument kind is + * returned. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * For I = 0, 1, and 2, Type, Integral, and Integral will be returned, + * respectively. + */ +CINDEX_LINKAGE enum CXTemplateArgumentKind +clang_Cursor_getTemplateArgumentKind(CXCursor C, unsigned I); + +/** + * Retrieve a CXType representing the type of a TemplateArgument of a + * function decl representing a template specialization. + * + * If the argument CXCursor does not represent a FunctionDecl, StructDecl, + * ClassDecl or ClassTemplatePartialSpecialization whose I'th template argument + * has a kind of CXTemplateArgKind_Integral, an invalid type is returned. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * If called with I = 0, "float", will be returned. + * Invalid types will be returned for I == 1 or 2. + */ +CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C, + unsigned I); + +/** + * Retrieve the value of an Integral TemplateArgument (of a function + * decl representing a template specialization) as a signed long long. + * + * It is undefined to call this function on a CXCursor that does not represent a + * FunctionDecl, StructDecl, ClassDecl or ClassTemplatePartialSpecialization + * whose I'th template argument is not an integral value. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * If called with I = 1 or 2, -7 or true will be returned, respectively. + * For I == 0, this function's behavior is undefined. + */ +CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C, + unsigned I); + +/** + * Retrieve the value of an Integral TemplateArgument (of a function + * decl representing a template specialization) as an unsigned long long. + * + * It is undefined to call this function on a CXCursor that does not represent a + * FunctionDecl, StructDecl, ClassDecl or ClassTemplatePartialSpecialization or + * whose I'th template argument is not an integral value. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * If called with I = 1 or 2, 2147483649 or true will be returned, respectively. + * For I == 0, this function's behavior is undefined. + */ +CINDEX_LINKAGE unsigned long long +clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, unsigned I); + +/** + * Determine whether two CXTypes represent the same type. + * + * \returns non-zero if the CXTypes represent the same type and + * zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_equalTypes(CXType A, CXType B); + +/** + * Return the canonical type for a CXType. + * + * Clang's type system explicitly models typedefs and all the ways + * a specific type can be represented. The canonical type is the underlying + * type with all the "sugar" removed. For example, if 'T' is a typedef + * for 'int', the canonical type for 'T' would be 'int'. + */ +CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T); + +/** + * Determine whether a CXType has the "const" qualifier set, + * without looking through typedefs that may have added "const" at a + * different level. + */ +CINDEX_LINKAGE unsigned clang_isConstQualifiedType(CXType T); + +/** + * Determine whether a CXCursor that is a macro, is + * function like. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isMacroFunctionLike(CXCursor C); + +/** + * Determine whether a CXCursor that is a macro, is a + * builtin one. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isMacroBuiltin(CXCursor C); + +/** + * Determine whether a CXCursor that is a function declaration, is an + * inline declaration. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isFunctionInlined(CXCursor C); + +/** + * Determine whether a CXType has the "volatile" qualifier set, + * without looking through typedefs that may have added "volatile" at + * a different level. + */ +CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T); + +/** + * Determine whether a CXType has the "restrict" qualifier set, + * without looking through typedefs that may have added "restrict" at a + * different level. + */ +CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T); + +/** + * Returns the address space of the given type. + */ +CINDEX_LINKAGE unsigned clang_getAddressSpace(CXType T); + +/** + * Returns the typedef name of the given type. + */ +CINDEX_LINKAGE CXString clang_getTypedefName(CXType CT); + +/** + * For pointer types, returns the type of the pointee. + */ +CINDEX_LINKAGE CXType clang_getPointeeType(CXType T); + +/** + * Retrieve the unqualified variant of the given type, removing as + * little sugar as possible. + * + * For example, given the following series of typedefs: + * + * \code + * typedef int Integer; + * typedef const Integer CInteger; + * typedef CInteger DifferenceType; + * \endcode + * + * Executing \c clang_getUnqualifiedType() on a \c CXType that + * represents \c DifferenceType, will desugar to a type representing + * \c Integer, that has no qualifiers. + * + * And, executing \c clang_getUnqualifiedType() on the type of the + * first argument of the following function declaration: + * + * \code + * void foo(const int); + * \endcode + * + * Will return a type representing \c int, removing the \c const + * qualifier. + * + * Sugar over array types is not desugared. + * + * A type can be checked for qualifiers with \c + * clang_isConstQualifiedType(), \c clang_isVolatileQualifiedType() + * and \c clang_isRestrictQualifiedType(). + * + * A type that resulted from a call to \c clang_getUnqualifiedType + * will return \c false for all of the above calls. + */ +CINDEX_LINKAGE CXType clang_getUnqualifiedType(CXType CT); + +/** + * For reference types (e.g., "const int&"), returns the type that the + * reference refers to (e.g "const int"). + * + * Otherwise, returns the type itself. + * + * A type that has kind \c CXType_LValueReference or + * \c CXType_RValueReference is a reference type. + */ +CINDEX_LINKAGE CXType clang_getNonReferenceType(CXType CT); + +/** + * Return the cursor for the declaration of the given type. + */ +CINDEX_LINKAGE CXCursor clang_getTypeDeclaration(CXType T); + +/** + * Returns the Objective-C type encoding for the specified declaration. + */ +CINDEX_LINKAGE CXString clang_getDeclObjCTypeEncoding(CXCursor C); + +/** + * Returns the Objective-C type encoding for the specified CXType. + */ +CINDEX_LINKAGE CXString clang_Type_getObjCEncoding(CXType type); + +/** + * Retrieve the spelling of a given CXTypeKind. + */ +CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K); + +/** + * Retrieve the calling convention associated with a function type. + * + * If a non-function type is passed in, CXCallingConv_Invalid is returned. + */ +CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T); + +/** + * Retrieve the return type associated with a function type. + * + * If a non-function type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getResultType(CXType T); + +/** + * Retrieve the exception specification type associated with a function type. + * This is a value of type CXCursor_ExceptionSpecificationKind. + * + * If a non-function type is passed in, an error code of -1 is returned. + */ +CINDEX_LINKAGE int clang_getExceptionSpecificationType(CXType T); + +/** + * Retrieve the number of non-variadic parameters associated with a + * function type. + * + * If a non-function type is passed in, -1 is returned. + */ +CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); + +/** + * Retrieve the type of a parameter of a function type. + * + * If a non-function type is passed in or the function does not have enough + * parameters, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getArgType(CXType T, unsigned i); + +/** + * Retrieves the base type of the ObjCObjectType. + * + * If the type is not an ObjC object, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getObjCObjectBaseType(CXType T); + +/** + * Retrieve the number of protocol references associated with an ObjC object/id. + * + * If the type is not an ObjC object, 0 is returned. + */ +CINDEX_LINKAGE unsigned clang_Type_getNumObjCProtocolRefs(CXType T); + +/** + * Retrieve the decl for a protocol reference for an ObjC object/id. + * + * If the type is not an ObjC object or there are not enough protocol + * references, an invalid cursor is returned. + */ +CINDEX_LINKAGE CXCursor clang_Type_getObjCProtocolDecl(CXType T, unsigned i); + +/** + * Retrieve the number of type arguments associated with an ObjC object. + * + * If the type is not an ObjC object, 0 is returned. + */ +CINDEX_LINKAGE unsigned clang_Type_getNumObjCTypeArgs(CXType T); + +/** + * Retrieve a type argument associated with an ObjC object. + * + * If the type is not an ObjC or the index is not valid, + * an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getObjCTypeArg(CXType T, unsigned i); + +/** + * Return 1 if the CXType is a variadic function type, and 0 otherwise. + */ +CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T); + +/** + * Retrieve the return type associated with a given cursor. + * + * This only returns a valid type if the cursor refers to a function or method. + */ +CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C); + +/** + * Retrieve the exception specification type associated with a given cursor. + * This is a value of type CXCursor_ExceptionSpecificationKind. + * + * This only returns a valid result if the cursor refers to a function or + * method. + */ +CINDEX_LINKAGE int clang_getCursorExceptionSpecificationType(CXCursor C); + +/** + * Return 1 if the CXType is a POD (plain old data) type, and 0 + * otherwise. + */ +CINDEX_LINKAGE unsigned clang_isPODType(CXType T); + +/** + * Return the element type of an array, complex, or vector type. + * + * If a type is passed in that is not an array, complex, or vector type, + * an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getElementType(CXType T); + +/** + * Return the number of elements of an array or vector type. + * + * If a type is passed in that is not an array or vector type, + * -1 is returned. + */ +CINDEX_LINKAGE long long clang_getNumElements(CXType T); + +/** + * Return the element type of an array type. + * + * If a non-array type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_getArrayElementType(CXType T); + +/** + * Return the array size of a constant array. + * + * If a non-array type is passed in, -1 is returned. + */ +CINDEX_LINKAGE long long clang_getArraySize(CXType T); + +/** + * Retrieve the type named by the qualified-id. + * + * If a non-elaborated type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getNamedType(CXType T); + +/** + * Determine if a typedef is 'transparent' tag. + * + * A typedef is considered 'transparent' if it shares a name and spelling + * location with its underlying tag type, as is the case with the NS_ENUM macro. + * + * \returns non-zero if transparent and zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_Type_isTransparentTagTypedef(CXType T); + +enum CXTypeNullabilityKind { + /** + * Values of this type can never be null. + */ + CXTypeNullability_NonNull = 0, + /** + * Values of this type can be null. + */ + CXTypeNullability_Nullable = 1, + /** + * Whether values of this type can be null is (explicitly) + * unspecified. This captures a (fairly rare) case where we + * can't conclude anything about the nullability of the type even + * though it has been considered. + */ + CXTypeNullability_Unspecified = 2, + /** + * Nullability is not applicable to this type. + */ + CXTypeNullability_Invalid = 3, + + /** + * Generally behaves like Nullable, except when used in a block parameter that + * was imported into a swift async method. There, swift will assume that the + * parameter can get null even if no error occurred. _Nullable parameters are + * assumed to only get null on error. + */ + CXTypeNullability_NullableResult = 4 +}; + +/** + * Retrieve the nullability kind of a pointer type. + */ +CINDEX_LINKAGE enum CXTypeNullabilityKind clang_Type_getNullability(CXType T); + +/** + * List the possible error codes for \c clang_Type_getSizeOf, + * \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and + * \c clang_Cursor_getOffsetOf. + * + * A value of this enumeration type can be returned if the target type is not + * a valid argument to sizeof, alignof or offsetof. + */ +enum CXTypeLayoutError { + /** + * Type is of kind CXType_Invalid. + */ + CXTypeLayoutError_Invalid = -1, + /** + * The type is an incomplete Type. + */ + CXTypeLayoutError_Incomplete = -2, + /** + * The type is a dependent Type. + */ + CXTypeLayoutError_Dependent = -3, + /** + * The type is not a constant size type. + */ + CXTypeLayoutError_NotConstantSize = -4, + /** + * The Field name is not valid for this record. + */ + CXTypeLayoutError_InvalidFieldName = -5, + /** + * The type is undeduced. + */ + CXTypeLayoutError_Undeduced = -6 +}; + +/** + * Return the alignment of a type in bytes as per C++[expr.alignof] + * standard. + * + * If the type declaration is invalid, CXTypeLayoutError_Invalid is returned. + * If the type declaration is an incomplete type, CXTypeLayoutError_Incomplete + * is returned. + * If the type declaration is a dependent type, CXTypeLayoutError_Dependent is + * returned. + * If the type declaration is not a constant size type, + * CXTypeLayoutError_NotConstantSize is returned. + */ +CINDEX_LINKAGE long long clang_Type_getAlignOf(CXType T); + +/** + * Return the class type of an member pointer type. + * + * If a non-member-pointer type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getClassType(CXType T); + +/** + * Return the size of a type in bytes as per C++[expr.sizeof] standard. + * + * If the type declaration is invalid, CXTypeLayoutError_Invalid is returned. + * If the type declaration is an incomplete type, CXTypeLayoutError_Incomplete + * is returned. + * If the type declaration is a dependent type, CXTypeLayoutError_Dependent is + * returned. + */ +CINDEX_LINKAGE long long clang_Type_getSizeOf(CXType T); + +/** + * Return the offset of a field named S in a record of type T in bits + * as it would be returned by __offsetof__ as per C++11[18.2p4] + * + * If the cursor is not a record field declaration, CXTypeLayoutError_Invalid + * is returned. + * If the field's type declaration is an incomplete type, + * CXTypeLayoutError_Incomplete is returned. + * If the field's type declaration is a dependent type, + * CXTypeLayoutError_Dependent is returned. + * If the field's name S is not found, + * CXTypeLayoutError_InvalidFieldName is returned. + */ +CINDEX_LINKAGE long long clang_Type_getOffsetOf(CXType T, const char *S); + +/** + * Return the type that was modified by this attributed type. + * + * If the type is not an attributed type, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getModifiedType(CXType T); + +/** + * Gets the type contained by this atomic type. + * + * If a non-atomic type is passed in, an invalid type is returned. + */ +CINDEX_LINKAGE CXType clang_Type_getValueType(CXType CT); + +/** + * Return the offset of the field represented by the Cursor. + * + * If the cursor is not a field declaration, -1 is returned. + * If the cursor semantic parent is not a record field declaration, + * CXTypeLayoutError_Invalid is returned. + * If the field's type declaration is an incomplete type, + * CXTypeLayoutError_Incomplete is returned. + * If the field's type declaration is a dependent type, + * CXTypeLayoutError_Dependent is returned. + * If the field's name S is not found, + * CXTypeLayoutError_InvalidFieldName is returned. + */ +CINDEX_LINKAGE long long clang_Cursor_getOffsetOfField(CXCursor C); + +/** + * Determine whether the given cursor represents an anonymous + * tag or namespace + */ +CINDEX_LINKAGE unsigned clang_Cursor_isAnonymous(CXCursor C); + +/** + * Determine whether the given cursor represents an anonymous record + * declaration. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isAnonymousRecordDecl(CXCursor C); + +/** + * Determine whether the given cursor represents an inline namespace + * declaration. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isInlineNamespace(CXCursor C); + +enum CXRefQualifierKind { + /** No ref-qualifier was provided. */ + CXRefQualifier_None = 0, + /** An lvalue ref-qualifier was provided (\c &). */ + CXRefQualifier_LValue, + /** An rvalue ref-qualifier was provided (\c &&). */ + CXRefQualifier_RValue +}; + +/** + * Returns the number of template arguments for given template + * specialization, or -1 if type \c T is not a template specialization. + */ +CINDEX_LINKAGE int clang_Type_getNumTemplateArguments(CXType T); + +/** + * Returns the type template argument of a template class specialization + * at given index. + * + * This function only returns template type arguments and does not handle + * template template arguments or variadic packs. + */ +CINDEX_LINKAGE CXType clang_Type_getTemplateArgumentAsType(CXType T, + unsigned i); + +/** + * Retrieve the ref-qualifier kind of a function or method. + * + * The ref-qualifier is returned for C++ functions or methods. For other types + * or non-C++ declarations, CXRefQualifier_None is returned. + */ +CINDEX_LINKAGE enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T); + +/** + * Returns 1 if the base class specified by the cursor with kind + * CX_CXXBaseSpecifier is virtual. + */ +CINDEX_LINKAGE unsigned clang_isVirtualBase(CXCursor); + +/** + * Represents the C++ access control level to a base class for a + * cursor with kind CX_CXXBaseSpecifier. + */ +enum CX_CXXAccessSpecifier { + CX_CXXInvalidAccessSpecifier, + CX_CXXPublic, + CX_CXXProtected, + CX_CXXPrivate +}; + +/** + * Returns the access control level for the referenced object. + * + * If the cursor refers to a C++ declaration, its access control level within + * its parent scope is returned. Otherwise, if the cursor refers to a base + * specifier or access specifier, the specifier itself is returned. + */ +CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor); + +/** + * Represents the storage classes as declared in the source. CX_SC_Invalid + * was added for the case that the passed cursor in not a declaration. + */ +enum CX_StorageClass { + CX_SC_Invalid, + CX_SC_None, + CX_SC_Extern, + CX_SC_Static, + CX_SC_PrivateExtern, + CX_SC_OpenCLWorkGroupLocal, + CX_SC_Auto, + CX_SC_Register +}; + +/** + * Returns the storage class for a function or variable declaration. + * + * If the passed in Cursor is not a function or variable declaration, + * CX_SC_Invalid is returned else the storage class. + */ +CINDEX_LINKAGE enum CX_StorageClass clang_Cursor_getStorageClass(CXCursor); + +/** + * Determine the number of overloaded declarations referenced by a + * \c CXCursor_OverloadedDeclRef cursor. + * + * \param cursor The cursor whose overloaded declarations are being queried. + * + * \returns The number of overloaded declarations referenced by \c cursor. If it + * is not a \c CXCursor_OverloadedDeclRef cursor, returns 0. + */ +CINDEX_LINKAGE unsigned clang_getNumOverloadedDecls(CXCursor cursor); + +/** + * Retrieve a cursor for one of the overloaded declarations referenced + * by a \c CXCursor_OverloadedDeclRef cursor. + * + * \param cursor The cursor whose overloaded declarations are being queried. + * + * \param index The zero-based index into the set of overloaded declarations in + * the cursor. + * + * \returns A cursor representing the declaration referenced by the given + * \c cursor at the specified \c index. If the cursor does not have an + * associated set of overloaded declarations, or if the index is out of bounds, + * returns \c clang_getNullCursor(); + */ +CINDEX_LINKAGE CXCursor clang_getOverloadedDecl(CXCursor cursor, + unsigned index); + +/** + * @} + */ + +/** + * \defgroup CINDEX_ATTRIBUTES Information for attributes + * + * @{ + */ + +/** + * For cursors representing an iboutletcollection attribute, + * this function returns the collection element type. + * + */ +CINDEX_LINKAGE CXType clang_getIBOutletCollectionType(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors + * + * These routines provide the ability to traverse the abstract syntax tree + * using cursors. + * + * @{ + */ + +/** + * Describes how the traversal of the children of a particular + * cursor should proceed after visiting a particular child cursor. + * + * A value of this enumeration type should be returned by each + * \c CXCursorVisitor to indicate how clang_visitChildren() proceed. + */ +enum CXChildVisitResult { + /** + * Terminates the cursor traversal. + */ + CXChildVisit_Break, + /** + * Continues the cursor traversal with the next sibling of + * the cursor just visited, without visiting its children. + */ + CXChildVisit_Continue, + /** + * Recursively traverse the children of this cursor, using + * the same visitor and client data. + */ + CXChildVisit_Recurse +}; + +/** + * Visitor invoked for each cursor found by a traversal. + * + * This visitor function will be invoked for each cursor found by + * clang_visitCursorChildren(). Its first argument is the cursor being + * visited, its second argument is the parent visitor for that cursor, + * and its third argument is the client data provided to + * clang_visitCursorChildren(). + * + * The visitor should return one of the \c CXChildVisitResult values + * to direct clang_visitCursorChildren(). + */ +typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, + CXCursor parent, + CXClientData client_data); + +/** + * Visit the children of a particular cursor. + * + * This function visits all the direct children of the given cursor, + * invoking the given \p visitor function with the cursors of each + * visited child. The traversal may be recursive, if the visitor returns + * \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if + * the visitor returns \c CXChildVisit_Break. + * + * \param parent the cursor whose child may be visited. All kinds of + * cursors can be visited, including invalid cursors (which, by + * definition, have no children). + * + * \param visitor the visitor function that will be invoked for each + * child of \p parent. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the visitor each time it is invoked. + * + * \returns a non-zero value if the traversal was terminated + * prematurely by the visitor returning \c CXChildVisit_Break. + */ +CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, + CXCursorVisitor visitor, + CXClientData client_data); +/** + * Visitor invoked for each cursor found by a traversal. + * + * This visitor block will be invoked for each cursor found by + * clang_visitChildrenWithBlock(). Its first argument is the cursor being + * visited, its second argument is the parent visitor for that cursor. + * + * The visitor should return one of the \c CXChildVisitResult values + * to direct clang_visitChildrenWithBlock(). + */ +#if __has_feature(blocks) +typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor, + CXCursor parent); +#else +typedef struct _CXChildVisitResult *CXCursorVisitorBlock; +#endif + +/** + * Visits the children of a cursor using the specified block. Behaves + * identically to clang_visitChildren() in all other respects. + */ +CINDEX_LINKAGE unsigned +clang_visitChildrenWithBlock(CXCursor parent, CXCursorVisitorBlock block); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CURSOR_XREF Cross-referencing in the AST + * + * These routines provide the ability to determine references within and + * across translation units, by providing the names of the entities referenced + * by cursors, follow reference cursors to the declarations they reference, + * and associate declarations with their definitions. + * + * @{ + */ + +/** + * Retrieve a Unified Symbol Resolution (USR) for the entity referenced + * by the given cursor. + * + * A Unified Symbol Resolution (USR) is a string that identifies a particular + * entity (function, class, variable, etc.) within a program. USRs can be + * compared across translation units to determine, e.g., when references in + * one translation refer to an entity defined in another translation unit. + */ +CINDEX_LINKAGE CXString clang_getCursorUSR(CXCursor); + +/** + * Construct a USR for a specified Objective-C class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCClass(const char *class_name); + +/** + * Construct a USR for a specified Objective-C category. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCCategory( + const char *class_name, const char *category_name); + +/** + * Construct a USR for a specified Objective-C protocol. + */ +CINDEX_LINKAGE CXString +clang_constructUSR_ObjCProtocol(const char *protocol_name); + +/** + * Construct a USR for a specified Objective-C instance variable and + * the USR for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCIvar(const char *name, + CXString classUSR); + +/** + * Construct a USR for a specified Objective-C method and + * the USR for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCMethod(const char *name, + unsigned isInstanceMethod, + CXString classUSR); + +/** + * Construct a USR for a specified Objective-C property and the USR + * for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR); + +/** + * Retrieve a name for the entity referenced by this cursor. + */ +CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); + +/** + * Retrieve a range for a piece that forms the cursors spelling name. + * Most of the times there is only one range for the complete spelling but for + * Objective-C methods and Objective-C message expressions, there are multiple + * pieces for each selector identifier. + * + * \param pieceIndex the index of the spelling name piece. If this is greater + * than the actual number of pieces, it will return a NULL (invalid) range. + * + * \param options Reserved. + */ +CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange( + CXCursor, unsigned pieceIndex, unsigned options); + +/** + * Opaque pointer representing a policy that controls pretty printing + * for \c clang_getCursorPrettyPrinted. + */ +typedef void *CXPrintingPolicy; + +/** + * Properties for the printing policy. + * + * See \c clang::PrintingPolicy for more information. + */ +enum CXPrintingPolicyProperty { + CXPrintingPolicy_Indentation, + CXPrintingPolicy_SuppressSpecifiers, + CXPrintingPolicy_SuppressTagKeyword, + CXPrintingPolicy_IncludeTagDefinition, + CXPrintingPolicy_SuppressScope, + CXPrintingPolicy_SuppressUnwrittenScope, + CXPrintingPolicy_SuppressInitializers, + CXPrintingPolicy_ConstantArraySizeAsWritten, + CXPrintingPolicy_AnonymousTagLocations, + CXPrintingPolicy_SuppressStrongLifetime, + CXPrintingPolicy_SuppressLifetimeQualifiers, + CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors, + CXPrintingPolicy_Bool, + CXPrintingPolicy_Restrict, + CXPrintingPolicy_Alignof, + CXPrintingPolicy_UnderscoreAlignof, + CXPrintingPolicy_UseVoidForZeroParams, + CXPrintingPolicy_TerseOutput, + CXPrintingPolicy_PolishForDeclaration, + CXPrintingPolicy_Half, + CXPrintingPolicy_MSWChar, + CXPrintingPolicy_IncludeNewlines, + CXPrintingPolicy_MSVCFormatting, + CXPrintingPolicy_ConstantsAsWritten, + CXPrintingPolicy_SuppressImplicitBase, + CXPrintingPolicy_FullyQualifiedName, + + CXPrintingPolicy_LastProperty = CXPrintingPolicy_FullyQualifiedName +}; + +/** + * Get a property value for the given printing policy. + */ +CINDEX_LINKAGE unsigned +clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property); + +/** + * Set a property value for the given printing policy. + */ +CINDEX_LINKAGE void +clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property, + unsigned Value); + +/** + * Retrieve the default policy for the cursor. + * + * The policy should be released after use with \c + * clang_PrintingPolicy_dispose. + */ +CINDEX_LINKAGE CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor); + +/** + * Release a printing policy. + */ +CINDEX_LINKAGE void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy); + +/** + * Pretty print declarations. + * + * \param Cursor The cursor representing a declaration. + * + * \param Policy The policy to control the entities being printed. If + * NULL, a default policy is used. + * + * \returns The pretty printed declaration or the empty string for + * other cursors. + */ +CINDEX_LINKAGE CXString clang_getCursorPrettyPrinted(CXCursor Cursor, + CXPrintingPolicy Policy); + +/** + * Retrieve the display name for the entity referenced by this cursor. + * + * The display name contains extra information that helps identify the cursor, + * such as the parameters of a function or template or the arguments of a + * class template specialization. + */ +CINDEX_LINKAGE CXString clang_getCursorDisplayName(CXCursor); + +/** For a cursor that is a reference, retrieve a cursor representing the + * entity that it references. + * + * Reference cursors refer to other entities in the AST. For example, an + * Objective-C superclass reference cursor refers to an Objective-C class. + * This function produces the cursor for the Objective-C class from the + * cursor for the superclass reference. If the input cursor is a declaration or + * definition, it returns that declaration or definition unchanged. + * Otherwise, returns the NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCursorReferenced(CXCursor); + +/** + * For a cursor that is either a reference to or a declaration + * of some entity, retrieve a cursor that describes the definition of + * that entity. + * + * Some entities can be declared multiple times within a translation + * unit, but only one of those declarations can also be a + * definition. For example, given: + * + * \code + * int f(int, int); + * int g(int x, int y) { return f(x, y); } + * int f(int a, int b) { return a + b; } + * int f(int, int); + * \endcode + * + * there are three declarations of the function "f", but only the + * second one is a definition. The clang_getCursorDefinition() + * function will take any cursor pointing to a declaration of "f" + * (the first or fourth lines of the example) or a cursor referenced + * that uses "f" (the call to "f' inside "g") and will return a + * declaration cursor pointing to the definition (the second "f" + * declaration). + * + * If given a cursor for which there is no corresponding definition, + * e.g., because there is no definition of that entity within this + * translation unit, returns a NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCursorDefinition(CXCursor); + +/** + * Determine whether the declaration pointed to by this cursor + * is also a definition of that entity. + */ +CINDEX_LINKAGE unsigned clang_isCursorDefinition(CXCursor); + +/** + * Retrieve the canonical cursor corresponding to the given cursor. + * + * In the C family of languages, many kinds of entities can be declared several + * times within a single translation unit. For example, a structure type can + * be forward-declared (possibly multiple times) and later defined: + * + * \code + * struct X; + * struct X; + * struct X { + * int member; + * }; + * \endcode + * + * The declarations and the definition of \c X are represented by three + * different cursors, all of which are declarations of the same underlying + * entity. One of these cursor is considered the "canonical" cursor, which + * is effectively the representative for the underlying entity. One can + * determine if two cursors are declarations of the same underlying entity by + * comparing their canonical cursors. + * + * \returns The canonical cursor for the entity referred to by the given cursor. + */ +CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor); + +/** + * If the cursor points to a selector identifier in an Objective-C + * method or message expression, this returns the selector index. + * + * After getting a cursor with #clang_getCursor, this can be called to + * determine if the location points to a selector identifier. + * + * \returns The selector index if the cursor is an Objective-C method or message + * expression and the cursor is pointing to a selector identifier, or -1 + * otherwise. + */ +CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor); + +/** + * Given a cursor pointing to a C++ method call or an Objective-C + * message, returns non-zero if the method/message is "dynamic", meaning: + * + * For a C++ method: the call is virtual. + * For an Objective-C message: the receiver is an object instance, not 'super' + * or a specific class. + * + * If the method/message is "static" or the cursor does not point to a + * method/message, it will return zero. + */ +CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C); + +/** + * Given a cursor pointing to an Objective-C message or property + * reference, or C++ method call, returns the CXType of the receiver. + */ +CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C); + +/** + * Property attributes for a \c CXCursor_ObjCPropertyDecl. + */ +typedef enum { + CXObjCPropertyAttr_noattr = 0x00, + CXObjCPropertyAttr_readonly = 0x01, + CXObjCPropertyAttr_getter = 0x02, + CXObjCPropertyAttr_assign = 0x04, + CXObjCPropertyAttr_readwrite = 0x08, + CXObjCPropertyAttr_retain = 0x10, + CXObjCPropertyAttr_copy = 0x20, + CXObjCPropertyAttr_nonatomic = 0x40, + CXObjCPropertyAttr_setter = 0x80, + CXObjCPropertyAttr_atomic = 0x100, + CXObjCPropertyAttr_weak = 0x200, + CXObjCPropertyAttr_strong = 0x400, + CXObjCPropertyAttr_unsafe_unretained = 0x800, + CXObjCPropertyAttr_class = 0x1000 +} CXObjCPropertyAttrKind; + +/** + * Given a cursor that represents a property declaration, return the + * associated property attributes. The bits are formed from + * \c CXObjCPropertyAttrKind. + * + * \param reserved Reserved for future use, pass 0. + */ +CINDEX_LINKAGE unsigned +clang_Cursor_getObjCPropertyAttributes(CXCursor C, unsigned reserved); + +/** + * Given a cursor that represents a property declaration, return the + * name of the method that implements the getter. + */ +CINDEX_LINKAGE CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C); + +/** + * Given a cursor that represents a property declaration, return the + * name of the method that implements the setter, if any. + */ +CINDEX_LINKAGE CXString clang_Cursor_getObjCPropertySetterName(CXCursor C); + +/** + * 'Qualifiers' written next to the return and parameter types in + * Objective-C method declarations. + */ +typedef enum { + CXObjCDeclQualifier_None = 0x0, + CXObjCDeclQualifier_In = 0x1, + CXObjCDeclQualifier_Inout = 0x2, + CXObjCDeclQualifier_Out = 0x4, + CXObjCDeclQualifier_Bycopy = 0x8, + CXObjCDeclQualifier_Byref = 0x10, + CXObjCDeclQualifier_Oneway = 0x20 +} CXObjCDeclQualifierKind; + +/** + * Given a cursor that represents an Objective-C method or parameter + * declaration, return the associated Objective-C qualifiers for the return + * type or the parameter respectively. The bits are formed from + * CXObjCDeclQualifierKind. + */ +CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C); + +/** + * Given a cursor that represents an Objective-C method or property + * declaration, return non-zero if the declaration was affected by "\@optional". + * Returns zero if the cursor is not such a declaration or it is "\@required". + */ +CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C); + +/** + * Returns non-zero if the given cursor is a variadic function or method. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C); + +/** + * Returns non-zero if the given cursor points to a symbol marked with + * external_source_symbol attribute. + * + * \param language If non-NULL, and the attribute is present, will be set to + * the 'language' string from the attribute. + * + * \param definedIn If non-NULL, and the attribute is present, will be set to + * the 'definedIn' string from the attribute. + * + * \param isGenerated If non-NULL, and the attribute is present, will be set to + * non-zero if the 'generated_declaration' is set in the attribute. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isExternalSymbol(CXCursor C, + CXString *language, + CXString *definedIn, + unsigned *isGenerated); + +/** + * Given a cursor that represents a declaration, return the associated + * comment's source range. The range may include multiple consecutive comments + * with whitespace in between. + */ +CINDEX_LINKAGE CXSourceRange clang_Cursor_getCommentRange(CXCursor C); + +/** + * Given a cursor that represents a declaration, return the associated + * comment text, including comment markers. + */ +CINDEX_LINKAGE CXString clang_Cursor_getRawCommentText(CXCursor C); + +/** + * Given a cursor that represents a documentable entity (e.g., + * declaration), return the associated \paragraph; otherwise return the + * first paragraph. + */ +CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C); + +/** + * @} + */ + +/** \defgroup CINDEX_MANGLE Name Mangling API Functions + * + * @{ + */ + +/** + * Retrieve the CXString representing the mangled name of the cursor. + */ +CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor); + +/** + * Retrieve the CXStrings representing the mangled symbols of the C++ + * constructor or destructor at the cursor. + */ +CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor); + +/** + * Retrieve the CXStrings representing the mangled symbols of the ObjC + * class interface or implementation at the cursor. + */ +CINDEX_LINKAGE CXStringSet *clang_Cursor_getObjCManglings(CXCursor); + +/** + * @} + */ + +/** + * \defgroup CINDEX_MODULE Module introspection + * + * The functions in this group provide access to information about modules. + * + * @{ + */ + +typedef void *CXModule; + +/** + * Given a CXCursor_ModuleImportDecl cursor, return the associated module. + */ +CINDEX_LINKAGE CXModule clang_Cursor_getModule(CXCursor C); + +/** + * Given a CXFile header file, return the module that contains it, if one + * exists. + */ +CINDEX_LINKAGE CXModule clang_getModuleForFile(CXTranslationUnit, CXFile); + +/** + * \param Module a module object. + * + * \returns the module file where the provided module object came from. + */ +CINDEX_LINKAGE CXFile clang_Module_getASTFile(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the parent of a sub-module or NULL if the given module is top-level, + * e.g. for 'std.vector' it will return the 'std' module. + */ +CINDEX_LINKAGE CXModule clang_Module_getParent(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the name of the module, e.g. for the 'std.vector' sub-module it + * will return "vector". + */ +CINDEX_LINKAGE CXString clang_Module_getName(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the full name of the module, e.g. "std.vector". + */ +CINDEX_LINKAGE CXString clang_Module_getFullName(CXModule Module); + +/** + * \param Module a module object. + * + * \returns non-zero if the module is a system one. + */ +CINDEX_LINKAGE int clang_Module_isSystem(CXModule Module); + +/** + * \param Module a module object. + * + * \returns the number of top level headers associated with this module. + */ +CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXTranslationUnit, + CXModule Module); + +/** + * \param Module a module object. + * + * \param Index top level header index (zero-based). + * + * \returns the specified top level header associated with the module. + */ +CINDEX_LINKAGE +CXFile clang_Module_getTopLevelHeader(CXTranslationUnit, CXModule Module, + unsigned Index); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CPP C++ AST introspection + * + * The routines in this group provide access information in the ASTs specific + * to C++ language features. + * + * @{ + */ + +/** + * Determine if a C++ constructor is a converting constructor. + */ +CINDEX_LINKAGE unsigned +clang_CXXConstructor_isConvertingConstructor(CXCursor C); + +/** + * Determine if a C++ constructor is a copy constructor. + */ +CINDEX_LINKAGE unsigned clang_CXXConstructor_isCopyConstructor(CXCursor C); + +/** + * Determine if a C++ constructor is the default constructor. + */ +CINDEX_LINKAGE unsigned clang_CXXConstructor_isDefaultConstructor(CXCursor C); + +/** + * Determine if a C++ constructor is a move constructor. + */ +CINDEX_LINKAGE unsigned clang_CXXConstructor_isMoveConstructor(CXCursor C); + +/** + * Determine if a C++ field is declared 'mutable'. + */ +CINDEX_LINKAGE unsigned clang_CXXField_isMutable(CXCursor C); + +/** + * Determine if a C++ method is declared '= default'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isDefaulted(CXCursor C); + +/** + * Determine if a C++ method is declared '= delete'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isDeleted(CXCursor C); + +/** + * Determine if a C++ member function or member function template is + * pure virtual. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isPureVirtual(CXCursor C); + +/** + * Determine if a C++ member function or member function template is + * declared 'static'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C); + +/** + * Determine if a C++ member function or member function template is + * explicitly declared 'virtual' or if it overrides a virtual method from + * one of the base classes. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); + +/** + * Determine if a C++ member function is a copy-assignment operator, + * returning 1 if such is the case and 0 otherwise. + * + * > A copy-assignment operator `X::operator=` is a non-static, + * > non-template member function of _class_ `X` with exactly one + * > parameter of type `X`, `X&`, `const X&`, `volatile X&` or `const + * > volatile X&`. + * + * That is, for example, the `operator=` in: + * + * class Foo { + * bool operator=(const volatile Foo&); + * }; + * + * Is a copy-assignment operator, while the `operator=` in: + * + * class Bar { + * bool operator=(const int&); + * }; + * + * Is not. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C); + +/** + * Determine if a C++ member function is a move-assignment operator, + * returning 1 if such is the case and 0 otherwise. + * + * > A move-assignment operator `X::operator=` is a non-static, + * > non-template member function of _class_ `X` with exactly one + * > parameter of type `X&&`, `const X&&`, `volatile X&&` or `const + * > volatile X&&`. + * + * That is, for example, the `operator=` in: + * + * class Foo { + * bool operator=(const volatile Foo&&); + * }; + * + * Is a move-assignment operator, while the `operator=` in: + * + * class Bar { + * bool operator=(const int&&); + * }; + * + * Is not. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isMoveAssignmentOperator(CXCursor C); + +/** + * Determines if a C++ constructor or conversion function was declared + * explicit, returning 1 if such is the case and 0 otherwise. + * + * Constructors or conversion functions are declared explicit through + * the use of the explicit specifier. + * + * For example, the following constructor and conversion function are + * not explicit as they lack the explicit specifier: + * + * class Foo { + * Foo(); + * operator int(); + * }; + * + * While the following constructor and conversion function are + * explicit as they are declared with the explicit specifier. + * + * class Foo { + * explicit Foo(); + * explicit operator int(); + * }; + * + * This function will return 0 when given a cursor pointing to one of + * the former declarations and it will return 1 for a cursor pointing + * to the latter declarations. + * + * The explicit specifier allows the user to specify a + * conditional compile-time expression whose value decides + * whether the marked element is explicit or not. + * + * For example: + * + * constexpr bool foo(int i) { return i % 2 == 0; } + * + * class Foo { + * explicit(foo(1)) Foo(); + * explicit(foo(2)) operator int(); + * } + * + * This function will return 0 for the constructor and 1 for + * the conversion function. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isExplicit(CXCursor C); + +/** + * Determine if a C++ record is abstract, i.e. whether a class or struct + * has a pure virtual member function. + */ +CINDEX_LINKAGE unsigned clang_CXXRecord_isAbstract(CXCursor C); + +/** + * Determine if an enum declaration refers to a scoped enum. + */ +CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); + +/** + * Determine if a C++ member function or member function template is + * declared 'const'. + */ +CINDEX_LINKAGE unsigned clang_CXXMethod_isConst(CXCursor C); + +/** + * Given a cursor that represents a template, determine + * the cursor kind of the specializations would be generated by instantiating + * the template. + * + * This routine can be used to determine what flavor of function template, + * class template, or class template partial specialization is stored in the + * cursor. For example, it can describe whether a class template cursor is + * declared with "struct", "class" or "union". + * + * \param C The cursor to query. This cursor should represent a template + * declaration. + * + * \returns The cursor kind of the specializations that would be generated + * by instantiating the template \p C. If \p C is not a template, returns + * \c CXCursor_NoDeclFound. + */ +CINDEX_LINKAGE enum CXCursorKind clang_getTemplateCursorKind(CXCursor C); + +/** + * Given a cursor that may represent a specialization or instantiation + * of a template, retrieve the cursor that represents the template that it + * specializes or from which it was instantiated. + * + * This routine determines the template involved both for explicit + * specializations of templates and for implicit instantiations of the template, + * both of which are referred to as "specializations". For a class template + * specialization (e.g., \c std::vector), this routine will return + * either the primary template (\c std::vector) or, if the specialization was + * instantiated from a class template partial specialization, the class template + * partial specialization. For a class template partial specialization and a + * function template specialization (including instantiations), this + * this routine will return the specialized template. + * + * For members of a class template (e.g., member functions, member classes, or + * static data members), returns the specialized or instantiated member. + * Although not strictly "templates" in the C++ language, members of class + * templates have the same notions of specializations and instantiations that + * templates do, so this routine treats them similarly. + * + * \param C A cursor that may be a specialization of a template or a member + * of a template. + * + * \returns If the given cursor is a specialization or instantiation of a + * template or a member thereof, the template or member that it specializes or + * from which it was instantiated. Otherwise, returns a NULL cursor. + */ +CINDEX_LINKAGE CXCursor clang_getSpecializedCursorTemplate(CXCursor C); + +/** + * Given a cursor that references something else, return the source range + * covering that reference. + * + * \param C A cursor pointing to a member reference, a declaration reference, or + * an operator call. + * \param NameFlags A bitset with three independent flags: + * CXNameRange_WantQualifier, CXNameRange_WantTemplateArgs, and + * CXNameRange_WantSinglePiece. + * \param PieceIndex For contiguous names or when passing the flag + * CXNameRange_WantSinglePiece, only one piece with index 0 is + * available. When the CXNameRange_WantSinglePiece flag is not passed for a + * non-contiguous names, this index can be used to retrieve the individual + * pieces of the name. See also CXNameRange_WantSinglePiece. + * + * \returns The piece of the name pointed to by the given cursor. If there is no + * name, or if the PieceIndex is out-of-range, a null-cursor will be returned. + */ +CINDEX_LINKAGE CXSourceRange clang_getCursorReferenceNameRange( + CXCursor C, unsigned NameFlags, unsigned PieceIndex); + +enum CXNameRefFlags { + /** + * Include the nested-name-specifier, e.g. Foo:: in x.Foo::y, in the + * range. + */ + CXNameRange_WantQualifier = 0x1, + + /** + * Include the explicit template arguments, e.g. \ in x.f, + * in the range. + */ + CXNameRange_WantTemplateArgs = 0x2, + + /** + * If the name is non-contiguous, return the full spanning range. + * + * Non-contiguous names occur in Objective-C when a selector with two or more + * parameters is used, or in C++ when using an operator: + * \code + * [object doSomething:here withValue:there]; // Objective-C + * return some_vector[1]; // C++ + * \endcode + */ + CXNameRange_WantSinglePiece = 0x4 +}; + +/** + * @} + */ + +/** + * \defgroup CINDEX_LEX Token extraction and manipulation + * + * The routines in this group provide access to the tokens within a + * translation unit, along with a semantic mapping of those tokens to + * their corresponding cursors. + * + * @{ + */ + +/** + * Describes a kind of token. + */ +typedef enum CXTokenKind { + /** + * A token that contains some kind of punctuation. + */ + CXToken_Punctuation, + + /** + * A language keyword. + */ + CXToken_Keyword, + + /** + * An identifier (that is not a keyword). + */ + CXToken_Identifier, + + /** + * A numeric, string, or character literal. + */ + CXToken_Literal, + + /** + * A comment. + */ + CXToken_Comment +} CXTokenKind; + +/** + * Describes a single preprocessing token. + */ +typedef struct { + unsigned int_data[4]; + void *ptr_data; +} CXToken; + +/** + * Get the raw lexical token starting with the given location. + * + * \param TU the translation unit whose text is being tokenized. + * + * \param Location the source location with which the token starts. + * + * \returns The token starting with the given location or NULL if no such token + * exist. The returned pointer must be freed with clang_disposeTokens before the + * translation unit is destroyed. + */ +CINDEX_LINKAGE CXToken *clang_getToken(CXTranslationUnit TU, + CXSourceLocation Location); + +/** + * Determine the kind of the given token. + */ +CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken); + +/** + * Determine the spelling of the given token. + * + * The spelling of a token is the textual representation of that token, e.g., + * the text of an identifier or keyword. + */ +CINDEX_LINKAGE CXString clang_getTokenSpelling(CXTranslationUnit, CXToken); + +/** + * Retrieve the source location of the given token. + */ +CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit, + CXToken); + +/** + * Retrieve a source range that covers the given token. + */ +CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken); + +/** + * Tokenize the source code described by the given range into raw + * lexical tokens. + * + * \param TU the translation unit whose text is being tokenized. + * + * \param Range the source range in which text should be tokenized. All of the + * tokens produced by tokenization will fall within this source range, + * + * \param Tokens this pointer will be set to point to the array of tokens + * that occur within the given source range. The returned pointer must be + * freed with clang_disposeTokens() before the translation unit is destroyed. + * + * \param NumTokens will be set to the number of tokens in the \c *Tokens + * array. + * + */ +CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, + CXToken **Tokens, unsigned *NumTokens); + +/** + * Annotate the given set of tokens by providing cursors for each token + * that can be mapped to a specific entity within the abstract syntax tree. + * + * This token-annotation routine is equivalent to invoking + * clang_getCursor() for the source locations of each of the + * tokens. The cursors provided are filtered, so that only those + * cursors that have a direct correspondence to the token are + * accepted. For example, given a function call \c f(x), + * clang_getCursor() would provide the following cursors: + * + * * when the cursor is over the 'f', a DeclRefExpr cursor referring to 'f'. + * * when the cursor is over the '(' or the ')', a CallExpr referring to 'f'. + * * when the cursor is over the 'x', a DeclRefExpr cursor referring to 'x'. + * + * Only the first and last of these cursors will occur within the + * annotate, since the tokens "f" and "x' directly refer to a function + * and a variable, respectively, but the parentheses are just a small + * part of the full syntax of the function call expression, which is + * not provided as an annotation. + * + * \param TU the translation unit that owns the given tokens. + * + * \param Tokens the set of tokens to annotate. + * + * \param NumTokens the number of tokens in \p Tokens. + * + * \param Cursors an array of \p NumTokens cursors, whose contents will be + * replaced with the cursors corresponding to each token. + */ +CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, + unsigned NumTokens, CXCursor *Cursors); + +/** + * Free the given set of tokens. + */ +CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, CXToken *Tokens, + unsigned NumTokens); + +/** + * @} + */ + +/** + * \defgroup CINDEX_DEBUG Debugging facilities + * + * These routines are used for testing and debugging, only, and should not + * be relied upon. + * + * @{ + */ + +/* for debug/testing */ +CINDEX_LINKAGE CXString clang_getCursorKindSpelling(enum CXCursorKind Kind); +CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent( + CXCursor, const char **startBuf, const char **endBuf, unsigned *startLine, + unsigned *startColumn, unsigned *endLine, unsigned *endColumn); +CINDEX_LINKAGE void clang_enableStackTraces(void); +CINDEX_LINKAGE void clang_executeOnThread(void (*fn)(void *), void *user_data, + unsigned stack_size); + +/** + * @} + */ + +/** + * \defgroup CINDEX_CODE_COMPLET Code completion + * + * Code completion involves taking an (incomplete) source file, along with + * knowledge of where the user is actively editing that file, and suggesting + * syntactically- and semantically-valid constructs that the user might want to + * use at that particular point in the source code. These data structures and + * routines provide support for code completion. + * + * @{ + */ + +/** + * A semantic string that describes a code-completion result. + * + * A semantic string that describes the formatting of a code-completion + * result as a single "template" of text that should be inserted into the + * source buffer when a particular code-completion result is selected. + * Each semantic string is made up of some number of "chunks", each of which + * contains some text along with a description of what that text means, e.g., + * the name of the entity being referenced, whether the text chunk is part of + * the template, or whether it is a "placeholder" that the user should replace + * with actual code,of a specific kind. See \c CXCompletionChunkKind for a + * description of the different kinds of chunks. + */ +typedef void *CXCompletionString; + +/** + * A single result of code completion. + */ +typedef struct { + /** + * The kind of entity that this completion refers to. + * + * The cursor kind will be a macro, keyword, or a declaration (one of the + * *Decl cursor kinds), describing the entity that the completion is + * referring to. + * + * \todo In the future, we would like to provide a full cursor, to allow + * the client to extract additional information from declaration. + */ + enum CXCursorKind CursorKind; + + /** + * The code-completion string that describes how to insert this + * code-completion result into the editing buffer. + */ + CXCompletionString CompletionString; +} CXCompletionResult; + +/** + * Describes a single piece of text within a code-completion string. + * + * Each "chunk" within a code-completion string (\c CXCompletionString) is + * either a piece of text with a specific "kind" that describes how that text + * should be interpreted by the client or is another completion string. + */ +enum CXCompletionChunkKind { + /** + * A code-completion string that describes "optional" text that + * could be a part of the template (but is not required). + * + * The Optional chunk is the only kind of chunk that has a code-completion + * string for its representation, which is accessible via + * \c clang_getCompletionChunkCompletionString(). The code-completion string + * describes an additional part of the template that is completely optional. + * For example, optional chunks can be used to describe the placeholders for + * arguments that match up with defaulted function parameters, e.g. given: + * + * \code + * void f(int x, float y = 3.14, double z = 2.71828); + * \endcode + * + * The code-completion string for this function would contain: + * - a TypedText chunk for "f". + * - a LeftParen chunk for "(". + * - a Placeholder chunk for "int x" + * - an Optional chunk containing the remaining defaulted arguments, e.g., + * - a Comma chunk for "," + * - a Placeholder chunk for "float y" + * - an Optional chunk containing the last defaulted argument: + * - a Comma chunk for "," + * - a Placeholder chunk for "double z" + * - a RightParen chunk for ")" + * + * There are many ways to handle Optional chunks. Two simple approaches are: + * - Completely ignore optional chunks, in which case the template for the + * function "f" would only include the first parameter ("int x"). + * - Fully expand all optional chunks, in which case the template for the + * function "f" would have all of the parameters. + */ + CXCompletionChunk_Optional, + /** + * Text that a user would be expected to type to get this + * code-completion result. + * + * There will be exactly one "typed text" chunk in a semantic string, which + * will typically provide the spelling of a keyword or the name of a + * declaration that could be used at the current code point. Clients are + * expected to filter the code-completion results based on the text in this + * chunk. + */ + CXCompletionChunk_TypedText, + /** + * Text that should be inserted as part of a code-completion result. + * + * A "text" chunk represents text that is part of the template to be + * inserted into user code should this particular code-completion result + * be selected. + */ + CXCompletionChunk_Text, + /** + * Placeholder text that should be replaced by the user. + * + * A "placeholder" chunk marks a place where the user should insert text + * into the code-completion template. For example, placeholders might mark + * the function parameters for a function declaration, to indicate that the + * user should provide arguments for each of those parameters. The actual + * text in a placeholder is a suggestion for the text to display before + * the user replaces the placeholder with real code. + */ + CXCompletionChunk_Placeholder, + /** + * Informative text that should be displayed but never inserted as + * part of the template. + * + * An "informative" chunk contains annotations that can be displayed to + * help the user decide whether a particular code-completion result is the + * right option, but which is not part of the actual template to be inserted + * by code completion. + */ + CXCompletionChunk_Informative, + /** + * Text that describes the current parameter when code-completion is + * referring to function call, message send, or template specialization. + * + * A "current parameter" chunk occurs when code-completion is providing + * information about a parameter corresponding to the argument at the + * code-completion point. For example, given a function + * + * \code + * int add(int x, int y); + * \endcode + * + * and the source code \c add(, where the code-completion point is after the + * "(", the code-completion string will contain a "current parameter" chunk + * for "int x", indicating that the current argument will initialize that + * parameter. After typing further, to \c add(17, (where the code-completion + * point is after the ","), the code-completion string will contain a + * "current parameter" chunk to "int y". + */ + CXCompletionChunk_CurrentParameter, + /** + * A left parenthesis ('('), used to initiate a function call or + * signal the beginning of a function parameter list. + */ + CXCompletionChunk_LeftParen, + /** + * A right parenthesis (')'), used to finish a function call or + * signal the end of a function parameter list. + */ + CXCompletionChunk_RightParen, + /** + * A left bracket ('['). + */ + CXCompletionChunk_LeftBracket, + /** + * A right bracket (']'). + */ + CXCompletionChunk_RightBracket, + /** + * A left brace ('{'). + */ + CXCompletionChunk_LeftBrace, + /** + * A right brace ('}'). + */ + CXCompletionChunk_RightBrace, + /** + * A left angle bracket ('<'). + */ + CXCompletionChunk_LeftAngle, + /** + * A right angle bracket ('>'). + */ + CXCompletionChunk_RightAngle, + /** + * A comma separator (','). + */ + CXCompletionChunk_Comma, + /** + * Text that specifies the result type of a given result. + * + * This special kind of informative chunk is not meant to be inserted into + * the text buffer. Rather, it is meant to illustrate the type that an + * expression using the given completion string would have. + */ + CXCompletionChunk_ResultType, + /** + * A colon (':'). + */ + CXCompletionChunk_Colon, + /** + * A semicolon (';'). + */ + CXCompletionChunk_SemiColon, + /** + * An '=' sign. + */ + CXCompletionChunk_Equal, + /** + * Horizontal space (' '). + */ + CXCompletionChunk_HorizontalSpace, + /** + * Vertical space ('\\n'), after which it is generally a good idea to + * perform indentation. + */ + CXCompletionChunk_VerticalSpace +}; + +/** + * Determine the kind of a particular chunk within a completion string. + * + * \param completion_string the completion string to query. + * + * \param chunk_number the 0-based index of the chunk in the completion string. + * + * \returns the kind of the chunk at the index \c chunk_number. + */ +CINDEX_LINKAGE enum CXCompletionChunkKind +clang_getCompletionChunkKind(CXCompletionString completion_string, + unsigned chunk_number); + +/** + * Retrieve the text associated with a particular chunk within a + * completion string. + * + * \param completion_string the completion string to query. + * + * \param chunk_number the 0-based index of the chunk in the completion string. + * + * \returns the text associated with the chunk at index \c chunk_number. + */ +CINDEX_LINKAGE CXString clang_getCompletionChunkText( + CXCompletionString completion_string, unsigned chunk_number); + +/** + * Retrieve the completion string associated with a particular chunk + * within a completion string. + * + * \param completion_string the completion string to query. + * + * \param chunk_number the 0-based index of the chunk in the completion string. + * + * \returns the completion string associated with the chunk at index + * \c chunk_number. + */ +CINDEX_LINKAGE CXCompletionString clang_getCompletionChunkCompletionString( + CXCompletionString completion_string, unsigned chunk_number); + +/** + * Retrieve the number of chunks in the given code-completion string. + */ +CINDEX_LINKAGE unsigned +clang_getNumCompletionChunks(CXCompletionString completion_string); + +/** + * Determine the priority of this code completion. + * + * The priority of a code completion indicates how likely it is that this + * particular completion is the completion that the user will select. The + * priority is selected by various internal heuristics. + * + * \param completion_string The completion string to query. + * + * \returns The priority of this completion string. Smaller values indicate + * higher-priority (more likely) completions. + */ +CINDEX_LINKAGE unsigned +clang_getCompletionPriority(CXCompletionString completion_string); + +/** + * Determine the availability of the entity that this code-completion + * string refers to. + * + * \param completion_string The completion string to query. + * + * \returns The availability of the completion string. + */ +CINDEX_LINKAGE enum CXAvailabilityKind +clang_getCompletionAvailability(CXCompletionString completion_string); + +/** + * Retrieve the number of annotations associated with the given + * completion string. + * + * \param completion_string the completion string to query. + * + * \returns the number of annotations associated with the given completion + * string. + */ +CINDEX_LINKAGE unsigned +clang_getCompletionNumAnnotations(CXCompletionString completion_string); + +/** + * Retrieve the annotation associated with the given completion string. + * + * \param completion_string the completion string to query. + * + * \param annotation_number the 0-based index of the annotation of the + * completion string. + * + * \returns annotation string associated with the completion at index + * \c annotation_number, or a NULL string if that annotation is not available. + */ +CINDEX_LINKAGE CXString clang_getCompletionAnnotation( + CXCompletionString completion_string, unsigned annotation_number); + +/** + * Retrieve the parent context of the given completion string. + * + * The parent context of a completion string is the semantic parent of + * the declaration (if any) that the code completion represents. For example, + * a code completion for an Objective-C method would have the method's class + * or protocol as its context. + * + * \param completion_string The code completion string whose parent is + * being queried. + * + * \param kind DEPRECATED: always set to CXCursor_NotImplemented if non-NULL. + * + * \returns The name of the completion parent, e.g., "NSObject" if + * the completion string represents a method in the NSObject class. + */ +CINDEX_LINKAGE CXString clang_getCompletionParent( + CXCompletionString completion_string, enum CXCursorKind *kind); + +/** + * Retrieve the brief documentation comment attached to the declaration + * that corresponds to the given completion string. + */ +CINDEX_LINKAGE CXString +clang_getCompletionBriefComment(CXCompletionString completion_string); + +/** + * Retrieve a completion string for an arbitrary declaration or macro + * definition cursor. + * + * \param cursor The cursor to query. + * + * \returns A non-context-sensitive completion string for declaration and macro + * definition cursors, or NULL for other kinds of cursors. + */ +CINDEX_LINKAGE CXCompletionString +clang_getCursorCompletionString(CXCursor cursor); + +/** + * Contains the results of code-completion. + * + * This data structure contains the results of code completion, as + * produced by \c clang_codeCompleteAt(). Its contents must be freed by + * \c clang_disposeCodeCompleteResults. + */ +typedef struct { + /** + * The code-completion results. + */ + CXCompletionResult *Results; + + /** + * The number of code-completion results stored in the + * \c Results array. + */ + unsigned NumResults; +} CXCodeCompleteResults; + +/** + * Retrieve the number of fix-its for the given completion index. + * + * Calling this makes sense only if CXCodeComplete_IncludeCompletionsWithFixIts + * option was set. + * + * \param results The structure keeping all completion results + * + * \param completion_index The index of the completion + * + * \return The number of fix-its which must be applied before the completion at + * completion_index can be applied + */ +CINDEX_LINKAGE unsigned +clang_getCompletionNumFixIts(CXCodeCompleteResults *results, + unsigned completion_index); + +/** + * Fix-its that *must* be applied before inserting the text for the + * corresponding completion. + * + * By default, clang_codeCompleteAt() only returns completions with empty + * fix-its. Extra completions with non-empty fix-its should be explicitly + * requested by setting CXCodeComplete_IncludeCompletionsWithFixIts. + * + * For the clients to be able to compute position of the cursor after applying + * fix-its, the following conditions are guaranteed to hold for + * replacement_range of the stored fix-its: + * - Ranges in the fix-its are guaranteed to never contain the completion + * point (or identifier under completion point, if any) inside them, except + * at the start or at the end of the range. + * - If a fix-it range starts or ends with completion point (or starts or + * ends after the identifier under completion point), it will contain at + * least one character. It allows to unambiguously recompute completion + * point after applying the fix-it. + * + * The intuition is that provided fix-its change code around the identifier we + * complete, but are not allowed to touch the identifier itself or the + * completion point. One example of completions with corrections are the ones + * replacing '.' with '->' and vice versa: + * + * std::unique_ptr> vec_ptr; + * In 'vec_ptr.^', one of the completions is 'push_back', it requires + * replacing '.' with '->'. + * In 'vec_ptr->^', one of the completions is 'release', it requires + * replacing '->' with '.'. + * + * \param results The structure keeping all completion results + * + * \param completion_index The index of the completion + * + * \param fixit_index The index of the fix-it for the completion at + * completion_index + * + * \param replacement_range The fix-it range that must be replaced before the + * completion at completion_index can be applied + * + * \returns The fix-it string that must replace the code at replacement_range + * before the completion at completion_index can be applied + */ +CINDEX_LINKAGE CXString clang_getCompletionFixIt( + CXCodeCompleteResults *results, unsigned completion_index, + unsigned fixit_index, CXSourceRange *replacement_range); + +/** + * Flags that can be passed to \c clang_codeCompleteAt() to + * modify its behavior. + * + * The enumerators in this enumeration can be bitwise-OR'd together to + * provide multiple options to \c clang_codeCompleteAt(). + */ +enum CXCodeComplete_Flags { + /** + * Whether to include macros within the set of code + * completions returned. + */ + CXCodeComplete_IncludeMacros = 0x01, + + /** + * Whether to include code patterns for language constructs + * within the set of code completions, e.g., for loops. + */ + CXCodeComplete_IncludeCodePatterns = 0x02, + + /** + * Whether to include brief documentation within the set of code + * completions returned. + */ + CXCodeComplete_IncludeBriefComments = 0x04, + + /** + * Whether to speed up completion by omitting top- or namespace-level entities + * defined in the preamble. There's no guarantee any particular entity is + * omitted. This may be useful if the headers are indexed externally. + */ + CXCodeComplete_SkipPreamble = 0x08, + + /** + * Whether to include completions with small + * fix-its, e.g. change '.' to '->' on member access, etc. + */ + CXCodeComplete_IncludeCompletionsWithFixIts = 0x10 +}; + +/** + * Bits that represent the context under which completion is occurring. + * + * The enumerators in this enumeration may be bitwise-OR'd together if multiple + * contexts are occurring simultaneously. + */ +enum CXCompletionContext { + /** + * The context for completions is unexposed, as only Clang results + * should be included. (This is equivalent to having no context bits set.) + */ + CXCompletionContext_Unexposed = 0, + + /** + * Completions for any possible type should be included in the results. + */ + CXCompletionContext_AnyType = 1 << 0, + + /** + * Completions for any possible value (variables, function calls, etc.) + * should be included in the results. + */ + CXCompletionContext_AnyValue = 1 << 1, + /** + * Completions for values that resolve to an Objective-C object should + * be included in the results. + */ + CXCompletionContext_ObjCObjectValue = 1 << 2, + /** + * Completions for values that resolve to an Objective-C selector + * should be included in the results. + */ + CXCompletionContext_ObjCSelectorValue = 1 << 3, + /** + * Completions for values that resolve to a C++ class type should be + * included in the results. + */ + CXCompletionContext_CXXClassTypeValue = 1 << 4, + + /** + * Completions for fields of the member being accessed using the dot + * operator should be included in the results. + */ + CXCompletionContext_DotMemberAccess = 1 << 5, + /** + * Completions for fields of the member being accessed using the arrow + * operator should be included in the results. + */ + CXCompletionContext_ArrowMemberAccess = 1 << 6, + /** + * Completions for properties of the Objective-C object being accessed + * using the dot operator should be included in the results. + */ + CXCompletionContext_ObjCPropertyAccess = 1 << 7, + + /** + * Completions for enum tags should be included in the results. + */ + CXCompletionContext_EnumTag = 1 << 8, + /** + * Completions for union tags should be included in the results. + */ + CXCompletionContext_UnionTag = 1 << 9, + /** + * Completions for struct tags should be included in the results. + */ + CXCompletionContext_StructTag = 1 << 10, + + /** + * Completions for C++ class names should be included in the results. + */ + CXCompletionContext_ClassTag = 1 << 11, + /** + * Completions for C++ namespaces and namespace aliases should be + * included in the results. + */ + CXCompletionContext_Namespace = 1 << 12, + /** + * Completions for C++ nested name specifiers should be included in + * the results. + */ + CXCompletionContext_NestedNameSpecifier = 1 << 13, + + /** + * Completions for Objective-C interfaces (classes) should be included + * in the results. + */ + CXCompletionContext_ObjCInterface = 1 << 14, + /** + * Completions for Objective-C protocols should be included in + * the results. + */ + CXCompletionContext_ObjCProtocol = 1 << 15, + /** + * Completions for Objective-C categories should be included in + * the results. + */ + CXCompletionContext_ObjCCategory = 1 << 16, + /** + * Completions for Objective-C instance messages should be included + * in the results. + */ + CXCompletionContext_ObjCInstanceMessage = 1 << 17, + /** + * Completions for Objective-C class messages should be included in + * the results. + */ + CXCompletionContext_ObjCClassMessage = 1 << 18, + /** + * Completions for Objective-C selector names should be included in + * the results. + */ + CXCompletionContext_ObjCSelectorName = 1 << 19, + + /** + * Completions for preprocessor macro names should be included in + * the results. + */ + CXCompletionContext_MacroName = 1 << 20, + + /** + * Natural language completions should be included in the results. + */ + CXCompletionContext_NaturalLanguage = 1 << 21, + + /** + * #include file completions should be included in the results. + */ + CXCompletionContext_IncludedFile = 1 << 22, + + /** + * The current context is unknown, so set all contexts. + */ + CXCompletionContext_Unknown = ((1 << 23) - 1) +}; + +/** + * Returns a default set of code-completion options that can be + * passed to\c clang_codeCompleteAt(). + */ +CINDEX_LINKAGE unsigned clang_defaultCodeCompleteOptions(void); + +/** + * Perform code completion at a given location in a translation unit. + * + * This function performs code completion at a particular file, line, and + * column within source code, providing results that suggest potential + * code snippets based on the context of the completion. The basic model + * for code completion is that Clang will parse a complete source file, + * performing syntax checking up to the location where code-completion has + * been requested. At that point, a special code-completion token is passed + * to the parser, which recognizes this token and determines, based on the + * current location in the C/Objective-C/C++ grammar and the state of + * semantic analysis, what completions to provide. These completions are + * returned via a new \c CXCodeCompleteResults structure. + * + * Code completion itself is meant to be triggered by the client when the + * user types punctuation characters or whitespace, at which point the + * code-completion location will coincide with the cursor. For example, if \c p + * is a pointer, code-completion might be triggered after the "-" and then + * after the ">" in \c p->. When the code-completion location is after the ">", + * the completion results will provide, e.g., the members of the struct that + * "p" points to. The client is responsible for placing the cursor at the + * beginning of the token currently being typed, then filtering the results + * based on the contents of the token. For example, when code-completing for + * the expression \c p->get, the client should provide the location just after + * the ">" (e.g., pointing at the "g") to this code-completion hook. Then, the + * client can filter the results based on the current token text ("get"), only + * showing those results that start with "get". The intent of this interface + * is to separate the relatively high-latency acquisition of code-completion + * results from the filtering of results on a per-character basis, which must + * have a lower latency. + * + * \param TU The translation unit in which code-completion should + * occur. The source files for this translation unit need not be + * completely up-to-date (and the contents of those source files may + * be overridden via \p unsaved_files). Cursors referring into the + * translation unit may be invalidated by this invocation. + * + * \param complete_filename The name of the source file where code + * completion should be performed. This filename may be any file + * included in the translation unit. + * + * \param complete_line The line at which code-completion should occur. + * + * \param complete_column The column at which code-completion should occur. + * Note that the column should point just after the syntactic construct that + * initiated code completion, and not in the middle of a lexical token. + * + * \param unsaved_files the Files that have not yet been saved to disk + * but may be required for parsing or code completion, including the + * contents of those files. The contents and name of these files (as + * specified by CXUnsavedFile) are copied when necessary, so the + * client only needs to guarantee their validity until the call to + * this function returns. + * + * \param num_unsaved_files The number of unsaved file entries in \p + * unsaved_files. + * + * \param options Extra options that control the behavior of code + * completion, expressed as a bitwise OR of the enumerators of the + * CXCodeComplete_Flags enumeration. The + * \c clang_defaultCodeCompleteOptions() function returns a default set + * of code-completion options. + * + * \returns If successful, a new \c CXCodeCompleteResults structure + * containing code-completion results, which should eventually be + * freed with \c clang_disposeCodeCompleteResults(). If code + * completion fails, returns NULL. + */ +CINDEX_LINKAGE +CXCodeCompleteResults * +clang_codeCompleteAt(CXTranslationUnit TU, const char *complete_filename, + unsigned complete_line, unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, unsigned options); + +/** + * Sort the code-completion results in case-insensitive alphabetical + * order. + * + * \param Results The set of results to sort. + * \param NumResults The number of results in \p Results. + */ +CINDEX_LINKAGE +void clang_sortCodeCompletionResults(CXCompletionResult *Results, + unsigned NumResults); + +/** + * Free the given set of code-completion results. + */ +CINDEX_LINKAGE +void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results); + +/** + * Determine the number of diagnostics produced prior to the + * location where code completion was performed. + */ +CINDEX_LINKAGE +unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results); + +/** + * Retrieve a diagnostic associated with the given code completion. + * + * \param Results the code completion results to query. + * \param Index the zero-based diagnostic number to retrieve. + * + * \returns the requested diagnostic. This diagnostic must be freed + * via a call to \c clang_disposeDiagnostic(). + */ +CINDEX_LINKAGE +CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results, + unsigned Index); + +/** + * Determines what completions are appropriate for the context + * the given code completion. + * + * \param Results the code completion results to query + * + * \returns the kinds of completions that are appropriate for use + * along with the given code completion results. + */ +CINDEX_LINKAGE +unsigned long long +clang_codeCompleteGetContexts(CXCodeCompleteResults *Results); + +/** + * Returns the cursor kind for the container for the current code + * completion context. The container is only guaranteed to be set for + * contexts where a container exists (i.e. member accesses or Objective-C + * message sends); if there is not a container, this function will return + * CXCursor_InvalidCode. + * + * \param Results the code completion results to query + * + * \param IsIncomplete on return, this value will be false if Clang has complete + * information about the container. If Clang does not have complete + * information, this value will be true. + * + * \returns the container kind, or CXCursor_InvalidCode if there is not a + * container + */ +CINDEX_LINKAGE +enum CXCursorKind +clang_codeCompleteGetContainerKind(CXCodeCompleteResults *Results, + unsigned *IsIncomplete); + +/** + * Returns the USR for the container for the current code completion + * context. If there is not a container for the current context, this + * function will return the empty string. + * + * \param Results the code completion results to query + * + * \returns the USR for the container + */ +CINDEX_LINKAGE +CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *Results); + +/** + * Returns the currently-entered selector for an Objective-C message + * send, formatted like "initWithFoo:bar:". Only guaranteed to return a + * non-empty string for CXCompletionContext_ObjCInstanceMessage and + * CXCompletionContext_ObjCClassMessage. + * + * \param Results the code completion results to query + * + * \returns the selector (or partial selector) that has been entered thus far + * for an Objective-C message send. + */ +CINDEX_LINKAGE +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results); + +/** + * @} + */ + +/** + * \defgroup CINDEX_MISC Miscellaneous utility functions + * + * @{ + */ + +/** + * Return a version string, suitable for showing to a user, but not + * intended to be parsed (the format is not guaranteed to be stable). + */ +CINDEX_LINKAGE CXString clang_getClangVersion(void); + +/** + * Enable/disable crash recovery. + * + * \param isEnabled Flag to indicate if crash recovery is enabled. A non-zero + * value enables crash recovery, while 0 disables it. + */ +CINDEX_LINKAGE void clang_toggleCrashRecovery(unsigned isEnabled); + +/** + * Visitor invoked for each file in a translation unit + * (used with clang_getInclusions()). + * + * This visitor function will be invoked by clang_getInclusions() for each + * file included (either at the top-level or by \#include directives) within + * a translation unit. The first argument is the file being included, and + * the second and third arguments provide the inclusion stack. The + * array is sorted in order of immediate inclusion. For example, + * the first element refers to the location that included 'included_file'. + */ +typedef void (*CXInclusionVisitor)(CXFile included_file, + CXSourceLocation *inclusion_stack, + unsigned include_len, + CXClientData client_data); + +/** + * Visit the set of preprocessor inclusions in a translation unit. + * The visitor function is called with the provided data for every included + * file. This does not include headers included by the PCH file (unless one + * is inspecting the inclusions in the PCH file itself). + */ +CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu, + CXInclusionVisitor visitor, + CXClientData client_data); + +typedef enum { + CXEval_Int = 1, + CXEval_Float = 2, + CXEval_ObjCStrLiteral = 3, + CXEval_StrLiteral = 4, + CXEval_CFStr = 5, + CXEval_Other = 6, + + CXEval_UnExposed = 0 + +} CXEvalResultKind; + +/** + * Evaluation result of a cursor + */ +typedef void *CXEvalResult; + +/** + * If cursor is a statement declaration tries to evaluate the + * statement and if its variable, tries to evaluate its initializer, + * into its corresponding type. + * If it's an expression, tries to evaluate the expression. + */ +CINDEX_LINKAGE CXEvalResult clang_Cursor_Evaluate(CXCursor C); + +/** + * Returns the kind of the evaluated result. + */ +CINDEX_LINKAGE CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E); + +/** + * Returns the evaluation result as integer if the + * kind is Int. + */ +CINDEX_LINKAGE int clang_EvalResult_getAsInt(CXEvalResult E); + +/** + * Returns the evaluation result as a long long integer if the + * kind is Int. This prevents overflows that may happen if the result is + * returned with clang_EvalResult_getAsInt. + */ +CINDEX_LINKAGE long long clang_EvalResult_getAsLongLong(CXEvalResult E); + +/** + * Returns a non-zero value if the kind is Int and the evaluation + * result resulted in an unsigned integer. + */ +CINDEX_LINKAGE unsigned clang_EvalResult_isUnsignedInt(CXEvalResult E); + +/** + * Returns the evaluation result as an unsigned integer if + * the kind is Int and clang_EvalResult_isUnsignedInt is non-zero. + */ +CINDEX_LINKAGE unsigned long long +clang_EvalResult_getAsUnsigned(CXEvalResult E); + +/** + * Returns the evaluation result as double if the + * kind is double. + */ +CINDEX_LINKAGE double clang_EvalResult_getAsDouble(CXEvalResult E); + +/** + * Returns the evaluation result as a constant string if the + * kind is other than Int or float. User must not free this pointer, + * instead call clang_EvalResult_dispose on the CXEvalResult returned + * by clang_Cursor_Evaluate. + */ +CINDEX_LINKAGE const char *clang_EvalResult_getAsStr(CXEvalResult E); + +/** + * Disposes the created Eval memory. + */ +CINDEX_LINKAGE void clang_EvalResult_dispose(CXEvalResult E); +/** + * @} + */ + +/** \defgroup CINDEX_REMAPPING Remapping functions + * + * @{ + */ + +/** + * A remapping of original source files and their translated files. + */ +typedef void *CXRemapping; + +/** + * Retrieve a remapping. + * + * \param path the path that contains metadata about remappings. + * + * \returns the requested remapping. This remapping must be freed + * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred. + */ +CINDEX_LINKAGE CXRemapping clang_getRemappings(const char *path); + +/** + * Retrieve a remapping. + * + * \param filePaths pointer to an array of file paths containing remapping info. + * + * \param numFiles number of file paths. + * + * \returns the requested remapping. This remapping must be freed + * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred. + */ +CINDEX_LINKAGE +CXRemapping clang_getRemappingsFromFileList(const char **filePaths, + unsigned numFiles); + +/** + * Determine the number of remappings. + */ +CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping); + +/** + * Get the original and the associated filename from the remapping. + * + * \param original If non-NULL, will be set to the original filename. + * + * \param transformed If non-NULL, will be set to the filename that the original + * is associated with. + */ +CINDEX_LINKAGE void clang_remap_getFilenames(CXRemapping, unsigned index, + CXString *original, + CXString *transformed); + +/** + * Dispose the remapping. + */ +CINDEX_LINKAGE void clang_remap_dispose(CXRemapping); + +/** + * @} + */ + +/** \defgroup CINDEX_HIGH Higher level API functions + * + * @{ + */ + +enum CXVisitorResult { CXVisit_Break, CXVisit_Continue }; + +typedef struct CXCursorAndRangeVisitor { + void *context; + enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange); +} CXCursorAndRangeVisitor; + +typedef enum { + /** + * Function returned successfully. + */ + CXResult_Success = 0, + /** + * One of the parameters was invalid for the function. + */ + CXResult_Invalid = 1, + /** + * The function was terminated by a callback (e.g. it returned + * CXVisit_Break) + */ + CXResult_VisitBreak = 2 + +} CXResult; + +/** + * Find references of a declaration in a specific file. + * + * \param cursor pointing to a declaration or a reference of one. + * + * \param file to search for references. + * + * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for + * each reference found. + * The CXSourceRange will point inside the file; if the reference is inside + * a macro (and not a macro argument) the CXSourceRange will be invalid. + * + * \returns one of the CXResult enumerators. + */ +CINDEX_LINKAGE CXResult clang_findReferencesInFile( + CXCursor cursor, CXFile file, CXCursorAndRangeVisitor visitor); + +/** + * Find #import/#include directives in a specific file. + * + * \param TU translation unit containing the file to query. + * + * \param file to search for #import/#include directives. + * + * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for + * each directive found. + * + * \returns one of the CXResult enumerators. + */ +CINDEX_LINKAGE CXResult clang_findIncludesInFile( + CXTranslationUnit TU, CXFile file, CXCursorAndRangeVisitor visitor); + +#if __has_feature(blocks) +typedef enum CXVisitorResult (^CXCursorAndRangeVisitorBlock)(CXCursor, + CXSourceRange); +#else +typedef struct _CXCursorAndRangeVisitorBlock *CXCursorAndRangeVisitorBlock; +#endif + +CINDEX_LINKAGE +CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile, + CXCursorAndRangeVisitorBlock); + +CINDEX_LINKAGE +CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile, + CXCursorAndRangeVisitorBlock); + +/** + * The client's data object that is associated with a CXFile. + */ +typedef void *CXIdxClientFile; + +/** + * The client's data object that is associated with a semantic entity. + */ +typedef void *CXIdxClientEntity; + +/** + * The client's data object that is associated with a semantic container + * of entities. + */ +typedef void *CXIdxClientContainer; + +/** + * The client's data object that is associated with an AST file (PCH + * or module). + */ +typedef void *CXIdxClientASTFile; + +/** + * Source location passed to index callbacks. + */ +typedef struct { + void *ptr_data[2]; + unsigned int_data; +} CXIdxLoc; + +/** + * Data for ppIncludedFile callback. + */ +typedef struct { + /** + * Location of '#' in the \#include/\#import directive. + */ + CXIdxLoc hashLoc; + /** + * Filename as written in the \#include/\#import directive. + */ + const char *filename; + /** + * The actual file that the \#include/\#import directive resolved to. + */ + CXFile file; + int isImport; + int isAngled; + /** + * Non-zero if the directive was automatically turned into a module + * import. + */ + int isModuleImport; +} CXIdxIncludedFileInfo; + +/** + * Data for IndexerCallbacks#importedASTFile. + */ +typedef struct { + /** + * Top level AST file containing the imported PCH, module or submodule. + */ + CXFile file; + /** + * The imported module or NULL if the AST file is a PCH. + */ + CXModule module; + /** + * Location where the file is imported. Applicable only for modules. + */ + CXIdxLoc loc; + /** + * Non-zero if an inclusion directive was automatically turned into + * a module import. Applicable only for modules. + */ + int isImplicit; + +} CXIdxImportedASTFileInfo; + +typedef enum { + CXIdxEntity_Unexposed = 0, + CXIdxEntity_Typedef = 1, + CXIdxEntity_Function = 2, + CXIdxEntity_Variable = 3, + CXIdxEntity_Field = 4, + CXIdxEntity_EnumConstant = 5, + + CXIdxEntity_ObjCClass = 6, + CXIdxEntity_ObjCProtocol = 7, + CXIdxEntity_ObjCCategory = 8, + + CXIdxEntity_ObjCInstanceMethod = 9, + CXIdxEntity_ObjCClassMethod = 10, + CXIdxEntity_ObjCProperty = 11, + CXIdxEntity_ObjCIvar = 12, + + CXIdxEntity_Enum = 13, + CXIdxEntity_Struct = 14, + CXIdxEntity_Union = 15, + + CXIdxEntity_CXXClass = 16, + CXIdxEntity_CXXNamespace = 17, + CXIdxEntity_CXXNamespaceAlias = 18, + CXIdxEntity_CXXStaticVariable = 19, + CXIdxEntity_CXXStaticMethod = 20, + CXIdxEntity_CXXInstanceMethod = 21, + CXIdxEntity_CXXConstructor = 22, + CXIdxEntity_CXXDestructor = 23, + CXIdxEntity_CXXConversionFunction = 24, + CXIdxEntity_CXXTypeAlias = 25, + CXIdxEntity_CXXInterface = 26, + CXIdxEntity_CXXConcept = 27 + +} CXIdxEntityKind; + +typedef enum { + CXIdxEntityLang_None = 0, + CXIdxEntityLang_C = 1, + CXIdxEntityLang_ObjC = 2, + CXIdxEntityLang_CXX = 3, + CXIdxEntityLang_Swift = 4 +} CXIdxEntityLanguage; + +/** + * Extra C++ template information for an entity. This can apply to: + * CXIdxEntity_Function + * CXIdxEntity_CXXClass + * CXIdxEntity_CXXStaticMethod + * CXIdxEntity_CXXInstanceMethod + * CXIdxEntity_CXXConstructor + * CXIdxEntity_CXXConversionFunction + * CXIdxEntity_CXXTypeAlias + */ +typedef enum { + CXIdxEntity_NonTemplate = 0, + CXIdxEntity_Template = 1, + CXIdxEntity_TemplatePartialSpecialization = 2, + CXIdxEntity_TemplateSpecialization = 3 +} CXIdxEntityCXXTemplateKind; + +typedef enum { + CXIdxAttr_Unexposed = 0, + CXIdxAttr_IBAction = 1, + CXIdxAttr_IBOutlet = 2, + CXIdxAttr_IBOutletCollection = 3 +} CXIdxAttrKind; + +typedef struct { + CXIdxAttrKind kind; + CXCursor cursor; + CXIdxLoc loc; +} CXIdxAttrInfo; + +typedef struct { + CXIdxEntityKind kind; + CXIdxEntityCXXTemplateKind templateKind; + CXIdxEntityLanguage lang; + const char *name; + const char *USR; + CXCursor cursor; + const CXIdxAttrInfo *const *attributes; + unsigned numAttributes; +} CXIdxEntityInfo; + +typedef struct { + CXCursor cursor; +} CXIdxContainerInfo; + +typedef struct { + const CXIdxAttrInfo *attrInfo; + const CXIdxEntityInfo *objcClass; + CXCursor classCursor; + CXIdxLoc classLoc; +} CXIdxIBOutletCollectionAttrInfo; + +typedef enum { CXIdxDeclFlag_Skipped = 0x1 } CXIdxDeclInfoFlags; + +typedef struct { + const CXIdxEntityInfo *entityInfo; + CXCursor cursor; + CXIdxLoc loc; + const CXIdxContainerInfo *semanticContainer; + /** + * Generally same as #semanticContainer but can be different in + * cases like out-of-line C++ member functions. + */ + const CXIdxContainerInfo *lexicalContainer; + int isRedeclaration; + int isDefinition; + int isContainer; + const CXIdxContainerInfo *declAsContainer; + /** + * Whether the declaration exists in code or was created implicitly + * by the compiler, e.g. implicit Objective-C methods for properties. + */ + int isImplicit; + const CXIdxAttrInfo *const *attributes; + unsigned numAttributes; + + unsigned flags; + +} CXIdxDeclInfo; + +typedef enum { + CXIdxObjCContainer_ForwardRef = 0, + CXIdxObjCContainer_Interface = 1, + CXIdxObjCContainer_Implementation = 2 +} CXIdxObjCContainerKind; + +typedef struct { + const CXIdxDeclInfo *declInfo; + CXIdxObjCContainerKind kind; +} CXIdxObjCContainerDeclInfo; + +typedef struct { + const CXIdxEntityInfo *base; + CXCursor cursor; + CXIdxLoc loc; +} CXIdxBaseClassInfo; + +typedef struct { + const CXIdxEntityInfo *protocol; + CXCursor cursor; + CXIdxLoc loc; +} CXIdxObjCProtocolRefInfo; + +typedef struct { + const CXIdxObjCProtocolRefInfo *const *protocols; + unsigned numProtocols; +} CXIdxObjCProtocolRefListInfo; + +typedef struct { + const CXIdxObjCContainerDeclInfo *containerInfo; + const CXIdxBaseClassInfo *superInfo; + const CXIdxObjCProtocolRefListInfo *protocols; +} CXIdxObjCInterfaceDeclInfo; + +typedef struct { + const CXIdxObjCContainerDeclInfo *containerInfo; + const CXIdxEntityInfo *objcClass; + CXCursor classCursor; + CXIdxLoc classLoc; + const CXIdxObjCProtocolRefListInfo *protocols; +} CXIdxObjCCategoryDeclInfo; + +typedef struct { + const CXIdxDeclInfo *declInfo; + const CXIdxEntityInfo *getter; + const CXIdxEntityInfo *setter; +} CXIdxObjCPropertyDeclInfo; + +typedef struct { + const CXIdxDeclInfo *declInfo; + const CXIdxBaseClassInfo *const *bases; + unsigned numBases; +} CXIdxCXXClassDeclInfo; + +/** + * Data for IndexerCallbacks#indexEntityReference. + * + * This may be deprecated in a future version as this duplicates + * the \c CXSymbolRole_Implicit bit in \c CXSymbolRole. + */ +typedef enum { + /** + * The entity is referenced directly in user's code. + */ + CXIdxEntityRef_Direct = 1, + /** + * An implicit reference, e.g. a reference of an Objective-C method + * via the dot syntax. + */ + CXIdxEntityRef_Implicit = 2 +} CXIdxEntityRefKind; + +/** + * Roles that are attributed to symbol occurrences. + * + * Internal: this currently mirrors low 9 bits of clang::index::SymbolRole with + * higher bits zeroed. These high bits may be exposed in the future. + */ +typedef enum { + CXSymbolRole_None = 0, + CXSymbolRole_Declaration = 1 << 0, + CXSymbolRole_Definition = 1 << 1, + CXSymbolRole_Reference = 1 << 2, + CXSymbolRole_Read = 1 << 3, + CXSymbolRole_Write = 1 << 4, + CXSymbolRole_Call = 1 << 5, + CXSymbolRole_Dynamic = 1 << 6, + CXSymbolRole_AddressOf = 1 << 7, + CXSymbolRole_Implicit = 1 << 8 +} CXSymbolRole; + +/** + * Data for IndexerCallbacks#indexEntityReference. + */ +typedef struct { + CXIdxEntityRefKind kind; + /** + * Reference cursor. + */ + CXCursor cursor; + CXIdxLoc loc; + /** + * The entity that gets referenced. + */ + const CXIdxEntityInfo *referencedEntity; + /** + * Immediate "parent" of the reference. For example: + * + * \code + * Foo *var; + * \endcode + * + * The parent of reference of type 'Foo' is the variable 'var'. + * For references inside statement bodies of functions/methods, + * the parentEntity will be the function/method. + */ + const CXIdxEntityInfo *parentEntity; + /** + * Lexical container context of the reference. + */ + const CXIdxContainerInfo *container; + /** + * Sets of symbol roles of the reference. + */ + CXSymbolRole role; +} CXIdxEntityRefInfo; + +/** + * A group of callbacks used by #clang_indexSourceFile and + * #clang_indexTranslationUnit. + */ +typedef struct { + /** + * Called periodically to check whether indexing should be aborted. + * Should return 0 to continue, and non-zero to abort. + */ + int (*abortQuery)(CXClientData client_data, void *reserved); + + /** + * Called at the end of indexing; passes the complete diagnostic set. + */ + void (*diagnostic)(CXClientData client_data, CXDiagnosticSet, void *reserved); + + CXIdxClientFile (*enteredMainFile)(CXClientData client_data, CXFile mainFile, + void *reserved); + + /** + * Called when a file gets \#included/\#imported. + */ + CXIdxClientFile (*ppIncludedFile)(CXClientData client_data, + const CXIdxIncludedFileInfo *); + + /** + * Called when a AST file (PCH or module) gets imported. + * + * AST files will not get indexed (there will not be callbacks to index all + * the entities in an AST file). The recommended action is that, if the AST + * file is not already indexed, to initiate a new indexing job specific to + * the AST file. + */ + CXIdxClientASTFile (*importedASTFile)(CXClientData client_data, + const CXIdxImportedASTFileInfo *); + + /** + * Called at the beginning of indexing a translation unit. + */ + CXIdxClientContainer (*startedTranslationUnit)(CXClientData client_data, + void *reserved); + + void (*indexDeclaration)(CXClientData client_data, const CXIdxDeclInfo *); + + /** + * Called to index a reference of an entity. + */ + void (*indexEntityReference)(CXClientData client_data, + const CXIdxEntityRefInfo *); + +} IndexerCallbacks; + +CINDEX_LINKAGE int clang_index_isEntityObjCContainerKind(CXIdxEntityKind); +CINDEX_LINKAGE const CXIdxObjCContainerDeclInfo * +clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxObjCInterfaceDeclInfo * +clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE +const CXIdxObjCCategoryDeclInfo * +clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxObjCProtocolRefListInfo * +clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxObjCPropertyDeclInfo * +clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *); + +CINDEX_LINKAGE const CXIdxIBOutletCollectionAttrInfo * +clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *); + +CINDEX_LINKAGE const CXIdxCXXClassDeclInfo * +clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *); + +/** + * For retrieving a custom CXIdxClientContainer attached to a + * container. + */ +CINDEX_LINKAGE CXIdxClientContainer +clang_index_getClientContainer(const CXIdxContainerInfo *); + +/** + * For setting a custom CXIdxClientContainer attached to a + * container. + */ +CINDEX_LINKAGE void clang_index_setClientContainer(const CXIdxContainerInfo *, + CXIdxClientContainer); + +/** + * For retrieving a custom CXIdxClientEntity attached to an entity. + */ +CINDEX_LINKAGE CXIdxClientEntity +clang_index_getClientEntity(const CXIdxEntityInfo *); + +/** + * For setting a custom CXIdxClientEntity attached to an entity. + */ +CINDEX_LINKAGE void clang_index_setClientEntity(const CXIdxEntityInfo *, + CXIdxClientEntity); + +/** + * An indexing action/session, to be applied to one or multiple + * translation units. + */ +typedef void *CXIndexAction; + +/** + * An indexing action/session, to be applied to one or multiple + * translation units. + * + * \param CIdx The index object with which the index action will be associated. + */ +CINDEX_LINKAGE CXIndexAction clang_IndexAction_create(CXIndex CIdx); + +/** + * Destroy the given index action. + * + * The index action must not be destroyed until all of the translation units + * created within that index action have been destroyed. + */ +CINDEX_LINKAGE void clang_IndexAction_dispose(CXIndexAction); + +typedef enum { + /** + * Used to indicate that no special indexing options are needed. + */ + CXIndexOpt_None = 0x0, + + /** + * Used to indicate that IndexerCallbacks#indexEntityReference should + * be invoked for only one reference of an entity per source file that does + * not also include a declaration/definition of the entity. + */ + CXIndexOpt_SuppressRedundantRefs = 0x1, + + /** + * Function-local symbols should be indexed. If this is not set + * function-local symbols will be ignored. + */ + CXIndexOpt_IndexFunctionLocalSymbols = 0x2, + + /** + * Implicit function/class template instantiations should be indexed. + * If this is not set, implicit instantiations will be ignored. + */ + CXIndexOpt_IndexImplicitTemplateInstantiations = 0x4, + + /** + * Suppress all compiler warnings when parsing for indexing. + */ + CXIndexOpt_SuppressWarnings = 0x8, + + /** + * Skip a function/method body that was already parsed during an + * indexing session associated with a \c CXIndexAction object. + * Bodies in system headers are always skipped. + */ + CXIndexOpt_SkipParsedBodiesInSession = 0x10 + +} CXIndexOptFlags; + +/** + * Index the given source file and the translation unit corresponding + * to that file via callbacks implemented through #IndexerCallbacks. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the invoked callbacks. + * + * \param index_callbacks Pointer to indexing callbacks that the client + * implements. + * + * \param index_callbacks_size Size of #IndexerCallbacks structure that gets + * passed in index_callbacks. + * + * \param index_options A bitmask of options that affects how indexing is + * performed. This should be a bitwise OR of the CXIndexOpt_XXX flags. + * + * \param[out] out_TU pointer to store a \c CXTranslationUnit that can be + * reused after indexing is finished. Set to \c NULL if you do not require it. + * + * \returns 0 on success or if there were errors from which the compiler could + * recover. If there is a failure from which there is no recovery, returns + * a non-zero \c CXErrorCode. + * + * The rest of the parameters are the same as #clang_parseTranslationUnit. + */ +CINDEX_LINKAGE int clang_indexSourceFile( + CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, unsigned index_options, + const char *source_filename, const char *const *command_line_args, + int num_command_line_args, struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options); + +/** + * Same as clang_indexSourceFile but requires a full command line + * for \c command_line_args including argv[0]. This is useful if the standard + * library paths are relative to the binary. + */ +CINDEX_LINKAGE int clang_indexSourceFileFullArgv( + CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, unsigned index_options, + const char *source_filename, const char *const *command_line_args, + int num_command_line_args, struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options); + +/** + * Index the given translation unit via callbacks implemented through + * #IndexerCallbacks. + * + * The order of callback invocations is not guaranteed to be the same as + * when indexing a source file. The high level order will be: + * + * -Preprocessor callbacks invocations + * -Declaration/reference callbacks invocations + * -Diagnostic callback invocations + * + * The parameters are the same as #clang_indexSourceFile. + * + * \returns If there is a failure from which there is no recovery, returns + * non-zero, otherwise returns 0. + */ +CINDEX_LINKAGE int clang_indexTranslationUnit( + CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, unsigned index_options, CXTranslationUnit); + +/** + * Retrieve the CXIdxFile, file, line, column, and offset represented by + * the given CXIdxLoc. + * + * If the location refers into a macro expansion, retrieves the + * location of the macro expansion and if it refers into a macro argument + * retrieves the location of the argument. + */ +CINDEX_LINKAGE void clang_indexLoc_getFileLocation(CXIdxLoc loc, + CXIdxClientFile *indexFile, + CXFile *file, unsigned *line, + unsigned *column, + unsigned *offset); + +/** + * Retrieve the CXSourceLocation represented by the given CXIdxLoc. + */ +CINDEX_LINKAGE +CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc); + +/** + * Visitor invoked for each field found by a traversal. + * + * This visitor function will be invoked for each field found by + * \c clang_Type_visitFields. Its first argument is the cursor being + * visited, its second argument is the client data provided to + * \c clang_Type_visitFields. + * + * The visitor should return one of the \c CXVisitorResult values + * to direct \c clang_Type_visitFields. + */ +typedef enum CXVisitorResult (*CXFieldVisitor)(CXCursor C, + CXClientData client_data); + +/** + * Visit the fields of a particular type. + * + * This function visits all the direct fields of the given cursor, + * invoking the given \p visitor function with the cursors of each + * visited field. The traversal may be ended prematurely, if + * the visitor returns \c CXFieldVisit_Break. + * + * \param T the record type whose field may be visited. + * + * \param visitor the visitor function that will be invoked for each + * field of \p T. + * + * \param client_data pointer data supplied by the client, which will + * be passed to the visitor each time it is invoked. + * + * \returns a non-zero value if the traversal was terminated + * prematurely by the visitor returning \c CXFieldVisit_Break. + */ +CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T, CXFieldVisitor visitor, + CXClientData client_data); + +/** + * Describes the kind of binary operators. + */ +enum CXBinaryOperatorKind { + /** This value describes cursors which are not binary operators. */ + CXBinaryOperator_Invalid, + /** C++ Pointer - to - member operator. */ + CXBinaryOperator_PtrMemD, + /** C++ Pointer - to - member operator. */ + CXBinaryOperator_PtrMemI, + /** Multiplication operator. */ + CXBinaryOperator_Mul, + /** Division operator. */ + CXBinaryOperator_Div, + /** Remainder operator. */ + CXBinaryOperator_Rem, + /** Addition operator. */ + CXBinaryOperator_Add, + /** Subtraction operator. */ + CXBinaryOperator_Sub, + /** Bitwise shift left operator. */ + CXBinaryOperator_Shl, + /** Bitwise shift right operator. */ + CXBinaryOperator_Shr, + /** C++ three-way comparison (spaceship) operator. */ + CXBinaryOperator_Cmp, + /** Less than operator. */ + CXBinaryOperator_LT, + /** Greater than operator. */ + CXBinaryOperator_GT, + /** Less or equal operator. */ + CXBinaryOperator_LE, + /** Greater or equal operator. */ + CXBinaryOperator_GE, + /** Equal operator. */ + CXBinaryOperator_EQ, + /** Not equal operator. */ + CXBinaryOperator_NE, + /** Bitwise AND operator. */ + CXBinaryOperator_And, + /** Bitwise XOR operator. */ + CXBinaryOperator_Xor, + /** Bitwise OR operator. */ + CXBinaryOperator_Or, + /** Logical AND operator. */ + CXBinaryOperator_LAnd, + /** Logical OR operator. */ + CXBinaryOperator_LOr, + /** Assignment operator. */ + CXBinaryOperator_Assign, + /** Multiplication assignment operator. */ + CXBinaryOperator_MulAssign, + /** Division assignment operator. */ + CXBinaryOperator_DivAssign, + /** Remainder assignment operator. */ + CXBinaryOperator_RemAssign, + /** Addition assignment operator. */ + CXBinaryOperator_AddAssign, + /** Subtraction assignment operator. */ + CXBinaryOperator_SubAssign, + /** Bitwise shift left assignment operator. */ + CXBinaryOperator_ShlAssign, + /** Bitwise shift right assignment operator. */ + CXBinaryOperator_ShrAssign, + /** Bitwise AND assignment operator. */ + CXBinaryOperator_AndAssign, + /** Bitwise XOR assignment operator. */ + CXBinaryOperator_XorAssign, + /** Bitwise OR assignment operator. */ + CXBinaryOperator_OrAssign, + /** Comma operator. */ + CXBinaryOperator_Comma +}; + +/** + * Retrieve the spelling of a given CXBinaryOperatorKind. + */ +CINDEX_LINKAGE CXString +clang_getBinaryOperatorKindSpelling(enum CXBinaryOperatorKind kind); + +/** + * Retrieve the binary operator kind of this cursor. + * + * If this cursor is not a binary operator then returns Invalid. + */ +CINDEX_LINKAGE enum CXBinaryOperatorKind +clang_getCursorBinaryOperatorKind(CXCursor cursor); + +/** + * Describes the kind of unary operators. + */ +enum CXUnaryOperatorKind { + /** This value describes cursors which are not unary operators. */ + CXUnaryOperator_Invalid, + /** Postfix increment operator. */ + CXUnaryOperator_PostInc, + /** Postfix decrement operator. */ + CXUnaryOperator_PostDec, + /** Prefix increment operator. */ + CXUnaryOperator_PreInc, + /** Prefix decrement operator. */ + CXUnaryOperator_PreDec, + /** Address of operator. */ + CXUnaryOperator_AddrOf, + /** Dereference operator. */ + CXUnaryOperator_Deref, + /** Plus operator. */ + CXUnaryOperator_Plus, + /** Minus operator. */ + CXUnaryOperator_Minus, + /** Not operator. */ + CXUnaryOperator_Not, + /** LNot operator. */ + CXUnaryOperator_LNot, + /** "__real expr" operator. */ + CXUnaryOperator_Real, + /** "__imag expr" operator. */ + CXUnaryOperator_Imag, + /** __extension__ marker operator. */ + CXUnaryOperator_Extension, + /** C++ co_await operator. */ + CXUnaryOperator_Coawait +}; + +/** + * Retrieve the spelling of a given CXUnaryOperatorKind. + */ +CINDEX_LINKAGE CXString +clang_getUnaryOperatorKindSpelling(enum CXUnaryOperatorKind kind); + +/** + * Retrieve the unary operator kind of this cursor. + * + * If this cursor is not a unary operator then returns Invalid. + */ +CINDEX_LINKAGE enum CXUnaryOperatorKind +clang_getCursorUnaryOperatorKind(CXCursor cursor); + +/** + * @} + */ + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/Platform.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Platform.h new file mode 100644 index 0000000000..67c1fff8ff --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Platform.h @@ -0,0 +1,53 @@ +/*===-- clang-c/Platform.h - C Index platform decls -------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides platform specific macros (dllimport, deprecated, ...) *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_PLATFORM_H +#define LLVM_CLANG_C_PLATFORM_H + +#include "clang-c/ExternC.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/* Windows DLL import/export. */ +#ifndef CINDEX_NO_EXPORTS + #define CINDEX_EXPORTS +#endif +#ifdef _WIN32 + #ifdef CINDEX_EXPORTS + #ifdef _CINDEX_LIB_ + #define CINDEX_LINKAGE __declspec(dllexport) + #else + #define CINDEX_LINKAGE __declspec(dllimport) + #endif + #endif +#elif defined(CINDEX_EXPORTS) && defined(__GNUC__) + #define CINDEX_LINKAGE __attribute__((visibility("default"))) +#endif + +#ifndef CINDEX_LINKAGE + #define CINDEX_LINKAGE +#endif + +#ifdef __GNUC__ + #define CINDEX_DEPRECATED __attribute__((deprecated)) +#else + #ifdef _MSC_VER + #define CINDEX_DEPRECATED __declspec(deprecated) + #else + #define CINDEX_DEPRECATED + #endif +#endif + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/include/clang-c/Rewrite.h b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Rewrite.h new file mode 100644 index 0000000000..ce1b05594b --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/include/clang-c/Rewrite.h @@ -0,0 +1,63 @@ +/*===-- clang-c/Rewrite.h - C CXRewriter --------------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_REWRITE_H +#define LLVM_CLANG_C_REWRITE_H + +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Index.h" +#include "clang-c/Platform.h" + +LLVM_CLANG_C_EXTERN_C_BEGIN + +typedef void *CXRewriter; + +/** + * Create CXRewriter. + */ +CINDEX_LINKAGE CXRewriter clang_CXRewriter_create(CXTranslationUnit TU); + +/** + * Insert the specified string at the specified location in the original buffer. + */ +CINDEX_LINKAGE void clang_CXRewriter_insertTextBefore(CXRewriter Rew, CXSourceLocation Loc, + const char *Insert); + +/** + * Replace the specified range of characters in the input with the specified + * replacement. + */ +CINDEX_LINKAGE void clang_CXRewriter_replaceText(CXRewriter Rew, CXSourceRange ToBeReplaced, + const char *Replacement); + +/** + * Remove the specified range. + */ +CINDEX_LINKAGE void clang_CXRewriter_removeText(CXRewriter Rew, CXSourceRange ToBeRemoved); + +/** + * Save all changed files to disk. + * Returns 1 if any files were not saved successfully, returns 0 otherwise. + */ +CINDEX_LINKAGE int clang_CXRewriter_overwriteChangedFiles(CXRewriter Rew); + +/** + * Write out rewritten version of the main file to stdout. + */ +CINDEX_LINKAGE void clang_CXRewriter_writeMainFileToStdOut(CXRewriter Rew); + +/** + * Free the given CXRewriter. + */ +CINDEX_LINKAGE void clang_CXRewriter_dispose(CXRewriter Rew); + +LLVM_CLANG_C_EXTERN_C_END + +#endif diff --git a/pkgs/ffigenpad/third_party/libclang/libclang.exports b/pkgs/ffigenpad/third_party/libclang/libclang.exports new file mode 100644 index 0000000000..da50f74474 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/libclang.exports @@ -0,0 +1,73 @@ +_clang_createIndex +_clang_disposeIndex +_clang_parseTranslationUnit +_clang_disposeTranslationUnit +_clang_getNumDiagnostics +_clang_getDiagnostic +_clang_getDiagnosticSeverity +_clang_disposeDiagnostic +_clang_EvalResult_getKind +_clang_EvalResult_getAsLongLong +_clang_EvalResult_getAsDouble +_clang_EvalResult_getAsStr +_clang_EvalResult_dispose +_clang_getCString_wrap +_clang_disposeString_wrap +_clang_getClangVersion_wrap +_clang_getCursorKind_wrap +_clang_getCursorDefinition_wrap +_clang_getCursorKindSpelling_wrap +_clang_getCursorType_wrap +_clang_getTypeSpelling_wrap +_clang_getTypeKindSpelling_wrap +_clang_getResultType_wrap +_clang_getPointeeType_wrap +_clang_getCanonicalType_wrap +_clang_Type_getModifiedType_wrap +_clang_Type_getNullability_wrap +_clang_Type_getNamedType_wrap +_clang_Type_getAlignOf_wrap +_clang_getTypeDeclaration_wrap +_clang_getTypedefName_wrap +_clang_getTypedefDeclUnderlyingType_wrap +_clang_getCursorSpelling_wrap +_clang_getCursorUSR_wrap +_clang_getTranslationUnitCursor_wrap +_clang_formatDiagnostic_wrap +_clang_visitChildren_wrap +_clang_getArgType_wrap +_clang_getNumArgTypes_wrap +_clang_getEnumConstantDeclValue_wrap +_clang_equalRanges_wrap +_clang_Cursor_Evaluate_wrap +_clang_Cursor_getArgument_wrap +_clang_Cursor_getNumArguments_wrap +_clang_Cursor_getCommentRange_wrap +_clang_Cursor_getRawCommentText_wrap +_clang_Cursor_getBriefCommentText_wrap +_clang_Cursor_getStorageClass_wrap +_clang_getFieldDeclBitWidth_wrap +_clang_Cursor_hasAttrs_wrap +_clang_Cursor_isFunctionInlined_wrap +_clang_Cursor_isAnonymous_wrap +_clang_Cursor_isAnonymousRecordDecl_wrap +_clang_Cursor_isNull_wrap +_clang_Cursor_isMacroFunctionLike_wrap +_clang_Cursor_isMacroBuiltin_wrap +_clang_Cursor_getObjCPropertyAttributes_wrap +_clang_Cursor_isObjCOptional_wrap +_clang_Cursor_getObjCPropertyGetterName_wrap +_clang_Cursor_getObjCPropertySetterName_wrap +_clang_getCursorResultType_wrap +_clang_isFunctionTypeVariadic_wrap +_clang_getCursorLocation_wrap +_clang_getEnumDeclIntegerType_wrap +_clang_getFileLocation_wrap +_clang_getFileName_wrap +_clang_getNumElements_wrap +_clang_getArrayElementType_wrap +_clang_isConstQualifiedType_wrap +_clang_Location_isInSystemHeader_wrap +_getCXTypeKind +_malloc +_free \ No newline at end of file diff --git a/pkgs/ffigenpad/third_party/libclang/license.txt b/pkgs/ffigenpad/third_party/libclang/license.txt new file mode 100644 index 0000000000..eeea4338d5 --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/license.txt @@ -0,0 +1,222 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + + +Files generated from libclang source code are +- lib/src/header_parser/clang_bindings/clang_bindings.dart diff --git a/pkgs/ffigenpad/third_party/libclang/wrapper.c b/pkgs/ffigenpad/third_party/libclang/wrapper.c new file mode 100644 index 0000000000..bddba41dad --- /dev/null +++ b/pkgs/ffigenpad/third_party/libclang/wrapper.c @@ -0,0 +1,300 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Heavily adapted from +// https://github.com/dart-archive/ffigen/blob/46ddca94b6f623590fe9f2ad7202cef250e554e2/tool/wrapped_libclang/wrapper.c + +#include "clang-c/Index.h" +#include +#include +#include + +// utility. +#define aloc(T) ((T *)malloc(sizeof(T))) +CXCursor *ptrToCXCursor(CXCursor t) { + CXCursor *c = aloc(CXCursor); + *c = t; + return c; +} +CXString *ptrToCXString(CXString t) { + CXString *c = aloc(CXString); + *c = t; + return c; +} +CXType *ptrToCXType(CXType t) { + CXType *c = aloc(CXType); + *c = t; + return c; +} +CXSourceLocation *ptrToCXSourceLocation(CXSourceLocation t) { + CXSourceLocation *c = aloc(CXSourceLocation); + *c = t; + return c; +} +CXSourceRange *ptrToCXSourceRange(CXSourceRange t) { + CXSourceRange *c = aloc(CXSourceRange); + *c = t; + return c; +} + +// START ===== WRAPPER FUNCTIONS ===================== + +CXString *clang_getClangVersion_wrap() { + return ptrToCXString(clang_getClangVersion()); +} + +const char *clang_getCString_wrap(CXString *string) { + const char *a = clang_getCString(*string); + + return a; +} + +void clang_disposeString_wrap(CXString *string) { + clang_disposeString(*string); + free(string); + return; +} + +enum CXCursorKind clang_getCursorKind_wrap(CXCursor *cursor) { + return clang_getCursorKind(*cursor); +} + +CXCursor *clang_getCursorDefinition_wrap(CXCursor *cursor) { + return ptrToCXCursor(clang_getCursorDefinition(*cursor)); +} + +CXString *clang_getCursorKindSpelling_wrap(enum CXCursorKind kind) { + return ptrToCXString(clang_getCursorKindSpelling(kind)); +} + +CXType *clang_getCursorType_wrap(CXCursor *cursor) { + return ptrToCXType(clang_getCursorType(*cursor)); +} + +CXString *clang_getTypeSpelling_wrap(CXType *type) { + return ptrToCXString(clang_getTypeSpelling(*type)); +} + +CXString *clang_getTypeKindSpelling_wrap(enum CXTypeKind typeKind) { + return ptrToCXString(clang_getTypeKindSpelling(typeKind)); +} + +CXType *clang_getResultType_wrap(CXType *functionType) { + return ptrToCXType(clang_getResultType(*functionType)); +} + +CXType *clang_getPointeeType_wrap(CXType *pointerType) { + return ptrToCXType(clang_getPointeeType(*pointerType)); +} + +CXType *clang_getCanonicalType_wrap(CXType *typerefType) { + return ptrToCXType(clang_getCanonicalType(*typerefType)); +} + +enum CXTypeKind getCXTypeKind(CXType *cxtype) { + return cxtype->kind; +} + +CXType *clang_Type_getModifiedType_wrap(CXType *type) { + return ptrToCXType(clang_Type_getModifiedType(*type)); +} + +enum CXTypeNullabilityKind clang_Type_getNullability_wrap(CXType *type) { + return clang_Type_getNullability(*type); +} + +CXType *clang_Type_getNamedType_wrap(CXType *elaboratedType) { + return ptrToCXType(clang_Type_getNamedType(*elaboratedType)); +} + +long long clang_Type_getAlignOf_wrap(CXType *cxtype) { + return clang_Type_getAlignOf(*cxtype); +} + +CXCursor *clang_getTypeDeclaration_wrap(CXType *cxtype) { + return ptrToCXCursor(clang_getTypeDeclaration(*cxtype)); +} + +CXString *clang_getTypedefName_wrap(CXType *cxtype) { + return ptrToCXString(clang_getTypedefName(*cxtype)); +} + +CXType *clang_getTypedefDeclUnderlyingType_wrap(CXCursor *cxcursor) { + return ptrToCXType(clang_getTypedefDeclUnderlyingType(*cxcursor)); +} + +/** The name of parameter, struct, typedef. */ +CXString *clang_getCursorSpelling_wrap(CXCursor *cursor) { + return ptrToCXString(clang_getCursorSpelling(*cursor)); +} + +CXString *clang_getCursorUSR_wrap(CXCursor *cursor) { + return ptrToCXString(clang_getCursorUSR(*cursor)); +} + +CXCursor *clang_getTranslationUnitCursor_wrap(CXTranslationUnit tu) { + return ptrToCXCursor(clang_getTranslationUnitCursor(tu)); +} + +CXString *clang_formatDiagnostic_wrap(CXDiagnostic diag, int opts) { + return ptrToCXString(clang_formatDiagnostic(diag, opts)); +} + +// Alternative typedef for [CXCursorVisitor] using pointer for passing cursor +// and parent instead of passing by value +typedef enum CXChildVisitResult (*ModifiedCXCursorVisitor)( + CXCursor *cursor, CXCursor *parent, CXClientData client_data); + +// Do not write binding for this function. +// used by [clang_visitChildren_wrap]. +enum CXChildVisitResult _visitorwrap(CXCursor cursor, CXCursor parent, + CXClientData clientData) { + uintptr_t loc = *((uintptr_t *) clientData); + ModifiedCXCursorVisitor visitor = (ModifiedCXCursorVisitor) loc; + return visitor(&cursor, &parent, NULL); +} +/** Visitor is a function pointer with parameters having pointers to cxcursor + * instead of cxcursor by default. */ +unsigned clang_visitChildren_wrap(CXCursor *parent, uintptr_t _modifiedVisitor) { + return clang_visitChildren(*parent, _visitorwrap, &_modifiedVisitor); +} + +int clang_getNumArgTypes_wrap(CXType *cxtype) { + return clang_getNumArgTypes(*cxtype); +} + +CXType *clang_getArgType_wrap(CXType *cxtype, unsigned i) { + return ptrToCXType(clang_getArgType(*cxtype, i)); +} + +long long clang_getEnumConstantDeclValue_wrap(CXCursor *cursor) { + return clang_getEnumConstantDeclValue(*cursor); +} + +/** Returns non-zero if the ranges are the same, zero if they differ. */ +unsigned clang_equalRanges_wrap(CXSourceRange *c1, CXSourceRange *c2) { + return clang_equalRanges(*c1, *c2); +} + +CXEvalResult clang_Cursor_Evaluate_wrap(CXCursor *cursor) { + return clang_Cursor_Evaluate(*cursor); +} + +CXCursor *clang_Cursor_getArgument_wrap(CXCursor *cursor, unsigned i) { + return ptrToCXCursor(clang_Cursor_getArgument(*cursor, i)); +} + +int clang_Cursor_getNumArguments_wrap(CXCursor *cursor) { + return clang_Cursor_getNumArguments(*cursor); +} + +/** Returns the comment range. */ +CXSourceRange *clang_Cursor_getCommentRange_wrap(CXCursor *cursor) { + return ptrToCXSourceRange(clang_Cursor_getCommentRange(*cursor)); +} + +/** Returns the raw comment. */ +CXString *clang_Cursor_getRawCommentText_wrap(CXCursor *cursor) { + return ptrToCXString(clang_Cursor_getRawCommentText(*cursor)); +} + +/** Returns the first paragraph of doxygen doc comment. */ +CXString *clang_Cursor_getBriefCommentText_wrap(CXCursor *cursor) { + return ptrToCXString(clang_Cursor_getBriefCommentText(*cursor)); +} + +enum CX_StorageClass clang_Cursor_getStorageClass_wrap(CXCursor *cursor) { + return clang_Cursor_getStorageClass(*cursor); +} + +int clang_getFieldDeclBitWidth_wrap(CXCursor *C) { + return clang_getFieldDeclBitWidth(*C); +} + +unsigned clang_Cursor_hasAttrs_wrap(CXCursor *C) { + return clang_Cursor_hasAttrs(*C); +} + +unsigned clang_Cursor_isFunctionInlined_wrap(CXCursor *cursor) { + return clang_Cursor_isFunctionInlined(*cursor); +} + +unsigned clang_Cursor_isAnonymous_wrap(CXCursor *cursor) { + return clang_Cursor_isAnonymous(*cursor); +} + +unsigned clang_Cursor_isAnonymousRecordDecl_wrap(CXCursor *cursor) { + return clang_Cursor_isAnonymousRecordDecl(*cursor); +} + +int clang_Cursor_isNull_wrap(CXCursor *cursor) { + return clang_Cursor_isNull(*cursor); +} + +unsigned clang_Cursor_isMacroFunctionLike_wrap(CXCursor *cursor) { + return clang_Cursor_isMacroFunctionLike(*cursor); +} + +unsigned clang_Cursor_isMacroBuiltin_wrap(CXCursor *cursor) { + return clang_Cursor_isMacroBuiltin(*cursor); +} + +unsigned clang_Cursor_getObjCPropertyAttributes_wrap(CXCursor *cursor, unsigned reserved) { + return clang_Cursor_getObjCPropertyAttributes(*cursor, reserved); +} + +unsigned clang_Cursor_isObjCOptional_wrap(CXCursor *cursor) { + return clang_Cursor_isObjCOptional(*cursor); +} + +CXString *clang_Cursor_getObjCPropertyGetterName_wrap(CXCursor *C) { + return ptrToCXString(clang_Cursor_getObjCPropertyGetterName(*C)); +} + +CXString *clang_Cursor_getObjCPropertySetterName_wrap(CXCursor *C) { + return ptrToCXString(clang_Cursor_getObjCPropertySetterName(*C)); +} + +CXType *clang_getCursorResultType_wrap(CXCursor *C) { + return ptrToCXType(clang_getCursorResultType(*C)); +} + +unsigned clang_isFunctionTypeVariadic_wrap(CXType *type) { + return clang_isFunctionTypeVariadic(*type); +} + +CXSourceLocation *clang_getCursorLocation_wrap(CXCursor *cursor) { + return ptrToCXSourceLocation(clang_getCursorLocation(*cursor)); +} + +CXType *clang_getEnumDeclIntegerType_wrap(CXCursor *cursor) { + return ptrToCXType(clang_getEnumDeclIntegerType(*cursor)); +} + +void clang_getFileLocation_wrap(CXSourceLocation *location, CXFile *file, + unsigned *line, unsigned *column, + unsigned *offset) { + return clang_getFileLocation(*location, file, line, column, offset); +} + +CXString *clang_getFileName_wrap(CXFile SFile) { + return ptrToCXString(clang_getFileName(SFile)); +} + +unsigned long long clang_getNumElements_wrap(CXType *cxtype) { + return clang_getNumElements(*cxtype); +} + +CXType *clang_getArrayElementType_wrap(CXType *cxtype) { + return ptrToCXType(clang_getArrayElementType(*cxtype)); +} + +unsigned clang_isConstQualifiedType_wrap(CXType *cxtype) { + return clang_isConstQualifiedType(*cxtype); +} + +int clang_Location_isInSystemHeader_wrap(CXSourceLocation *location) { + return clang_Location_isInSystemHeader(*location); +} +// END ===== WRAPPER FUNCTIONS ===================== diff --git a/pkgs/ffigenpad/tool/build_libclang.dart b/pkgs/ffigenpad/tool/build_libclang.dart new file mode 100644 index 0000000000..f5e9f9d7d2 --- /dev/null +++ b/pkgs/ffigenpad/tool/build_libclang.dart @@ -0,0 +1,136 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// cd to project's root, and run - +// dart run tool/build_libclang.dart + +import 'dart:io'; +import 'package:dart_style/dart_style.dart'; +import 'package:path/path.dart' as p; +import 'package:yaml/yaml.dart'; + +final _formatter = DartFormatter(); + +/// Used to mock the Clang class in ffigen. +/// Generates `lib/src/header_parser/clang_bindings/clang_wrapper.dart`. +void _generateClangClassWrapper(List exportedFunctions) { + final wrapperFunctions = exportedFunctions.map((func) { + final funcAlias = func.replaceFirst(RegExp(r'_wrap'), ''); + return 'final $funcAlias = c.$func;'; + }).join('\n'); + + final output = """ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// AUTO GENERATED FILE, DO NOT EDIT. +// ignore_for_file: camel_case_types, non_constant_identifier_names + +import 'clang_bindings.dart' as c; + +class Clang { +$wrapperFunctions +} +"""; + + File(p.joinAll([ + p.dirname(Platform.script.path), + '..', + 'lib', + 'src', + 'header_parser', + 'clang_bindings', + 'clang_wrapper.dart' + ])).writeAsStringSync(_formatter.format(output)); +} + +void _generateClangExports(String filePath, List exportedFunctions) { + // export malloc and free additionally to use to do memory + // management in ffigenpad + final functions = [...exportedFunctions, 'malloc', 'free'] + .map((func) => '_$func') + .join('\n'); + File(filePath).writeAsStringSync(functions); +} + +void _checkEmscriptenVersion() { + final process = Process.runSync('emcc', ['--version']); + final versionExp = RegExp(r'\d+.\d+.\d+'); + final version = versionExp.stringMatch(process.stdout.toString()); + if (version == null) { + throw Exception('Failed to extract emscripten version.'); + } + final versionList = version.split('.').map(int.parse).toList(growable: false); + if (!(versionList[0] > 3 || versionList[1] > 1 || versionList[2] > 60)) { + throw Exception('Upgrade to atleast v3.1.61 of emscripten to proceed.'); + } + print('Acceptable emscripten version: $version'); +} + +void main(List args) async { + // Load the ffigen config for libclang to extract included functions. + final configYaml = await File(p.join( + p.dirname(Platform.script.path), + 'libclang_config.yaml', + )).readAsString(); + final config = loadYaml(configYaml) as YamlMap; + + // Get the list of functions to be exported from libclang. + final exportedFunctions = + // ignore: avoid_dynamic_calls + List.from(config['functions']['include'] as YamlList); + + final libclangDir = p.joinAll( + [p.dirname(Platform.script.path), '..', 'third_party', 'libclang'], + ); + + print('Writing third_party/libclang/libclang.exports'); + _generateClangExports( + p.join(libclangDir, 'libclang.exports'), + exportedFunctions, + ); + + print('Writing lib/src/header_parser/clang_wrapper.dart'); + _generateClangClassWrapper(exportedFunctions); + + print('Checking emscripten version'); + _checkEmscriptenVersion(); + + print('Building bin/libclang.wasm'); + final archiveFiles = + await Directory(p.join(libclangDir, 'llvm-project', 'lib')) + .list(recursive: false) + .map((file) => p.relative(file.path, from: libclangDir)) + .where((filepath) => filepath.endsWith('.a')) + .toList(); + + final result = await Process.run( + 'emcc', + [ + ...archiveFiles, + 'wrapper.c', + '-I./llvm-project/include', + '-o', + '../../bin/libclang.mjs', + '--no-entry', + '-sALLOW_MEMORY_GROWTH', + '-sALLOW_TABLE_GROWTH', + '-sWASM_BIGINT', + '-sENVIRONMENT=web,worker', + '--embed-file', + './llvm-project/lib/clang@/lib/clang', + '-sEXPORTED_FUNCTIONS=@libclang.exports', + '-sFS_DEBUG', + // ignore: lines_longer_than_80_chars + '-sEXPORTED_RUNTIME_METHODS=FS,wasmExports,wasmMemory,addFunction,removeFunction', + // used for production builds + if (args.contains('--optimize')) ...['-O3', '-lexports.js'] + ], + workingDirectory: libclangDir, + runInShell: true, + ); + stdout.write(result.stdout); + stderr.write(result.stderr); +} diff --git a/pkgs/ffigenpad/tool/libclang_config.yaml b/pkgs/ffigenpad/tool/libclang_config.yaml new file mode 100644 index 0000000000..7417f5c70e --- /dev/null +++ b/pkgs/ffigenpad/tool/libclang_config.yaml @@ -0,0 +1,174 @@ +# Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# Config file for generating the libclang.wasm bindings used by ffigenpad. + +# ===================== GENERATING BINDINGS ===================== +# cd to project's root, and run - +# dart run ffigen --config tool/libclang_config.yaml +# =============================================================== + +# yaml-language-server: $schema=../../ffigen/ffigen.schema.json + +name: Clang +description: Holds bindings to libclang.wasm used by ffigenpad +output: "../lib/src/header_parser/clang_bindings/clang_bindings.dart" +ffi-native: + assetId: libclang +compiler-opts: + - "-Ithird_party/libclang/include" + - "-I/usr/lib/clang/17/include" +headers: + entry-points: + - "../third_party/libclang/wrapper.c" +preamble: | + // Part of the LLVM Project, under the Apache License v2.0 with LLVM + // Exceptions. + // See https://llvm.org/LICENSE.txt for license information. + // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + // ignore_for_file: camel_case_types, non_constant_identifier_names + +exclude-all-by-default: true + +unions: + dependency-only: opaque + +typedefs: + include: + - CXIndex + - CXTranslationUnit + - CXDiagnostic + - CXClientData + - CXEvalResult + - CXFile + +structs: + dependency-only: opaque + +silence-enum-warning: true +enums: + include: + - CXChildVisitResult + - CXCursorKind + - CXTypeKind + - CXDiagnosticDisplayOptions + - CXDiagnosticSeverity + - CXTranslationUnit_Flags + - CXEvalResultKind + - CXObjCPropertyAttrKind + - CXTypeNullabilityKind + - CXTypeLayoutError + - CX_StorageClass + as-int: + include: + - CXChildVisitResult + - CXCursorKind + - CXTypeKind + - CXDiagnosticDisplayOptions + - CXDiagnosticSeverity + - CXTranslationUnit_Flags + - CXEvalResultKind + - CXObjCPropertyAttrKind + - CXTypeNullabilityKind + - CXTypeLayoutError + - CX_StorageClass + +functions: + include: + - clang_createIndex + - clang_disposeIndex + - clang_parseTranslationUnit + - clang_disposeTranslationUnit + - clang_getNumDiagnostics + - clang_getDiagnostic + - clang_getDiagnosticSeverity + - clang_disposeDiagnostic + - clang_EvalResult_getKind + - clang_EvalResult_getAsLongLong + - clang_EvalResult_getAsDouble + - clang_EvalResult_getAsStr + - clang_EvalResult_dispose + - clang_getCString_wrap + - clang_disposeString_wrap + - clang_getClangVersion_wrap + - clang_getCursorKind_wrap + - clang_getCursorDefinition_wrap + - clang_getCursorKindSpelling_wrap + - clang_getCursorType_wrap + - clang_getTypeSpelling_wrap + - clang_getTypeKindSpelling_wrap + - clang_getResultType_wrap + - clang_getPointeeType_wrap + - clang_getCanonicalType_wrap + - clang_Type_getModifiedType_wrap + - clang_Type_getNullability_wrap + - clang_Type_getNamedType_wrap + - clang_Type_getAlignOf_wrap + - clang_getTypeDeclaration_wrap + - clang_getTypedefName_wrap + - clang_getTypedefDeclUnderlyingType_wrap + - clang_getCursorSpelling_wrap + - clang_getCursorUSR_wrap + - clang_getTranslationUnitCursor_wrap + - clang_formatDiagnostic_wrap + - clang_visitChildren_wrap + - clang_getArgType_wrap + - clang_getNumArgTypes_wrap + - clang_getEnumConstantDeclValue_wrap + - clang_equalRanges_wrap + - clang_Cursor_Evaluate_wrap + - clang_Cursor_getArgument_wrap + - clang_Cursor_getNumArguments_wrap + - clang_Cursor_getCommentRange_wrap + - clang_Cursor_getRawCommentText_wrap + - clang_Cursor_getBriefCommentText_wrap + - clang_Cursor_getStorageClass_wrap + - clang_getFieldDeclBitWidth_wrap + - clang_Cursor_hasAttrs_wrap + - clang_Cursor_isFunctionInlined_wrap + - clang_Cursor_isAnonymous_wrap + - clang_Cursor_isAnonymousRecordDecl_wrap + - clang_Cursor_isNull_wrap + - clang_Cursor_isMacroFunctionLike_wrap + - clang_Cursor_isMacroBuiltin_wrap + - clang_Cursor_getObjCPropertyAttributes_wrap + - clang_Cursor_isObjCOptional_wrap + - clang_Cursor_getObjCPropertyGetterName_wrap + - clang_Cursor_getObjCPropertySetterName_wrap + - clang_getCursorResultType_wrap + - clang_isFunctionTypeVariadic_wrap + - clang_getCursorLocation_wrap + - clang_getEnumDeclIntegerType_wrap + - clang_getFileLocation_wrap + - clang_getFileName_wrap + - clang_getNumElements_wrap + - clang_getArrayElementType_wrap + - clang_isConstQualifiedType_wrap + - clang_Location_isInSystemHeader_wrap + # Helper functions + - getCXTypeKind + +type-map: + "native-types": + "char": + "lib": "ffi" + "c-type": "Uint8" + "dart-type": "int" + "unsigned int": + "lib": "ffi" + "c-type": "Uint32" + "dart-type": "int" + "int": + "lib": "ffi" + "c-type": "Int32" + "dart-type": "int" + "long long": + "lib": "ffi" + "c-type": "Int64" + "dart-type": "int" + "unsigned long long": + "lib": "ffi" + "c-type": "Uint64" + "dart-type": "int" diff --git a/pkgs/ffigenpad/tool/setup.dart b/pkgs/ffigenpad/tool/setup.dart new file mode 100644 index 0000000000..f73de4230c --- /dev/null +++ b/pkgs/ffigenpad/tool/setup.dart @@ -0,0 +1,63 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Downloads required files needed to build ffigenpad + +import 'dart:io'; +import 'package:path/path.dart' as p; + +const llvmCompiledRelease = + 'https://github.com/TheComputerM/libclang-wasm/releases/download/v0/llvm-build.tar.gz'; + +Future main(List args) async { + final libclangDir = p.joinAll( + [p.dirname(Platform.script.path), '..', 'third_party', 'libclang'], + ); + final llvmDir = p.join(libclangDir, 'llvm-project'); + + if (args.contains('-f') && await Directory(llvmDir).exists()) { + await Directory(llvmDir).delete(recursive: true); + } + + if (await Directory(llvmDir).exists()) { + print('Compiled LLVM archives already exist.'); + print('Use `-f` to forcefully download archives.'); + return; + } + print('Downloading compiled LLVM archives'); + + // Download .tar.gz file + + final tempFileName = 'llvm-build.tar.gz'; + final tempFile = File(p.join(libclangDir, tempFileName)); + + final httpClient = HttpClient(); + final request = await httpClient.getUrl(Uri.parse(llvmCompiledRelease)); + final response = await request.close(); + final sink = tempFile.openWrite(); + await response.pipe(sink); + await sink.flush(); + await sink.close(); + httpClient.close(); + + print('Extracting LLVM archives to $llvmDir'); + + // Extract file to Config.llvmDir + + await Directory(llvmDir).create(recursive: true); + final result = await Process.run( + 'tar', + ['-xzf', tempFileName, '-C', llvmDir], + workingDirectory: libclangDir, + ); + if (result.exitCode >= 0) { + print('Archive files extracted successfully.'); + } else { + print('Error: ${result.stderr}'); + return; + } + + // remove temp .tar.gz file + await tempFile.delete(); +} diff --git a/pkgs/ffigenpad/web/.gitignore b/pkgs/ffigenpad/web/.gitignore new file mode 100644 index 0000000000..fa147c3e81 --- /dev/null +++ b/pkgs/ffigenpad/web/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +## Panda +styled-system +styled-system-studio \ No newline at end of file diff --git a/pkgs/ffigenpad/web/README.md b/pkgs/ffigenpad/web/README.md new file mode 100644 index 0000000000..d96e025b9e --- /dev/null +++ b/pkgs/ffigenpad/web/README.md @@ -0,0 +1,19 @@ +# FFIgenPad Web Interface + +## Setup + +Make sure you build *libclang.wasm* and *ffigenpad.wasm* and they are present in `/bin`. + +```bash +$ pnpm install +``` + +You can then run the dev server with the following command, any changes you make to the website while dev mode is active will be hot-reloaded to the preview. + +```bash +$ pnpm dev +``` + +## Developing + +FFIgenPad's online interface uses the [SolidJS](https://www.solidjs.com/) framework, [codemirror](https://codemirror.net/) for the code editors and [park-ui](https://park-ui.com/) for the UI components. diff --git a/pkgs/ffigenpad/web/index.html b/pkgs/ffigenpad/web/index.html new file mode 100644 index 0000000000..b6eed543c0 --- /dev/null +++ b/pkgs/ffigenpad/web/index.html @@ -0,0 +1,13 @@ + + + + + + + FFIgenPad + + +
+ + + diff --git a/pkgs/ffigenpad/web/package.json b/pkgs/ffigenpad/web/package.json new file mode 100644 index 0000000000..902f14a525 --- /dev/null +++ b/pkgs/ffigenpad/web/package.json @@ -0,0 +1,39 @@ +{ + "name": "web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "prepare": "panda codegen", + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@ark-ui/solid": "^3.7.0", + "@codemirror/lang-cpp": "^6.0.2", + "@codemirror/lang-yaml": "^6.1.1", + "@codemirror/language": "^6.10.2", + "@codemirror/legacy-modes": "^6.4.1", + "@codemirror/state": "^6.4.1", + "@codemirror/theme-one-dark": "^6.1.2", + "@fontsource-variable/reddit-mono": "^5.0.4", + "codemirror": "^6.0.1", + "pathe": "^1.1.2", + "solid-icons": "^1.1.0", + "solid-js": "^1.8.21" + }, + "devDependencies": { + "@babel/types": "^7.25.6", + "@pandacss/dev": "^0.45.1", + "@park-ui/panda-preset": "^0.42.0", + "@types/node": "^22.4.0", + "typescript": "^5.5.4", + "vite": "^5.4.1", + "vite-plugin-solid": "^2.10.2", + "vite-tsconfig-paths": "^5.0.1" + }, + "engines": { + "node": ">=20.17.0" + } +} diff --git a/pkgs/ffigenpad/web/panda.config.ts b/pkgs/ffigenpad/web/panda.config.ts new file mode 100644 index 0000000000..a025d0eed4 --- /dev/null +++ b/pkgs/ffigenpad/web/panda.config.ts @@ -0,0 +1,45 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { defineConfig } from "@pandacss/dev"; +import { createPreset } from "@park-ui/panda-preset"; + +export default defineConfig({ + preflight: true, + presets: [ + "@pandacss/preset-base", + createPreset({ + accentColor: "blue", + grayColor: "slate", + borderRadius: "sm", + }), + ], + include: ["./src/**/*.{js,jsx,ts,tsx,vue}"], + jsxFramework: "solid", + outdir: "styled-system", + theme: { + extend: { + slotRecipes: { + treeView: { + base: { + tree: { gap: "0.5" }, + }, + }, + tabs: { + base: { + root: { height: "full", flexGrow: 1, gap: "1" }, + content: { height: "full", flexGrow: 1, overflow: "auto" }, + }, + compoundVariants: [ + { + size: "md", + variant: "enclosed", + css: { content: { p: "unset" } }, + }, + ], + }, + }, + }, + }, +}); diff --git a/pkgs/ffigenpad/web/park-ui.json b/pkgs/ffigenpad/web/park-ui.json new file mode 100644 index 0000000000..3f03b3ec32 --- /dev/null +++ b/pkgs/ffigenpad/web/park-ui.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://park-ui.com/registry/latest/schema.json", + "jsFramework": "solid", + "outputPath": "./third_party/ui" +} diff --git a/pkgs/ffigenpad/web/pnpm-lock.yaml b/pkgs/ffigenpad/web/pnpm-lock.yaml new file mode 100644 index 0000000000..7ff589768b --- /dev/null +++ b/pkgs/ffigenpad/web/pnpm-lock.yaml @@ -0,0 +1,4182 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ark-ui/solid': + specifier: ^3.7.0 + version: 3.7.0(solid-js@1.8.21) + '@codemirror/lang-cpp': + specifier: ^6.0.2 + version: 6.0.2 + '@codemirror/lang-yaml': + specifier: ^6.1.1 + version: 6.1.1(@codemirror/view@6.32.0) + '@codemirror/language': + specifier: ^6.10.2 + version: 6.10.2 + '@codemirror/legacy-modes': + specifier: ^6.4.1 + version: 6.4.1 + '@codemirror/state': + specifier: ^6.4.1 + version: 6.4.1 + '@codemirror/theme-one-dark': + specifier: ^6.1.2 + version: 6.1.2 + '@fontsource-variable/reddit-mono': + specifier: ^5.0.4 + version: 5.0.4 + codemirror: + specifier: ^6.0.1 + version: 6.0.1(@lezer/common@1.2.1) + pathe: + specifier: ^1.1.2 + version: 1.1.2 + solid-icons: + specifier: ^1.1.0 + version: 1.1.0(solid-js@1.8.21) + solid-js: + specifier: ^1.8.21 + version: 1.8.21 + devDependencies: + '@babel/types': + specifier: ^7.25.6 + version: 7.25.6 + '@pandacss/dev': + specifier: ^0.45.1 + version: 0.45.1(typescript@5.5.4) + '@park-ui/panda-preset': + specifier: ^0.42.0 + version: 0.42.0(@internationalized/date@3.5.5)(@pandacss/dev@0.45.1(typescript@5.5.4)) + '@types/node': + specifier: ^22.4.0 + version: 22.4.0 + typescript: + specifier: ^5.5.4 + version: 5.5.4 + vite: + specifier: ^5.4.1 + version: 5.4.1(@types/node@22.4.0)(lightningcss@1.25.1) + vite-plugin-solid: + specifier: ^2.10.2 + version: 2.10.2(solid-js@1.8.21)(vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1)) + vite-tsconfig-paths: + specifier: ^5.0.1 + version: 5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1)) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@ark-ui/anatomy@3.5.0': + resolution: {integrity: sha512-KoROLVVT23BvFHcye/GYhG8NJ2CH0C+CaoJhXrkEjvk8pbEx80Xk5NIUy5gL7xmX+LDD7kY5t3NotBqCu+2L2w==} + + '@ark-ui/solid@3.7.0': + resolution: {integrity: sha512-aJhOb0SuGv+45Me605ICAemos5Q8aZ76xSVD4/VKZCaG2wA7iJa0qoQksCBulS1TYJZ+nZ29GQKi5Wbyi09BtA==} + peerDependencies: + solid-js: '>=1.6.0' + + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.25.2': + resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.25.2': + resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.25.0': + resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.25.2': + resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.18.6': + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.7': + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.25.2': + resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.24.8': + resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-simple-access@7.24.7': + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.8': + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.24.8': + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.25.0': + resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.25.3': + resolution: {integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.24.7': + resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.25.0': + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.25.3': + resolution: {integrity: sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.25.6': + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} + engines: {node: '>=6.9.0'} + + '@clack/core@0.3.4': + resolution: {integrity: sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==} + + '@clack/prompts@0.7.0': + resolution: {integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==} + bundledDependencies: + - is-unicode-supported + + '@codemirror/autocomplete@6.18.0': + resolution: {integrity: sha512-5DbOvBbY4qW5l57cjDsmmpDh3/TeK1vXfTHa+BUMrRzdWdcxKZ4U4V7vQaTtOpApNU4kLS4FQ6cINtLg245LXA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + + '@codemirror/commands@6.6.0': + resolution: {integrity: sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==} + + '@codemirror/lang-cpp@6.0.2': + resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} + + '@codemirror/lang-yaml@6.1.1': + resolution: {integrity: sha512-HV2NzbK9bbVnjWxwObuZh5FuPCowx51mEfoFT9y3y+M37fA3+pbxx4I7uePuygFzDsAmCTwQSc/kXh/flab4uw==} + + '@codemirror/language@6.10.2': + resolution: {integrity: sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==} + + '@codemirror/legacy-modes@6.4.1': + resolution: {integrity: sha512-vdg3XY7OAs5uLDx2Iw+cGfnwtd7kM+Et/eMsqAGTfT/JKiVBQZXosTzjEbWAi/FrY6DcQIz8mQjBozFHZEUWQA==} + + '@codemirror/lint@6.8.1': + resolution: {integrity: sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==} + + '@codemirror/search@6.5.6': + resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} + + '@codemirror/state@6.4.1': + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + + '@codemirror/theme-one-dark@6.1.2': + resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==} + + '@codemirror/view@6.32.0': + resolution: {integrity: sha512-AgVNvED2QTsZp5e3syoHLsrWtwJFYWdx1Vr/m3f4h1ATQz0ax60CfXF3Htdmk69k2MlYZw8gXesnQdHtzyVmAw==} + + '@csstools/postcss-cascade-layers@4.0.6': + resolution: {integrity: sha512-Xt00qGAQyqAODFiFEJNkTpSUz5VfYqnDLECdlA/Vv17nl/OIV5QfTRHGAXrBGG5YcJyHpJ+GF9gF/RZvOQz4oA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-specificity@3.1.1': + resolution: {integrity: sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.13 + + '@esbuild/aix-ppc64@0.20.2': + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.20.2': + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.20.2': + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.20.2': + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.20.2': + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.20.2': + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.20.2': + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.20.2': + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.20.2': + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.20.2': + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.20.2': + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.20.2': + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.20.2': + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.20.2': + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.20.2': + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.20.2': + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.20.2': + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.20.2': + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.20.2': + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.20.2': + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.20.2': + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.20.2': + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.20.2': + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.6.7': + resolution: {integrity: sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==} + + '@floating-ui/dom@1.6.8': + resolution: {integrity: sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==} + + '@floating-ui/utils@0.2.7': + resolution: {integrity: sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==} + + '@fontsource-variable/reddit-mono@5.0.4': + resolution: {integrity: sha512-HwnOG+UTtG1f3xfX4DmucethktAm0l03CPztOQ9SBo6jAThrAMNYQTZI/ifdmXxXVV61gG8Dc+FenwKuyINiwQ==} + + '@internationalized/date@3.5.5': + resolution: {integrity: sha512-H+CfYvOZ0LTJeeLOqm19E3uj/4YjrmOFtBufDHPfvtI80hFAMqtrp7oCACpe4Cil5l8S0Qu/9dYfZc/5lY8WQQ==} + + '@internationalized/number@3.5.3': + resolution: {integrity: sha512-rd1wA3ebzlp0Mehj5YTuTI50AQEx80gWFyHcQu+u91/5NgdwBecO8BH6ipPfE+lmQ9d63vpB3H9SHoIUiupllw==} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@lezer/common@1.2.1': + resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} + + '@lezer/cpp@1.1.2': + resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==} + + '@lezer/highlight@1.2.1': + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + + '@lezer/lr@1.4.2': + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + + '@lezer/yaml@1.0.3': + resolution: {integrity: sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pandacss/config@0.45.1': + resolution: {integrity: sha512-EDRv/3BomoNRgEFBS/NJPPWSh2jg2KAkVp01jCtKiPKIWo3WvAj8+BsCdWSVApYj8cVGSqbb/FlahYP8kK00qQ==} + + '@pandacss/core@0.45.1': + resolution: {integrity: sha512-vO4GMlFBsFzCba3h87XvexwmTjdNILKXNtvrwRcdbP5FfhtKYY5ZNx5lC7zkHZlCL/vRNAZKs+fpNAJiEg2wEg==} + + '@pandacss/dev@0.45.1': + resolution: {integrity: sha512-Bdeb3GmgHZBCoMqUVvBh3mchBkf88LytBSdUCc9lV+YAxucPam7an85vCfRNa2fD8bJTZLGca48r0iTpdlgpIg==} + hasBin: true + + '@pandacss/extractor@0.45.1': + resolution: {integrity: sha512-/lomXtUuDjiQQbrG+dG2PQgVw3YkFBHOvmRwjKy9q8QIUu/lK1I6PjNnF0moxwAmqdsmRWqFshhPZxtKUJg9Ug==} + + '@pandacss/generator@0.45.1': + resolution: {integrity: sha512-jOySRn+jGVqhB9w4HMB/EA3yB7rCLcnEGXK7wQUpkS6YPh2YXMChSVqOwJQKpDbQw2kzKK2YCq80/LBguCrYZQ==} + + '@pandacss/is-valid-prop@0.45.1': + resolution: {integrity: sha512-cY2qJtzTdLJLnO3ep/vz2+Hkar5Q9fht1WphFx2Os3mu4e0QQLi8pXeqjiH1R5vmDTGlarw2LwiMxVFEiamHsg==} + + '@pandacss/logger@0.45.1': + resolution: {integrity: sha512-Q6VKluc3qJyjhblGQQWPpUf1ExiP6puolrWHdqw0yDmyAreb2EPC5DE9g19CY/6YkUDA576MVAe5jgTiJD1eWw==} + + '@pandacss/node@0.45.1': + resolution: {integrity: sha512-K3KpoKAuZXSQX3/jpaMrTXw1A3PU2b9C4DjxtbIZ/+JpEzW9QjS2NAm4NQ4itlxdGJzmRWTm1uOEbxIPYXbkjA==} + + '@pandacss/parser@0.45.1': + resolution: {integrity: sha512-5MJ65/VktMOVyA2xPvUmvyxOQnb3+xGQx/QmvaIQZx8wbJ6VANZfz3DjaMPWnkI+2QVUXcgIDhf7OHyB0pAb5w==} + + '@pandacss/postcss@0.45.1': + resolution: {integrity: sha512-NSx4splVzXbJaJ5VNMgRl06H8Mw/4RT1+ahOpz1Sk4HzPBS2ooVfqjSAofku3HcXC+q6mZn0lSgVU+W2FnouDQ==} + + '@pandacss/preset-base@0.45.1': + resolution: {integrity: sha512-ke5nGIdSzKpFDz0iztFlK2laqqto+VCYdyPQsrl5wYjftTAbLpu3KC96WKxTixmon/hrI8u8/QslOepcW6A3Qw==} + + '@pandacss/preset-panda@0.45.1': + resolution: {integrity: sha512-ft+8QZqS/ivEvQ4HzHEY30r9gP8DtO42sM07Bo3i7p9qSN4K+Fu5GT1X8roE40TOieB/u4pafI2ZLXwX2lQNoQ==} + + '@pandacss/shared@0.45.1': + resolution: {integrity: sha512-05bY+vWkvB1CT0GlrbGsED89hN/wg9nKIedVad/eleuiioUyhX4iKJfnxP2dNcn2g6lFp1UJIeI7j19h5CForg==} + + '@pandacss/token-dictionary@0.45.1': + resolution: {integrity: sha512-z4W/FBu29UYyiboNIq7apxjg7VEHgQaZSx26Ts3qVnAd21uFlKMdtGNGzrRFAGhi1w59oooyKVy7hhrLYOBbqQ==} + + '@pandacss/types@0.45.1': + resolution: {integrity: sha512-ZK9WwK3ha9qT4KPL2PseO5yPSLHRIv9SEvIRgDQfqPR7NdRZHAe4iZ6WVtSx6XGj3yx7dWDuopK3S41D5jZsHA==} + + '@park-ui/panda-preset@0.42.0': + resolution: {integrity: sha512-YvFYNylONBwlnbEZJkziArzqznS6XMCcok8GlrgcIZ8VhjvJbG3Vct1kJr0KYkWOMhQLyFnS75+60ojQyxHNOQ==} + peerDependencies: + '@pandacss/dev': '>0.22.0' + + '@radix-ui/colors@3.0.0': + resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} + + '@rollup/rollup-android-arm-eabi@4.21.0': + resolution: {integrity: sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.21.0': + resolution: {integrity: sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.21.0': + resolution: {integrity: sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.21.0': + resolution: {integrity: sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.21.0': + resolution: {integrity: sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.21.0': + resolution: {integrity: sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.21.0': + resolution: {integrity: sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.21.0': + resolution: {integrity: sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.21.0': + resolution: {integrity: sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.21.0': + resolution: {integrity: sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.21.0': + resolution: {integrity: sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.21.0': + resolution: {integrity: sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.21.0': + resolution: {integrity: sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.21.0': + resolution: {integrity: sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.21.0': + resolution: {integrity: sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.21.0': + resolution: {integrity: sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==} + cpu: [x64] + os: [win32] + + '@swc/helpers@0.5.12': + resolution: {integrity: sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==} + + '@ts-morph/common@0.22.0': + resolution: {integrity: sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + + '@types/node@22.4.0': + resolution: {integrity: sha512-49AbMDwYUz7EXxKU/r7mXOsxwFr4BYbvB7tWYxVuLdb2ibd30ijjXINSMAHiEEZk5PCRBmW1gUeisn2VMKt3cQ==} + + '@vue/compiler-core@3.4.19': + resolution: {integrity: sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==} + + '@vue/compiler-dom@3.4.19': + resolution: {integrity: sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==} + + '@vue/compiler-sfc@3.4.19': + resolution: {integrity: sha512-LQ3U4SN0DlvV0xhr1lUsgLCYlwQfUfetyPxkKYu7dkfvx7g3ojrGAkw0AERLOKYXuAGnqFsEuytkdcComei3Yg==} + + '@vue/compiler-ssr@3.4.19': + resolution: {integrity: sha512-P0PLKC4+u4OMJ8sinba/5Z/iDT84uMRRlrWzadgLA69opCpI1gG4N55qDSC+dedwq2fJtzmGald05LWR5TFfLw==} + + '@vue/shared@3.4.19': + resolution: {integrity: sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==} + + '@zag-js/accordion@0.62.1': + resolution: {integrity: sha512-1lMKuD1GbiMuemOHOu+24BSAAG8iTD6l/4zYrQRBCTsxXzHhWqTtLF7okGgmSAs8iyNfOuWefCfaJJ3BJNSh5A==} + + '@zag-js/accordion@0.64.0': + resolution: {integrity: sha512-VXxRfi61vithidGoLrU1OZmbpieaXn1xog2EBfLJiyjs0d8omrrG7o3XNQfG6Z7wZy9AW9MnSwudGIRY9rSqxw==} + + '@zag-js/anatomy@0.62.1': + resolution: {integrity: sha512-1JiPQOyVlO1jHwLTSNJpyfy1R1UYoaVU1mKSUww5+htAuT/1txjs04pr+8vTF/L/UVzNEZZYepB1tTabyb9LYg==} + + '@zag-js/anatomy@0.64.0': + resolution: {integrity: sha512-zyOUtKAm2n2Ysqqlia/f5j4Qmi+CnFAfymFexW2aWdemhlMLOAu5T9uONH76fgrV1zE81mGzXsXK0/KWtgEaAw==} + + '@zag-js/aria-hidden@0.62.1': + resolution: {integrity: sha512-vVV8bwZhNU+AOOf/USEGV/n9zuTID+spHeC9ZAj29ibWAMmaiq2bx4t1kO4v9eKqKXULUBPPrZQ7CX7oiU616A==} + + '@zag-js/aria-hidden@0.64.0': + resolution: {integrity: sha512-tbOgt58bGdBiRUFj1HU2Vn5gZBzbkizZ66lIc54MVhWw/pMGHcagvK1V82EvdTPBfoe+C/Uj/aFFwCQXJryyuw==} + + '@zag-js/auto-resize@0.62.1': + resolution: {integrity: sha512-nznVkAsZGS+L+VhNO8hPnEyvagNhTezkb64SSPa8E49hJHS2DEN3T5hKCx86tDuiCMd0EdjwUCCQq3pnbzbnCQ==} + + '@zag-js/auto-resize@0.64.0': + resolution: {integrity: sha512-jhftwazRgfCpBtsUKRDGNW43xqigIiQwWkoKiUnUGPScRSCrQracFfgOcrcCncNZHSKd27cs5hYb6YaGBPSJqg==} + + '@zag-js/avatar@0.62.1': + resolution: {integrity: sha512-J+IRqJlpL4S9ikCQle/FHj6p8uT8Ee/D88u4k7m/An4Ot1FcrfKqfC3INB5YOI+d8hkIQVtEIAC8Yt/s4OzAMg==} + + '@zag-js/avatar@0.64.0': + resolution: {integrity: sha512-ikeNweG1EcZ7cYANyuBp5xRGbp39cKW4s0CXsohHhplcTRjA160D/AC4drqOevkiyaIh+yTj8szHuJQ4+BhqYg==} + + '@zag-js/carousel@0.62.1': + resolution: {integrity: sha512-0YQ2jJjzaS1zFLVnPBslVKI8/fY2Z6aOrcJbBjxozG27iSS6zEqmbsz3OOtcYJRlB8jLboZutpMBs3PGh5zg5Q==} + + '@zag-js/carousel@0.64.0': + resolution: {integrity: sha512-0Ig9MxWksTDLXnJT3FSXwCJUVzniQ+ksuPe/lKJgrBsSbCWcLZk/5bacXBBCy9abdtAn+yPmFbgwzLiJG/0v9w==} + + '@zag-js/checkbox@0.62.1': + resolution: {integrity: sha512-xiubQLhRXedlZe4Vc6zxaDFWLSpRdGEG0jTrF3OXovYZLN7bmq0iXiYcWqsLa012+2dYN9w5B1zfQQlzf4sk2w==} + + '@zag-js/checkbox@0.64.0': + resolution: {integrity: sha512-Oiu+CMy43u9U4u049rlEpr4vcAyHuXnuaetBD0minlRs4m/o+gcEtbPbjVYROWSPUdsRuVQeSX5DJ3A2/B8Xtg==} + + '@zag-js/clipboard@0.62.1': + resolution: {integrity: sha512-gEhCGLkAlrgNWkd7ZqF4p4yNKsR54+0YQPevEv7iX9oio8T/F8OWaDmDjA4NsXxqRe6hr5KLJbVp8dYRop30TQ==} + + '@zag-js/clipboard@0.64.0': + resolution: {integrity: sha512-Clk2oCCF0Xa8TZVrOrY2gqOKwvskGVURKkndJWiARFwOI1kPz4IQBCbCnJrQ8zRzai5Sl7k6fYmCm4HQZIxDIA==} + + '@zag-js/collapsible@0.62.1': + resolution: {integrity: sha512-M4hsuqf6dVra6RvKaxQjgQjZ+iYj3XH84w6QOnt/SXbJauQoE6nfy77RI/A8O2pPuP6uLq0h2E9Eo3ftcbGBoQ==} + + '@zag-js/collapsible@0.64.0': + resolution: {integrity: sha512-X2CXm2ji/NOW1K/rApfAbPdAXUuFNvOEMH3O50UfvLWyOTgmbGzEOw3i3+DvPj+WiIut/NTDWpbaYZNop3NHTA==} + + '@zag-js/collection@0.62.1': + resolution: {integrity: sha512-Qg3OvGCvcoeV4u8IcQmNCu4dChRttVyQ9DF8Ab0qlyrjRDF+w8vMAcNcgNqn10/xX4A7B743cz023LooVsW6VA==} + + '@zag-js/collection@0.64.0': + resolution: {integrity: sha512-8HZz8DBN+vVb/lEsgLG3G2KtZzMgbM2zJwtzfxSxOIyChV5IXIXasfVnToLhktitvMCEu6qZEGLBAfFjr+xfgg==} + + '@zag-js/color-picker@0.62.1': + resolution: {integrity: sha512-GLeADGcoMLcVS+UM6rn/c1BmBgSB2uTc5AWBkuKoH7TktsKo6+T/v3/QZIU7/b69qBAp3/vWZti99Flw42IDdw==} + + '@zag-js/color-picker@0.64.0': + resolution: {integrity: sha512-/nUCmXhTkwg2pvZumUvLImvmNVVBNX/1Js16nixx0JicSLJaXQCRDEIFRd7pbjhxuL+Jh0NyaiVcznraRNKY2A==} + + '@zag-js/color-utils@0.62.1': + resolution: {integrity: sha512-uXsEA0xsI4NT7YFwWZldy7LXsk32Ta+41MrckhzbSA766v+bW4sFDUYmJxwLkN4nl1QzlLAlGghhauXmW9Fs8g==} + + '@zag-js/color-utils@0.64.0': + resolution: {integrity: sha512-PQebKNAnwT5CePH/Ix8rBKrP7H3az/u8ZLiM07d9kF2ikahXRRtjYVXrfe+MWH1ZtreSf8I7QOx/hJwL38d7LQ==} + + '@zag-js/combobox@0.62.1': + resolution: {integrity: sha512-EovqyFqD61YmYJYc42qKH2OE7GxMm3gamWLU/lvZe/3eyZt6TsxFe2xeP7WSsvq2v90myMajAnUb0DOpvYaCKw==} + + '@zag-js/combobox@0.64.0': + resolution: {integrity: sha512-g1AQwrgp55t10dKXvONyXW4XKFZBTyKZH+/QuNuHiKR29S0um4h2Ln8uKjrzb0Ker4sU46TSJCDWo24emJh4gA==} + + '@zag-js/core@0.62.1': + resolution: {integrity: sha512-ZSjqnV5vcGDassjmZ/lxWbG244A0i+IHImVZ/a4/0JkjkH126ly+At4FC+HI571pNKiNlrqYmGzRRSBMqm37yQ==} + + '@zag-js/core@0.64.0': + resolution: {integrity: sha512-430n6hSSAFgVVS+5sf64HZwT5OWEbsiny/sROtHjntikFidHHXg1IBvsfu6gEBlRMDw95wtSvmyJENfYENSVgg==} + + '@zag-js/date-picker@0.62.1': + resolution: {integrity: sha512-Wl6yzMtrTy7XgDFbYJaRO8M5dkxLPBvAo3ilDvFBicbJViJCZ9pg1AJYh+xGaK/gfAd7O9wBdYJdHxfESlmlDg==} + + '@zag-js/date-picker@0.64.0': + resolution: {integrity: sha512-fXZH3JKFjYh5YhBuJzWbG+mSnUnxsAp2PGwzXtFeSbLKAn6ZFt9Ix/UKzakbMRgq3HDggnpIMeurpRT62jAzHg==} + + '@zag-js/date-utils@0.62.1': + resolution: {integrity: sha512-YBqT5YRtHOCDS2IcCZtrq7BfzBkU5c+Sc2pVTncf06/3jxjE6l6YbBncMPu5a3uWKjNld1wOTFszhSoPKZfrJA==} + peerDependencies: + '@internationalized/date': '>=3.0.0' + + '@zag-js/date-utils@0.64.0': + resolution: {integrity: sha512-j3WaH5CzgVB8hYw/5E392hE0u0VLRSxPbS1LmHJLrri9JOAd2ld9JLNvvizuwRaLIMHWS1ZxiPjVP/mkyW8MHg==} + peerDependencies: + '@internationalized/date': '>=3.0.0' + + '@zag-js/dialog@0.62.1': + resolution: {integrity: sha512-7YRvWZ9UMUjFz0q537/uaTMBljLimWISfVHkUSa2ngbXB8LPYYbqYv5Vio2rvRFqy3nJR3HTO4cGZJGDjO655g==} + + '@zag-js/dialog@0.64.0': + resolution: {integrity: sha512-ef1dwNU9J2xFzwacLybDDMgoWyCS4NMq8bPEFTVrYGUQXxgKS2b2rtEQRmEpatJxzqpyzrF6TcteAf9WTXzqag==} + + '@zag-js/dismissable@0.62.1': + resolution: {integrity: sha512-muGTBISpjQEWLCrsYa9wAFaGXlVxYtyMaDgpcPpQdQPwZF86b445y4d8h9FjwkESdJ6Zcdjn21pu5CWD28T3uQ==} + + '@zag-js/dismissable@0.64.0': + resolution: {integrity: sha512-3rEYvzFN2yBw7u7HYArXZDh5x/JJgQNzegcWNaYdWUnan3hoH+7acIQsAas50OsuAwJJ+PEEW1RycaEsSvO1ug==} + + '@zag-js/dom-event@0.62.1': + resolution: {integrity: sha512-/+okVW69Xdoot7dutJVMz0iciwWM6DvAeLWr7LB5DZsUQMu93oqV/8BE2JArDxEcg5C208HNThGStcWlTaddgA==} + + '@zag-js/dom-event@0.64.0': + resolution: {integrity: sha512-Uyn7iWJyWu+LvltTPpij/FTELD9Dz+RV6RDmpLdl5tIjhQ4DQBnjZXiLb6D/ui29bE60FpwE4/uOSRB3P37wGA==} + + '@zag-js/dom-query@0.62.1': + resolution: {integrity: sha512-sI/urNd3QX/WI7Sii+X1Z/OTWNisn7EaW3T0X9Rbn41u79DC4KeUnP+wpIq1igSJNH2zQWIWBLJ1OGhAjuSl5g==} + + '@zag-js/dom-query@0.64.0': + resolution: {integrity: sha512-1NnFveHoCwj9/yk3SpAW0Ri4sK0LAjQtWDhpdycVe1DmvNGD/fGfw9Bk+NL2jyH1HkZGI7LM8vTOojFQE4eR1A==} + + '@zag-js/editable@0.62.1': + resolution: {integrity: sha512-BkPLV8T9ixdhz3IxvseV24a1pBNmYhR1np+JUKap0C8thtFbDoF361haEQjCqTCfHDv+j5l1rtq/+H/TF3eEIg==} + + '@zag-js/editable@0.64.0': + resolution: {integrity: sha512-iqjzs+HhgR5IgyYNhOS8hMYk/SDOpfMQeSRHwtXBsA7RnNcXKJNcTocsieEM3nMde2fZMMed+cMaa+E2gM7lKQ==} + + '@zag-js/element-rect@0.62.1': + resolution: {integrity: sha512-SefRp1IeiENoUkl7yxGzUIdxtQqgKlI+G1qlgx9MZgchH2VZCpqi+EuZgLEKzz7REMabOYqbgs6EEIxGIyNueg==} + + '@zag-js/element-rect@0.64.0': + resolution: {integrity: sha512-AFnoIALKqtwVvrgFh/M4jcfku1c8kK2rGEQwucx5YHbPvXquXY6ZaLRtXax1TdkoZJK3ot5ES/OtdDxf03FO9g==} + + '@zag-js/element-size@0.62.1': + resolution: {integrity: sha512-QCtVeIJ611hJPorKEkdfrWWcMohadplZoW8xQW/2PLSmKUhTNLfHsZLyeoYKyj5Jk4X8OAN4onnMVETFw232EA==} + + '@zag-js/element-size@0.64.0': + resolution: {integrity: sha512-A4R70CdOZ4DKaHvAHZsvvLpoBv2PrHPExQTN73vI5mwlS3Eqb6yn58GUOp6I4xIHAo4/EhFgxorT0rZYkfBtjw==} + + '@zag-js/file-upload@0.62.1': + resolution: {integrity: sha512-Wh33acYMJLNRIV2y0GdSZqoN3aX/t/uzIBWh3rVsN7tpjDYWXLYIsXQttkGLFf0sgICK+3PVD+LLaIpiGDh4+Q==} + + '@zag-js/file-upload@0.64.0': + resolution: {integrity: sha512-XY1ptD09tU9aOrSVKnw2d2uwsTM1PMZfz7dlZWu6ww97sBvJEiGZDnocK1M1TeEprJn6Wro9fiLVhHqApntoSA==} + + '@zag-js/file-utils@0.62.1': + resolution: {integrity: sha512-p363S2pqz29wf1shcSfoY2GI9wWrJkKamNiwuehqoYFh2b8isrcWFVL3VYxm937N1/m5+rtMATQbn0a9j9sggA==} + + '@zag-js/file-utils@0.64.0': + resolution: {integrity: sha512-WgvotIED+PXXTBE157UZ+4YljdzwQbr8F6erIBHsCrmH3gbpufRe9wNYOFlzYZyxKAMP23BHqYAmBWyTfeaEUA==} + + '@zag-js/form-utils@0.62.1': + resolution: {integrity: sha512-GJWRRtEpro8TNEUuEWMhIOWmVFXqiHNTTrrRLxijxUIWbsPrPdPiKL7qwBAESYoZQCmN0hU99S0w2Xmm7Q05Zg==} + + '@zag-js/form-utils@0.64.0': + resolution: {integrity: sha512-ftOhcz3PL7yt3oGWgG4hnRslbmbyNPqvTLgvptZT5AbyZw30yJcTejQ6PcAE0noJnITf4JNVdtdikWMoheAcJQ==} + + '@zag-js/hover-card@0.62.1': + resolution: {integrity: sha512-ryiNHQmmHpiDiZ5nuk9nvGUgnT017q8hYf+wLSI5OJ+klHPjrHObb7I7v/fUmKzWNtIOhaL0uw9afzjRt3bLEw==} + + '@zag-js/hover-card@0.64.0': + resolution: {integrity: sha512-9EPoQXVURINkV16+fesBjEypBQn+TDX+2M7AQkJvlmhi0U5tYyPvoMovWg6Ck5ZBbdQlw3W/eri8je+ZMPfIkA==} + + '@zag-js/i18n-utils@0.62.1': + resolution: {integrity: sha512-ipzx0W6VK5x+w/PnUrN8z5SULJuLqvdzsPVBJ2iGHrMcTPC/y9JDt82nJV9fUYmG898pOZUx7vysfLLPNEAFTQ==} + + '@zag-js/i18n-utils@0.64.0': + resolution: {integrity: sha512-xMWuB8zkd4aKwvUyIVabEyUO/cHityeI3ilyInkj1BG0JDsB1M6xCXwhCHVBn8uIh9cDQ1yTVkfi2RUqV2NpQQ==} + + '@zag-js/interact-outside@0.62.1': + resolution: {integrity: sha512-V5N+kr2Uv97HWYL0U5ZVS//NMQu87XGLtI7Ae5EtHrdAEKxO2NpPwf50Gzza4zc1VEVYYFqobTlkNQ3hrrL6VQ==} + + '@zag-js/interact-outside@0.64.0': + resolution: {integrity: sha512-hs8bzaEnQO4fiei8MRV3/Rraoz6wAeKsvGsGyYOmpbWebeEiw+X1W/9Ff9EUbaHf349Th4/W9WTAcHOShMkzkQ==} + + '@zag-js/live-region@0.62.1': + resolution: {integrity: sha512-Giu7d5UWc2Sqb3/T0tSzqSwxJ4mVrNN+MTu06J7EaD4khK5RgX4GRpQ9rpwOS/GJT+8nc6YBhWTi7tqKN/+iHQ==} + + '@zag-js/live-region@0.64.0': + resolution: {integrity: sha512-6iK/gDVmBYduFi3wv9pM7zNj5UJnBJ+acbisp2cqotZyr5oEWzNTITCXggMfEd9A5AsvRW+o0lzRsSKAxzhdIg==} + + '@zag-js/menu@0.62.1': + resolution: {integrity: sha512-l/PartHj6//NMlENYNBmUmeYG9K0SbjbnnIudv+rK+oyrUoX/MDCJ7bdy7ZMYxWTR127WdZlLHBxsgMe86lBqQ==} + + '@zag-js/menu@0.64.0': + resolution: {integrity: sha512-oM3Wucli/RCo8Qk10PKcMM65MiWFvMyIpfVRGqwjPobOoRAqkEZa8SyJAmAZMxy97bPqItdPl8t4zDARSPjQUw==} + + '@zag-js/number-input@0.62.1': + resolution: {integrity: sha512-THizFB4Qwq4erMk6mI82voIo/PbbrAOSQXyPF8NPyGupSzqYntS1XPEdyqFH677PhHweelxQnvtZEm5alm1HLw==} + + '@zag-js/number-input@0.64.0': + resolution: {integrity: sha512-32zexWJCQkfcrl2wto8I4QVb2b7Y/GzIZZpPASUypK8iNdmHUIRalv8tOHfUcqQnN5fRYeYWpsAfku3lDHxcWQ==} + + '@zag-js/number-utils@0.62.1': + resolution: {integrity: sha512-ktnGSYKKLG9No14ivlboEzq4+jiOIWU+8yeoRrZmfdCG58g4s9JF0lBDRf3ts9vhUdofJ+vUFMPqkk2eCWyQlA==} + + '@zag-js/number-utils@0.64.0': + resolution: {integrity: sha512-FX9TY4AYIww0QOfCSNEgPqpu5xevuTT0cZ+JPA390CVSWw8cDjHSg7xUggoO42Op34RjbVYNcivc4XGFZdfhMw==} + + '@zag-js/numeric-range@0.62.1': + resolution: {integrity: sha512-R4/II5MvS+eJ880srPuIlexqRH7kVsGomcsDlB5yyhHsradm7OJfC5L6osvKj1DNAitfFh8901BZFaWmQe8O1w==} + + '@zag-js/numeric-range@0.64.0': + resolution: {integrity: sha512-qMKg+hbKY8NI6xRTfLOa9TEOQyXqot1GZVyHl3r9iYGKwnRHLtG3U/01dkkgFwK88FbRS535RyNLGEuYQJh9jA==} + + '@zag-js/pagination@0.62.1': + resolution: {integrity: sha512-fyDXNnAGyRsQEugvNR1kfEO8hGeesOV6l2rEACdvNN6G9Cqktqd52aaWVIf805G3Ig72igW2SybI9md/rDflzQ==} + + '@zag-js/pagination@0.64.0': + resolution: {integrity: sha512-K5nU0+AvgJq0DY8JFq7hJsD63/jq3vllO3O2+EnD2pC2PvbajV0OlR3XAlysZ2U+YEIvtKkIidNJA1sCVg8j+g==} + + '@zag-js/pin-input@0.62.1': + resolution: {integrity: sha512-CTAOyQCLaNSWH29bhc4XruEkvnYFJN1QF/x5axtHV+cir05zcdB3L7Sna4D6nUBSwd0tOGnUmPlviyP7zkpgBA==} + + '@zag-js/pin-input@0.64.0': + resolution: {integrity: sha512-X4SB7OpaN3PewCkHvOo1kY+snz55d97/3CAMWyKmmVSqpxN7x4wA+dw/CFdfsptkrkmeZeB6cZLJTKWS0tKlyw==} + + '@zag-js/popover@0.62.1': + resolution: {integrity: sha512-cT6okb5Yq69YWx6G1vonNEnEg4MlBXRbXLflLBqOP1PTwhk6RwlndXGV2uCdlnR0mUJa/RKldzdUcwOQesJaag==} + + '@zag-js/popover@0.64.0': + resolution: {integrity: sha512-0umY2np2AsmL+QEWPPb4W3EdZJjZDKIzpA24EiXyGCFVFyMzG7B4bWR+eKZpwWshCy00AAEg6ZbBGOJ8zQYDSA==} + + '@zag-js/popper@0.62.1': + resolution: {integrity: sha512-tyLEdYIsv3cgnWCWzPPv9f72hzmQDQcObDIczIZt+OQr89qgyhGHt5jR1f0Qxsz9zZlSPsEftccyXRQYInQtxQ==} + + '@zag-js/popper@0.64.0': + resolution: {integrity: sha512-IjB4Rpl9CkT3RkgRUiQvV0FGkI0GZdBkyDsIjRyew88976Szxvn2Er0hVxlez0LXcTO8mEbWONOey/fxv3u9Sg==} + + '@zag-js/presence@0.62.1': + resolution: {integrity: sha512-qjnr1WpW5yetRp2j2V0ocRvr6X6TuWNxjL2DyJAusodcsSElF2V0UuFOLT/xIZA8BVIbgcyCvcPB01PHugC5Ww==} + + '@zag-js/presence@0.64.0': + resolution: {integrity: sha512-P86qo3148iKD8FAppuspcXrRRWbPLDRed9sUJJv/3JBD/StNEsSMncgl/5o/XZlOUba6HvsHIQkhYcJzijUWIA==} + + '@zag-js/progress@0.62.1': + resolution: {integrity: sha512-7FyeP/wCiJ2dao1y/4RzhrLeIse305YtRMTDaVE5EnOJK3nit2Rrl+z8kGx5aqrGQcGsLH/rh5QYFp689Nx57Q==} + + '@zag-js/progress@0.64.0': + resolution: {integrity: sha512-AMSOtWYPJ5C0zH8G5YZrTrA5lvPzfTOT1tetTkA1r7WiwI7inxq0FR9C/EqiL26JRDt4eIY6YfHqduhL+sVkoQ==} + + '@zag-js/qr-code@0.62.1': + resolution: {integrity: sha512-648qXQduIqq4CZWN07D1UOcczZrdp3UjBSHFEi4PQHTz1Vg08pH0BIZDqiqpupG9niYJEB/GPLGofRQQYoIoDw==} + + '@zag-js/qr-code@0.64.0': + resolution: {integrity: sha512-sp1+NXFV0OKdgDZUVEnvxEVMX+ajeDU6oqHseqpzQ5fqdGT+W/n8E4E0VeiVaOSIMEYpCSt+8nEFBF1qOB2qJg==} + + '@zag-js/radio-group@0.62.1': + resolution: {integrity: sha512-VVGTUkHgD27vBTYeP7hPYi+eDRXkq7xtlv6Ml062t3gcTWBhc/2eaI6iZ7awlxTl9052sflzbawrrDysPREuAQ==} + + '@zag-js/radio-group@0.64.0': + resolution: {integrity: sha512-SbVxEi4dE0Eg7yoCK76RGF8ItfYQZLcAxkJBmqDaUxRgc3cPqEf7F8220GccxSsosMVwLCa6ks0r4keI/VW7jQ==} + + '@zag-js/rating-group@0.62.1': + resolution: {integrity: sha512-gXvHofr3gfZcaMh7Y3FU+wyj7ge1R0BgsuPJWFUShlAlxjnnE7e3AqjSGlzuvpkWMkc6KKDyKRJlMVWLCv94OA==} + + '@zag-js/rating-group@0.64.0': + resolution: {integrity: sha512-CjNeGuhm0VaHYeR47t//RwYDq2Zl7Pwz+IZSZWhWucUhv4wK4qqx58VP1mr8wbyr2AGcjg8ok2fbl4ZtMS95Vw==} + + '@zag-js/rect-utils@0.62.1': + resolution: {integrity: sha512-6w56LuRD382Oa2FXi4AfKQqgtUPS/nc/mZzXiaqKz9b5aFA1CXtmEwNC2GaiXhkqJp5DyxHwujDfQP1WXACnRQ==} + + '@zag-js/rect-utils@0.64.0': + resolution: {integrity: sha512-TezQ9YpAqhe/nMqnvyriSn5BeCL2VLp0hJAOLDF4h/eq8abZTrZyOI8QaxI2ESJ63q3Zg5ytNbB+POfulOoVrQ==} + + '@zag-js/remove-scroll@0.62.1': + resolution: {integrity: sha512-7xpX6HUrOEq/TNLIWojYnQf7kj20bk8ueOKpu7cTZmoN0LSL6cS09uil+NOqb+SzZsiRmQKvzd3fQBNwbdab5Q==} + + '@zag-js/remove-scroll@0.64.0': + resolution: {integrity: sha512-K/QkHSoRoF3T+SjA3XDjzbK4j0tHasfWTvPbx5LNS8QJPE6Ox3bZSPWsWW/kq1juIdYm0WJEZiaKlBPiAALHBg==} + + '@zag-js/select@0.62.1': + resolution: {integrity: sha512-dgU65imBSeB8+QfHkN68j7Xqd/d6wsF42itJ0AeRSdgnCHgTWdN9rRCK5EDbNkJue51oMkdsnJ7XG1k+oCgiAg==} + + '@zag-js/select@0.64.0': + resolution: {integrity: sha512-b2J5dAqsn+0cBdTqwwdWAm4722u+inefCaFbC9Ytl1NtsfpUN7v70GdinPf3OFtXYa55fynGJgVuCi8v4dHaTQ==} + + '@zag-js/signature-pad@0.62.1': + resolution: {integrity: sha512-hWZSWT9J9V1kbImkj8qXHCqS0TYm7nms9oAhcQ2QNIiGO38wqW8Yswos8sqAj8VtzHxkSMIeL1by7Zgy3Xjq9g==} + + '@zag-js/signature-pad@0.64.0': + resolution: {integrity: sha512-uCO1gZF47fX8Fh49IbBGrkgxSj0PNA2wFEjvX+kEa7FN4Pdin7o+3HGL/6WSGWkxC5FiVCY+wU+pAHZ5GnQk4g==} + + '@zag-js/slider@0.62.1': + resolution: {integrity: sha512-v5rgPJF3fh7bBPu0wzEGpN4EcXpK5cSw4OAwxatmbtkYsg2Udwv6WL26CB5Q2zVwYIR6R532b/bjFqicfVs+SA==} + + '@zag-js/slider@0.64.0': + resolution: {integrity: sha512-w+lkw/oxCk2DuSPry42R9oCvU3FXvoJ6SfLK9rxrpbMCc+Fsk7g0AlhIjr/B0p15rIoLoMrGjDV8jtObUDcO+Q==} + + '@zag-js/solid@0.64.0': + resolution: {integrity: sha512-eDpqol9o2Ov0AbJ36o4n3VyEE0FJQZsWrWJ9Afc/+w8uT9sH6tSIWOouNA8zfNI2jDKOur170P16yT3VbKJRSg==} + peerDependencies: + solid-js: '>=1.1.3' + + '@zag-js/splitter@0.62.1': + resolution: {integrity: sha512-Ni93ZaprnbctAsbuot8sEw9DDfNMgkelnd5xQfAiwpgjwUgnY8733LRbWydC5OUPoJ/cCs3XiNKa0CHwclcq6Q==} + + '@zag-js/splitter@0.64.0': + resolution: {integrity: sha512-XbZowl0C46N+e97Okj36yHDK9njzy9OyalpqjIPlbvIl+p8pve4do6JVaA5EEqtcgH2hWk6vmS/5BpbZNMtY8w==} + + '@zag-js/steps@0.64.0': + resolution: {integrity: sha512-AUQgG6WZ6rgCKkp5w0MAsm1xTs1AVzXlkX/tURuF16s0k/vgqGXqVaXf57OtVcgm4kYXUafFiOv6krOhq7spLg==} + + '@zag-js/store@0.62.1': + resolution: {integrity: sha512-0xkz7b/Rs9cHeI5CB3UH4yMlVzys3l+IsJU3KRWZwqWohDjTEqRyzcuFD6AH28WAcJPjIgOQYnRYzYSoMGZtDQ==} + + '@zag-js/store@0.64.0': + resolution: {integrity: sha512-6FB1K/YqKoGguJ4ZcnH2j5jbzjyDB3M+0j8LBChTYT1OvnyXNfLkk1kcQ81OBO1t9bOPaAo6qEzBiq/pd9qvnQ==} + + '@zag-js/switch@0.62.1': + resolution: {integrity: sha512-uh0yy3NuZqHF+jPVZ2oMcAtPx32eTnBebiROBGBDgj1A5yZBirfQm8j/vZLSILhDq9TdktHS9/gITJ7TvgV4cQ==} + + '@zag-js/switch@0.64.0': + resolution: {integrity: sha512-OO/gsg5q8USNSpvEGnpH3rCo46YVAXYaqCrPFMSbsMaPF5vSykrlltL6LM6KhTx/dvIjk/A/0A58bjCOMF6lkQ==} + + '@zag-js/tabs@0.62.1': + resolution: {integrity: sha512-BpY6oA2nmZLpYu8nQrpi+zTF4txTiMYIMB31CmbFmbJ3hMVkEqk8sgNzNQY3LrzkkSemDRBHxPZ5H+YKaQrEdg==} + + '@zag-js/tabs@0.64.0': + resolution: {integrity: sha512-UfYQDVsZQIezWMdijINWIbegPmPxgr0gXcHnnS34t8KW5L0/UO/5dxwS/MnPQTqqXdSvida5CwCPkmKXdYCnVQ==} + + '@zag-js/tags-input@0.62.1': + resolution: {integrity: sha512-8gJ4ckQQ0BB3oUGgIEGkmB6wIKSf7xx0q6e3tqTbfZnPhmWP4hpli38XAOYjsBQyNXmQW89H/Rp8/8W1A/Vpow==} + + '@zag-js/tags-input@0.64.0': + resolution: {integrity: sha512-1vXob3ds3ejB9AabZmZRThzH7hbQRlJ/vdscoOx8+4i0a/hLrz2ufUHK3lcF7N+UITEKjzrELbNbtvHOL+kHdQ==} + + '@zag-js/text-selection@0.62.1': + resolution: {integrity: sha512-0b049CnWN/Nyp/F/nbeU6G8BI/fzwlSQTTDWK81yRFADDFTZ2mWpVAWJF/fY0rKjsn4ucDykCS7GXMIo5rYILQ==} + + '@zag-js/text-selection@0.64.0': + resolution: {integrity: sha512-PoI5wTjAWDIQeF+zz6y4uGvh6StV5tH76b2z+FJxA9uV9PtFDKLW6W7EhDJGbarc4+d7+P2q6ZVcb/jU6h2U0w==} + + '@zag-js/time-picker@0.62.1': + resolution: {integrity: sha512-THNASHp9Fu5f4/LC3t3qJfsYD6FqjhbP7HrjIDDFOcdNGRzOTfbEpKF3JtJgmM6F+/fuQKhe6FUbcluMd9zo8Q==} + + '@zag-js/time-picker@0.64.0': + resolution: {integrity: sha512-KTC84r6sxHDg09WU4biZuczcgHdJ1yxdFqhByWILDk6jfB9UHgjjLNi6xD39AswawZIgLCRmv3EINKVfvyI31Q==} + + '@zag-js/toast@0.62.1': + resolution: {integrity: sha512-Kb+OiFx7KUG0fAExIL06xWEfhxeMRJACvP6q4B4FNuFX+6N06RbV/PZtLbPbffOodd7VhSk1W37T7t6Np32mvg==} + + '@zag-js/toast@0.64.0': + resolution: {integrity: sha512-k2byQHuH+crmmrkSvK/SiCrp7XRYoCCMlhB29lO0to2qfjqgKjsx/lamSIIkWFyvZlU9erLvrCJbJH7ec6GlTg==} + + '@zag-js/toggle-group@0.62.1': + resolution: {integrity: sha512-h7jQtWJt11uws6IYBd3kQzOyOemtZ5CqR7lt4XZdni3J1EtymKRJNha2JIukIETZS9/0VU1fPcuDkQeCXcGHgQ==} + + '@zag-js/toggle-group@0.64.0': + resolution: {integrity: sha512-CWGV6iuuQD4XqtBltaAVcjQdcQODbjgkA4+nWKfxX0maX5Xwxtff8ZeucVD0hQU/kEpTITBNwc5IF1yxI46/kQ==} + + '@zag-js/tooltip@0.62.1': + resolution: {integrity: sha512-318EJU6B4FR0nMNU79qMAgdOiVM6vbDiRWBHjGLDBK3z5No3lKfo4TZb/NqBmmi2W7ZFPiPwvLFsTql+H0xDbA==} + + '@zag-js/tooltip@0.64.0': + resolution: {integrity: sha512-lL0cNYwaH5JjnRui5WgzEf9H2FHY/oTCCn1wvkaX85eyWVjv87BpDYTOCyxnELTLB1OnXjeC4ZgR+IKmvg3nwA==} + + '@zag-js/tree-view@0.62.1': + resolution: {integrity: sha512-Y7qj16X18uElsD5jA9l03+rKEg1/5JIGRutO+NlEbs9Ffb7y34vqcEWquA+YgDfqXVWk2b5v9xcU1iKuKhOagQ==} + + '@zag-js/tree-view@0.64.0': + resolution: {integrity: sha512-BOgZyB+EJL9HB2iIAUubm8MUey5KmaPLh0Iv1XEJlD0xYB1mT9CROcQJtS6rr7hozJMGeAKbWJhVaZaegJTg8A==} + + '@zag-js/types@0.62.1': + resolution: {integrity: sha512-wjJvasoxg/rsFhMTaGLJEjYnSGaXz7DymtO+wWOIfa+O6y44flHc8wRQ1l6ZRRetCz4RALTuwhZI+0ESZ1Bpwg==} + + '@zag-js/types@0.64.0': + resolution: {integrity: sha512-PsOiyXQYjhJjjBut/29F+/GtoYRoqe8c1LbN9TOupKUQmy0GHHlwqhJ5lwknOTxk3gQ8F/NjUEvRx31cUUTAIQ==} + + '@zag-js/utils@0.62.1': + resolution: {integrity: sha512-90sk7Li2mqoMCAfZbns1xrySEg4PIFPwLpiRO/T2kvKpc9z/qsq2WqDFpS8eqHfYRmkLnmQa0Bw1LzItYYsGVQ==} + + '@zag-js/utils@0.64.0': + resolution: {integrity: sha512-XklPct1OMKgydWE1DIbKIdhZ8Z9R+g/WTo13rg7VSp3aE7lWChNdmyLPIoycNmH4SYcIetFsu6MW3yijkX0DsQ==} + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + babel-plugin-jsx-dom-expressions@0.38.1: + resolution: {integrity: sha512-4FD4H69Cu4jHx2uLDEvx4YC5T/fC/Dmaafhsm8hXm7SjHYzjr09gBVyHdoFza+91f/g9e6tIzjbLCMkOXwmlew==} + peerDependencies: + '@babel/core': ^7.20.12 + + babel-preset-solid@1.8.19: + resolution: {integrity: sha512-F3MoUdx3i4znhStnXUBno+5kGSbvhpbGrPgqfRPrS8W7foVJUOSd1/F9QDyd9dgClHfr+J7V14931eu1PEDDMQ==} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.23.3: + resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bundle-n-require@1.1.1: + resolution: {integrity: sha512-EB2wFjXF106LQLe/CYnKCMCdLeTW47AtcEtUfiqAOgr2a08k0+YgRklur2aLfEYHlhz6baMskZ8L2U92Hh0vyA==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001651: + resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + code-block-writer@12.0.0: + resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} + + codemirror@6.0.1: + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + crosspath@2.0.0: + resolution: {integrity: sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==} + engines: {node: '>=14.9.0'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-utils@5.0.0: + resolution: {integrity: sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + electron-to-chromium@1.5.11: + resolution: {integrity: sha512-R1CccCDYqndR25CaXFd6hp/u9RaaMcftMkphmvuepXr5b1vfLkRml6aWVeBhXJ7rbevHkKEMJtz8XqPf7ffmew==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + file-size@1.0.0: + resolution: {integrity: sha512-tLIdonWTpABkU6Axg2yGChYdrOsy4V8xcm0IcyAP8fSsu6jiXLm5pgs083e4sq5fzNRZuAYolUbZyYmPvCKfwQ==} + + filesize@10.1.4: + resolution: {integrity: sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==} + engines: {node: '>= 10.4.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + html-entities@2.3.3: + resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + javascript-stringify@2.1.0: + resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + lightningcss-darwin-arm64@1.25.1: + resolution: {integrity: sha512-G4Dcvv85bs5NLENcu/s1f7ehzE3D5ThnlWSDwE190tWXRQCQaqwcuHe+MGSVI/slm0XrxnaayXY+cNl3cSricw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.25.1: + resolution: {integrity: sha512-dYWuCzzfqRueDSmto6YU5SoGHvZTMU1Em9xvhcdROpmtOQLorurUZz8+xFxZ51lCO2LnYbfdjZ/gCqWEkwixNg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.25.1: + resolution: {integrity: sha512-hXoy2s9A3KVNAIoKz+Fp6bNeY+h9c3tkcx1J3+pS48CqAt+5bI/R/YY4hxGL57fWAIquRjGKW50arltD6iRt/w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.25.1: + resolution: {integrity: sha512-tWyMgHFlHlp1e5iW3EpqvH5MvsgoN7ZkylBbG2R2LWxnvH3FuWCJOhtGcYx9Ks0Kv0eZOBud789odkYLhyf1ng==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.25.1: + resolution: {integrity: sha512-Xjxsx286OT9/XSnVLIsFEDyDipqe4BcLeB4pXQ/FEA5+2uWCCuAEarUNQumRucnj7k6ftkAHUEph5r821KBccQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.25.1: + resolution: {integrity: sha512-IhxVFJoTW8wq6yLvxdPvyHv4NjzcpN1B7gjxrY3uaykQNXPHNIpChLB52+wfH+yS58zm1PL4LemUp8u9Cfp6Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.25.1: + resolution: {integrity: sha512-RXIaru79KrREPEd6WLXfKfIp4QzoppZvD3x7vuTKkDA64PwTzKJ2jaC43RZHRt8BmyIkRRlmywNhTRMbmkPYpA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.25.1: + resolution: {integrity: sha512-TdcNqFsAENEEFr8fJWg0Y4fZ/nwuqTRsIr7W7t2wmDUlA8eSXVepeeONYcb+gtTj1RaXn/WgNLB45SFkz+XBZA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-x64-msvc@1.25.1: + resolution: {integrity: sha512-9KZZkmmy9oGDSrnyHuxP6iMhbsgChUiu/NSgOx+U1I/wTngBStDf2i2aGRCHvFqj19HqqBEI4WuGVQBa2V6e0A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.25.1: + resolution: {integrity: sha512-V0RMVZzK1+rCHpymRv4URK2lNhIRyO8g7U7zOFwVAhJuat74HtkjIQpQRKNCwFEYkRGpafOpmXXLoaoBcyVtBg==} + engines: {node: '>= 12.0.0'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + look-it-up@2.1.0: + resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + + merge-anything@5.1.7: + resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} + engines: {node: '>=12.13'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + microdiff@1.3.2: + resolution: {integrity: sha512-pKy60S2febliZIbwdfEQKTtL5bLNxOyiRRmD400gueYl9XcHyNGxzHSlJWn9IMHwYXT0yohPYL08+bGozVk8cQ==} + + micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + engines: {node: '>=8.6'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.7.1: + resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-eval@2.0.0: + resolution: {integrity: sha512-Ap+L9HznXAVeJj3TJ1op6M6bg5xtTq8L5CU/PJxtkhea/DrIxdTknGKIECKd/v/Lgql95iuMAYvIzBNd0pmcMg==} + engines: {node: '>= 4'} + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + + outdent@0.8.0: + resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + + package-manager-detector@0.1.0: + resolution: {integrity: sha512-qRwvZgEE7geMY6xPChI3T0qrM0PL4s/AKiLnNVjhg3GdN2/fUUSrpGA5Z8mejMXauT1BS6RJIgWvSGAdqg8NnQ==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + perfect-freehand@1.2.2: + resolution: {integrity: sha512-eh31l019WICQ03pkF3FSzHxB8n07ItqIQ++G5UV8JX0zVOXzgTGCqnRR0jJ2h9U8/2uW4W4mtGJELt9kEV0CFQ==} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pkg-types@1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + + pkg-types@1.1.3: + resolution: {integrity: sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss-discard-duplicates@7.0.0: + resolution: {integrity: sha512-bAnSuBop5LpAIUmmOSsuvtKAAKREB6BBIYStWUTGq8oG5q9fClDMMuY8i4UPI/cEcDx2TN+7PMnXYIId20UVDw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-discard-empty@7.0.0: + resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-merge-rules@7.0.2: + resolution: {integrity: sha512-VAR47UNvRsdrTHLe7TV1CeEtF9SJYR5ukIB9U4GZyZOptgtsS20xSxy+k5wMrI3udST6O1XuIn7cjQkg7sDAAw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-minify-selectors@7.0.2: + resolution: {integrity: sha512-dCzm04wqW1uqLmDZ41XYNBJfjgps3ZugDpogAmJXoCb5oCiTzIX4oPXXKxDpTvWOnKxQKR4EbV4ZawJBLcdXXA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-nested@6.0.1: + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-normalize-whitespace@7.0.0: + resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.31 + + postcss-selector-parser@6.1.1: + resolution: {integrity: sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.41: + resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + + proxy-compare@3.0.0: + resolution: {integrity: sha512-y44MCkgtZUCT9tZGuE278fB7PWVf7fRYy0vbRXAts2o5F0EfC4fIQrvQQGBJo1WJbFcVLXzApOscyJuZqHQc1w==} + + proxy-memoize@3.0.1: + resolution: {integrity: sha512-VDdG/VYtOgdGkWJx7y0o7p+zArSf2383Isci8C+BP3YXgMYDoPd3cCBjw0JdWb6YBb9sFiOPbAADDVTPJnh+9g==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.21.0: + resolution: {integrity: sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + seroval-plugins@1.1.1: + resolution: {integrity: sha512-qNSy1+nUj7hsCOon7AO4wdAIo9P0jrzAMp18XhiOzA6/uO5TKtP7ScozVJ8T293oRIvi5wyCHSM4TrJo/c/GJA==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.1.1: + resolution: {integrity: sha512-rqEO6FZk8mv7Hyv4UCj3FD3b6Waqft605TLfsCe/BiaylRpyyMC0b+uA5TJKawX3KzMrdi3wsLbCaLplrQmBvQ==} + engines: {node: '>=10'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + solid-icons@1.1.0: + resolution: {integrity: sha512-IesTfr/F1ElVwH2E1110s2RPXH4pujKfSs+koT8rwuTAdleO5s26lNSpqJV7D1+QHooJj18mcOiz2PIKs0ic+A==} + peerDependencies: + solid-js: '*' + + solid-js@1.8.21: + resolution: {integrity: sha512-FHUGdoo7GVa1BTpGh/4UtwIISde0vSXoqNB6KFpHiTgkIY959tmCJ7NYQAWDfScBfnpoMGZR8lFz0DiwW/gFlw==} + + solid-refresh@0.6.3: + resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} + peerDependencies: + solid-js: ^1.3 + + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + + style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-evaluator@1.2.0: + resolution: {integrity: sha512-ncSGek1p92bj2ifB7s9UBgryHCkU9vwC5d+Lplt12gT9DH+e41X8dMoHRQjIMeAvyG7j9dEnuHmwgOtuRIQL+Q==} + engines: {node: '>=14.19.0'} + peerDependencies: + jsdom: '>=14.x || >=15.x || >=16.x || >=17.x || >=18.x || >=19.x || >=20.x || >=21.x || >=22.x' + typescript: '>=3.2.x || >= 4.x || >= 5.x' + peerDependenciesMeta: + jsdom: + optional: true + + ts-morph@21.0.1: + resolution: {integrity: sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==} + + ts-pattern@5.0.8: + resolution: {integrity: sha512-aafbuAQOTEeWmA7wtcL94w6I89EgLD7F+IlWkr596wYxeb0oveWDO5dQpv85YP0CGbxXT/qXBIeV6IYLcoZ2uA==} + + ts-pattern@5.2.0: + resolution: {integrity: sha512-aGaSpOlDcns7ZoeG/OMftWyQG1KqPVhgplhJxNCvyIXqWrumM5uIoOSarw/hmmi/T1PnuQ/uD8NaFHvLpHicDg==} + + tsconfck@3.0.2: + resolution: {integrity: sha512-6lWtFjwuhS3XI4HsX4Zg0izOI3FU/AI9EGVlPEUMDIhvLPMD4wkiof0WCoDgW7qY+Dy198g4d9miAqUHWHFH6Q==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tsconfck@3.1.1: + resolution: {integrity: sha512-00eoI6WY57SvZEVjm13stEVE90VkEdJAFGgpFLTsZbJyW/LwFQ7uQxJHWpZ2hzSWgCPKc9AnBnNP+0X7o3hAmQ==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + + typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + + undici-types@6.19.6: + resolution: {integrity: sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + update-browserslist-db@1.1.0: + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validate-html-nesting@1.2.2: + resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} + + vite-plugin-solid@2.10.2: + resolution: {integrity: sha512-AOEtwMe2baBSXMXdo+BUwECC8IFHcKS6WQV/1NEd+Q7vHPap5fmIhLcAzr+DUJ04/KHx/1UBU0l1/GWP+rMAPQ==} + peerDependencies: + '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* + solid-js: ^1.7.2 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + '@testing-library/jest-dom': + optional: true + + vite-tsconfig-paths@5.0.1: + resolution: {integrity: sha512-yqwv+LstU7NwPeNqajZzLEBVpUFU6Dugtb2P84FXuvaoYA+/70l9MHE+GYfYAycVyPSDYZ7mjOFuYBRqlEpTig==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite@5.4.1: + resolution: {integrity: sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitefu@0.2.5: + resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + vite: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@ark-ui/anatomy@3.5.0(@internationalized/date@3.5.5)': + dependencies: + '@zag-js/accordion': 0.62.1 + '@zag-js/anatomy': 0.62.1 + '@zag-js/avatar': 0.62.1 + '@zag-js/carousel': 0.62.1 + '@zag-js/checkbox': 0.62.1 + '@zag-js/clipboard': 0.62.1 + '@zag-js/collapsible': 0.62.1 + '@zag-js/color-picker': 0.62.1 + '@zag-js/color-utils': 0.62.1 + '@zag-js/combobox': 0.62.1 + '@zag-js/date-picker': 0.62.1 + '@zag-js/date-utils': 0.62.1(@internationalized/date@3.5.5) + '@zag-js/dialog': 0.62.1 + '@zag-js/editable': 0.62.1 + '@zag-js/file-upload': 0.62.1 + '@zag-js/hover-card': 0.62.1 + '@zag-js/menu': 0.62.1 + '@zag-js/number-input': 0.62.1 + '@zag-js/pagination': 0.62.1 + '@zag-js/pin-input': 0.62.1 + '@zag-js/popover': 0.62.1 + '@zag-js/presence': 0.62.1 + '@zag-js/progress': 0.62.1 + '@zag-js/qr-code': 0.62.1 + '@zag-js/radio-group': 0.62.1 + '@zag-js/rating-group': 0.62.1 + '@zag-js/select': 0.62.1 + '@zag-js/signature-pad': 0.62.1 + '@zag-js/slider': 0.62.1 + '@zag-js/splitter': 0.62.1 + '@zag-js/switch': 0.62.1 + '@zag-js/tabs': 0.62.1 + '@zag-js/tags-input': 0.62.1 + '@zag-js/time-picker': 0.62.1 + '@zag-js/toast': 0.62.1 + '@zag-js/toggle-group': 0.62.1 + '@zag-js/tooltip': 0.62.1 + '@zag-js/tree-view': 0.62.1 + transitivePeerDependencies: + - '@internationalized/date' + + '@ark-ui/solid@3.7.0(solid-js@1.8.21)': + dependencies: + '@internationalized/date': 3.5.5 + '@zag-js/accordion': 0.64.0 + '@zag-js/anatomy': 0.64.0 + '@zag-js/avatar': 0.64.0 + '@zag-js/carousel': 0.64.0 + '@zag-js/checkbox': 0.64.0 + '@zag-js/clipboard': 0.64.0 + '@zag-js/collapsible': 0.64.0 + '@zag-js/color-picker': 0.64.0 + '@zag-js/combobox': 0.64.0 + '@zag-js/date-picker': 0.64.0 + '@zag-js/dialog': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/editable': 0.64.0 + '@zag-js/file-upload': 0.64.0 + '@zag-js/file-utils': 0.64.0 + '@zag-js/hover-card': 0.64.0 + '@zag-js/i18n-utils': 0.64.0 + '@zag-js/menu': 0.64.0 + '@zag-js/number-input': 0.64.0 + '@zag-js/pagination': 0.64.0 + '@zag-js/pin-input': 0.64.0 + '@zag-js/popover': 0.64.0 + '@zag-js/presence': 0.64.0 + '@zag-js/progress': 0.64.0 + '@zag-js/qr-code': 0.64.0 + '@zag-js/radio-group': 0.64.0 + '@zag-js/rating-group': 0.64.0 + '@zag-js/select': 0.64.0 + '@zag-js/signature-pad': 0.64.0 + '@zag-js/slider': 0.64.0 + '@zag-js/solid': 0.64.0(solid-js@1.8.21) + '@zag-js/splitter': 0.64.0 + '@zag-js/steps': 0.64.0 + '@zag-js/switch': 0.64.0 + '@zag-js/tabs': 0.64.0 + '@zag-js/tags-input': 0.64.0 + '@zag-js/time-picker': 0.64.0 + '@zag-js/toast': 0.64.0 + '@zag-js/toggle-group': 0.64.0 + '@zag-js/tooltip': 0.64.0 + '@zag-js/tree-view': 0.64.0 + '@zag-js/types': 0.64.0 + solid-js: 1.8.21 + + '@babel/code-frame@7.24.7': + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 + + '@babel/compat-data@7.25.2': {} + + '@babel/core@7.25.2': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.0 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.0 + '@babel/parser': 7.25.3 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.6 + convert-source-map: 2.0.0 + debug: 4.3.6 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.25.0': + dependencies: + '@babel/types': 7.25.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + '@babel/helper-compilation-targets@7.25.2': + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.18.6': + dependencies: + '@babel/types': 7.25.6 + + '@babel/helper-module-imports@7.24.7': + dependencies: + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.24.8': {} + + '@babel/helper-simple-access@7.24.7': + dependencies: + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.24.8': {} + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/helper-validator-option@7.24.8': {} + + '@babel/helpers@7.25.0': + dependencies: + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/parser@7.25.3': + dependencies: + '@babel/types': 7.25.6 + + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/template@7.25.0': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.6 + + '@babel/traverse@7.25.3': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.0 + '@babel/parser': 7.25.3 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + debug: 4.3.6 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.25.6': + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + + '@clack/core@0.3.4': + dependencies: + picocolors: 1.0.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.7.0': + dependencies: + '@clack/core': 0.3.4 + picocolors: 1.0.1 + sisteransi: 1.0.5 + + '@codemirror/autocomplete@6.18.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.32.0)(@lezer/common@1.2.1)': + dependencies: + '@codemirror/language': 6.10.2 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + '@lezer/common': 1.2.1 + + '@codemirror/commands@6.6.0': + dependencies: + '@codemirror/language': 6.10.2 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + '@lezer/common': 1.2.1 + + '@codemirror/lang-cpp@6.0.2': + dependencies: + '@codemirror/language': 6.10.2 + '@lezer/cpp': 1.1.2 + + '@codemirror/lang-yaml@6.1.1(@codemirror/view@6.32.0)': + dependencies: + '@codemirror/autocomplete': 6.18.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.32.0)(@lezer/common@1.2.1) + '@codemirror/language': 6.10.2 + '@codemirror/state': 6.4.1 + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/yaml': 1.0.3 + transitivePeerDependencies: + - '@codemirror/view' + + '@codemirror/language@6.10.2': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + style-mod: 4.1.2 + + '@codemirror/legacy-modes@6.4.1': + dependencies: + '@codemirror/language': 6.10.2 + + '@codemirror/lint@6.8.1': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + crelt: 1.0.6 + + '@codemirror/search@6.5.6': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + crelt: 1.0.6 + + '@codemirror/state@6.4.1': {} + + '@codemirror/theme-one-dark@6.1.2': + dependencies: + '@codemirror/language': 6.10.2 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + '@lezer/highlight': 1.2.1 + + '@codemirror/view@6.32.0': + dependencies: + '@codemirror/state': 6.4.1 + style-mod: 4.1.2 + w3c-keyname: 2.2.8 + + '@csstools/postcss-cascade-layers@4.0.6(postcss@8.4.41)': + dependencies: + '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.1) + postcss: 8.4.41 + postcss-selector-parser: 6.1.1 + + '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.1.1)': + dependencies: + postcss-selector-parser: 6.1.1 + + '@esbuild/aix-ppc64@0.20.2': + optional: true + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.20.2': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.20.2': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.20.2': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.20.2': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.20.2': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.20.2': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.20.2': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.20.2': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.20.2': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.20.2': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.20.2': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.20.2': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.20.2': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.20.2': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.20.2': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.20.2': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.20.2': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.20.2': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.20.2': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.20.2': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.20.2': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.20.2': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@floating-ui/core@1.6.7': + dependencies: + '@floating-ui/utils': 0.2.7 + + '@floating-ui/dom@1.6.8': + dependencies: + '@floating-ui/core': 1.6.7 + '@floating-ui/utils': 0.2.7 + + '@floating-ui/utils@0.2.7': {} + + '@fontsource-variable/reddit-mono@5.0.4': {} + + '@internationalized/date@3.5.5': + dependencies: + '@swc/helpers': 0.5.12 + + '@internationalized/number@3.5.3': + dependencies: + '@swc/helpers': 0.5.12 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@lezer/common@1.2.1': {} + + '@lezer/cpp@1.1.2': + dependencies: + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/highlight@1.2.1': + dependencies: + '@lezer/common': 1.2.1 + + '@lezer/lr@1.4.2': + dependencies: + '@lezer/common': 1.2.1 + + '@lezer/yaml@1.0.3': + dependencies: + '@lezer/common': 1.2.1 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@pandacss/config@0.45.1': + dependencies: + '@pandacss/logger': 0.45.1 + '@pandacss/preset-base': 0.45.1 + '@pandacss/preset-panda': 0.45.1 + '@pandacss/shared': 0.45.1 + '@pandacss/types': 0.45.1 + bundle-n-require: 1.1.1 + escalade: 3.1.2 + merge-anything: 5.1.7 + microdiff: 1.3.2 + typescript: 5.3.3 + + '@pandacss/core@0.45.1': + dependencies: + '@csstools/postcss-cascade-layers': 4.0.6(postcss@8.4.41) + '@pandacss/is-valid-prop': 0.45.1 + '@pandacss/logger': 0.45.1 + '@pandacss/shared': 0.45.1 + '@pandacss/token-dictionary': 0.45.1 + '@pandacss/types': 0.45.1 + browserslist: 4.23.3 + hookable: 5.5.3 + lightningcss: 1.25.1 + lodash.merge: 4.6.2 + outdent: 0.8.0 + postcss: 8.4.41 + postcss-discard-duplicates: 7.0.0(postcss@8.4.41) + postcss-discard-empty: 7.0.0(postcss@8.4.41) + postcss-merge-rules: 7.0.2(postcss@8.4.41) + postcss-minify-selectors: 7.0.2(postcss@8.4.41) + postcss-nested: 6.0.1(postcss@8.4.41) + postcss-normalize-whitespace: 7.0.0(postcss@8.4.41) + postcss-selector-parser: 6.1.1 + ts-pattern: 5.0.8 + + '@pandacss/dev@0.45.1(typescript@5.5.4)': + dependencies: + '@clack/prompts': 0.7.0 + '@pandacss/config': 0.45.1 + '@pandacss/logger': 0.45.1 + '@pandacss/node': 0.45.1(typescript@5.5.4) + '@pandacss/postcss': 0.45.1(typescript@5.5.4) + '@pandacss/preset-panda': 0.45.1 + '@pandacss/shared': 0.45.1 + '@pandacss/token-dictionary': 0.45.1 + '@pandacss/types': 0.45.1 + cac: 6.7.14 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/extractor@0.45.1(typescript@5.5.4)': + dependencies: + '@pandacss/shared': 0.45.1 + ts-evaluator: 1.2.0(typescript@5.5.4) + ts-morph: 21.0.1 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/generator@0.45.1': + dependencies: + '@pandacss/core': 0.45.1 + '@pandacss/is-valid-prop': 0.45.1 + '@pandacss/logger': 0.45.1 + '@pandacss/shared': 0.45.1 + '@pandacss/token-dictionary': 0.45.1 + '@pandacss/types': 0.45.1 + javascript-stringify: 2.1.0 + outdent: 0.8.0 + pluralize: 8.0.0 + postcss: 8.4.41 + ts-pattern: 5.0.8 + + '@pandacss/is-valid-prop@0.45.1': {} + + '@pandacss/logger@0.45.1': + dependencies: + '@pandacss/types': 0.45.1 + kleur: 4.1.5 + + '@pandacss/node@0.45.1(typescript@5.5.4)': + dependencies: + '@pandacss/config': 0.45.1 + '@pandacss/core': 0.45.1 + '@pandacss/extractor': 0.45.1(typescript@5.5.4) + '@pandacss/generator': 0.45.1 + '@pandacss/logger': 0.45.1 + '@pandacss/parser': 0.45.1(typescript@5.5.4) + '@pandacss/shared': 0.45.1 + '@pandacss/token-dictionary': 0.45.1 + '@pandacss/types': 0.45.1 + browserslist: 4.23.3 + chokidar: 3.6.0 + fast-glob: 3.3.2 + file-size: 1.0.0 + filesize: 10.1.4 + fs-extra: 11.2.0 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lodash.merge: 4.6.2 + look-it-up: 2.1.0 + outdent: 0.8.0 + package-manager-detector: 0.1.0 + perfect-debounce: 1.0.0 + pkg-types: 1.0.3 + pluralize: 8.0.0 + postcss: 8.4.41 + prettier: 3.2.5 + ts-morph: 21.0.1 + ts-pattern: 5.0.8 + tsconfck: 3.0.2(typescript@5.5.4) + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/parser@0.45.1(typescript@5.5.4)': + dependencies: + '@pandacss/config': 0.45.1 + '@pandacss/core': 0.45.1 + '@pandacss/extractor': 0.45.1(typescript@5.5.4) + '@pandacss/logger': 0.45.1 + '@pandacss/shared': 0.45.1 + '@pandacss/types': 0.45.1 + '@vue/compiler-sfc': 3.4.19 + magic-string: 0.30.11 + ts-morph: 21.0.1 + ts-pattern: 5.0.8 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/postcss@0.45.1(typescript@5.5.4)': + dependencies: + '@pandacss/node': 0.45.1(typescript@5.5.4) + postcss: 8.4.41 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/preset-base@0.45.1': + dependencies: + '@pandacss/types': 0.45.1 + + '@pandacss/preset-panda@0.45.1': + dependencies: + '@pandacss/types': 0.45.1 + + '@pandacss/shared@0.45.1': {} + + '@pandacss/token-dictionary@0.45.1': + dependencies: + '@pandacss/logger': 0.45.1 + '@pandacss/shared': 0.45.1 + '@pandacss/types': 0.45.1 + ts-pattern: 5.0.8 + + '@pandacss/types@0.45.1': {} + + '@park-ui/panda-preset@0.42.0(@internationalized/date@3.5.5)(@pandacss/dev@0.45.1(typescript@5.5.4))': + dependencies: + '@ark-ui/anatomy': 3.5.0(@internationalized/date@3.5.5) + '@pandacss/dev': 0.45.1(typescript@5.5.4) + '@radix-ui/colors': 3.0.0 + ts-pattern: 5.2.0 + transitivePeerDependencies: + - '@internationalized/date' + + '@radix-ui/colors@3.0.0': {} + + '@rollup/rollup-android-arm-eabi@4.21.0': + optional: true + + '@rollup/rollup-android-arm64@4.21.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.21.0': + optional: true + + '@rollup/rollup-darwin-x64@4.21.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.21.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.21.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.21.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.21.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.21.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.21.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.21.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.21.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.21.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.21.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.21.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.21.0': + optional: true + + '@swc/helpers@0.5.12': + dependencies: + tslib: 2.6.3 + + '@ts-morph/common@0.22.0': + dependencies: + fast-glob: 3.3.2 + minimatch: 9.0.5 + mkdirp: 3.0.1 + path-browserify: 1.0.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.25.3 + '@babel/types': 7.25.6 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.25.6 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.25.3 + '@babel/types': 7.25.6 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.25.6 + + '@types/estree@1.0.5': {} + + '@types/node@17.0.45': {} + + '@types/node@22.4.0': + dependencies: + undici-types: 6.19.6 + + '@vue/compiler-core@3.4.19': + dependencies: + '@babel/parser': 7.25.3 + '@vue/shared': 3.4.19 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + + '@vue/compiler-dom@3.4.19': + dependencies: + '@vue/compiler-core': 3.4.19 + '@vue/shared': 3.4.19 + + '@vue/compiler-sfc@3.4.19': + dependencies: + '@babel/parser': 7.25.3 + '@vue/compiler-core': 3.4.19 + '@vue/compiler-dom': 3.4.19 + '@vue/compiler-ssr': 3.4.19 + '@vue/shared': 3.4.19 + estree-walker: 2.0.2 + magic-string: 0.30.11 + postcss: 8.4.41 + source-map-js: 1.2.0 + + '@vue/compiler-ssr@3.4.19': + dependencies: + '@vue/compiler-dom': 3.4.19 + '@vue/shared': 3.4.19 + + '@vue/shared@3.4.19': {} + + '@zag-js/accordion@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/accordion@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/anatomy@0.62.1': {} + + '@zag-js/anatomy@0.64.0': {} + + '@zag-js/aria-hidden@0.62.1': + dependencies: + '@zag-js/dom-query': 0.62.1 + + '@zag-js/aria-hidden@0.64.0': + dependencies: + '@zag-js/dom-query': 0.64.0 + + '@zag-js/auto-resize@0.62.1': + dependencies: + '@zag-js/dom-query': 0.62.1 + + '@zag-js/auto-resize@0.64.0': + dependencies: + '@zag-js/dom-query': 0.64.0 + + '@zag-js/avatar@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/avatar@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/carousel@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/carousel@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/checkbox@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/checkbox@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/clipboard@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/clipboard@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/collapsible@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/collapsible@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/collection@0.62.1': + dependencies: + '@zag-js/utils': 0.62.1 + + '@zag-js/collection@0.64.0': + dependencies: + '@zag-js/utils': 0.64.0 + + '@zag-js/color-picker@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/color-utils': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/text-selection': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/color-picker@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/color-utils': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/text-selection': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/color-utils@0.62.1': + dependencies: + '@zag-js/numeric-range': 0.62.1 + + '@zag-js/color-utils@0.64.0': + dependencies: + '@zag-js/numeric-range': 0.64.0 + + '@zag-js/combobox@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/aria-hidden': 0.62.1 + '@zag-js/collection': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/combobox@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/aria-hidden': 0.64.0 + '@zag-js/collection': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/core@0.62.1': + dependencies: + '@zag-js/store': 0.62.1 + klona: 2.0.6 + + '@zag-js/core@0.64.0': + dependencies: + '@zag-js/store': 0.64.0 + klona: 2.0.6 + + '@zag-js/date-picker@0.62.1': + dependencies: + '@internationalized/date': 3.5.5 + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/date-utils': 0.62.1(@internationalized/date@3.5.5) + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/live-region': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/text-selection': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/date-picker@0.64.0': + dependencies: + '@internationalized/date': 3.5.5 + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/date-utils': 0.64.0(@internationalized/date@3.5.5) + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/live-region': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/text-selection': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/date-utils@0.62.1(@internationalized/date@3.5.5)': + dependencies: + '@internationalized/date': 3.5.5 + + '@zag-js/date-utils@0.64.0(@internationalized/date@3.5.5)': + dependencies: + '@internationalized/date': 3.5.5 + + '@zag-js/dialog@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/aria-hidden': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/remove-scroll': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + focus-trap: 7.5.4 + + '@zag-js/dialog@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/aria-hidden': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/remove-scroll': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + focus-trap: 7.5.4 + + '@zag-js/dismissable@0.62.1': + dependencies: + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/interact-outside': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/dismissable@0.64.0': + dependencies: + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/interact-outside': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/dom-event@0.62.1': + dependencies: + '@zag-js/dom-query': 0.62.1 + '@zag-js/text-selection': 0.62.1 + '@zag-js/types': 0.62.1 + + '@zag-js/dom-event@0.64.0': + dependencies: + '@zag-js/dom-query': 0.64.0 + '@zag-js/text-selection': 0.64.0 + '@zag-js/types': 0.64.0 + + '@zag-js/dom-query@0.62.1': {} + + '@zag-js/dom-query@0.64.0': {} + + '@zag-js/editable@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/interact-outside': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/editable@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/interact-outside': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/element-rect@0.62.1': {} + + '@zag-js/element-rect@0.64.0': {} + + '@zag-js/element-size@0.62.1': {} + + '@zag-js/element-size@0.64.0': {} + + '@zag-js/file-upload@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/file-utils': 0.62.1 + '@zag-js/i18n-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/file-upload@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/file-utils': 0.64.0 + '@zag-js/i18n-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/file-utils@0.62.1': + dependencies: + '@zag-js/i18n-utils': 0.62.1 + + '@zag-js/file-utils@0.64.0': + dependencies: + '@zag-js/i18n-utils': 0.64.0 + + '@zag-js/form-utils@0.62.1': {} + + '@zag-js/form-utils@0.64.0': {} + + '@zag-js/hover-card@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/hover-card@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/i18n-utils@0.62.1': + dependencies: + '@zag-js/dom-query': 0.62.1 + + '@zag-js/i18n-utils@0.64.0': + dependencies: + '@zag-js/dom-query': 0.64.0 + + '@zag-js/interact-outside@0.62.1': + dependencies: + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/interact-outside@0.64.0': + dependencies: + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/live-region@0.62.1': {} + + '@zag-js/live-region@0.64.0': {} + + '@zag-js/menu@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/rect-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/menu@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/rect-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/number-input@0.62.1': + dependencies: + '@internationalized/number': 3.5.3 + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/number-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/number-input@0.64.0': + dependencies: + '@internationalized/number': 3.5.3 + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/number-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/number-utils@0.62.1': {} + + '@zag-js/number-utils@0.64.0': {} + + '@zag-js/numeric-range@0.62.1': {} + + '@zag-js/numeric-range@0.64.0': {} + + '@zag-js/pagination@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/pagination@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/pin-input@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/pin-input@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/popover@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/aria-hidden': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/remove-scroll': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + focus-trap: 7.5.4 + + '@zag-js/popover@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/aria-hidden': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/remove-scroll': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + focus-trap: 7.5.4 + + '@zag-js/popper@0.62.1': + dependencies: + '@floating-ui/dom': 1.6.8 + '@zag-js/dom-query': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/popper@0.64.0': + dependencies: + '@floating-ui/dom': 1.6.8 + '@zag-js/dom-query': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/presence@0.62.1': + dependencies: + '@zag-js/core': 0.62.1 + '@zag-js/types': 0.62.1 + + '@zag-js/presence@0.64.0': + dependencies: + '@zag-js/core': 0.64.0 + '@zag-js/types': 0.64.0 + + '@zag-js/progress@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/progress@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/qr-code@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + proxy-memoize: 3.0.1 + uqr: 0.1.2 + + '@zag-js/qr-code@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + proxy-memoize: 3.0.1 + uqr: 0.1.2 + + '@zag-js/radio-group@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/element-rect': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/radio-group@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/element-rect': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/rating-group@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/rating-group@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/rect-utils@0.62.1': {} + + '@zag-js/rect-utils@0.64.0': {} + + '@zag-js/remove-scroll@0.62.1': + dependencies: + '@zag-js/dom-query': 0.62.1 + + '@zag-js/remove-scroll@0.64.0': + dependencies: + '@zag-js/dom-query': 0.64.0 + + '@zag-js/select@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/collection': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/select@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/collection': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/signature-pad@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + perfect-freehand: 1.2.2 + + '@zag-js/signature-pad@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + perfect-freehand: 1.2.2 + + '@zag-js/slider@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/element-size': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/numeric-range': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/slider@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/element-size': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/numeric-range': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/solid@0.64.0(solid-js@1.8.21)': + dependencies: + '@zag-js/core': 0.64.0 + '@zag-js/store': 0.64.0 + '@zag-js/types': 0.64.0 + solid-js: 1.8.21 + + '@zag-js/splitter@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/number-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/splitter@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/number-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/steps@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/store@0.62.1': + dependencies: + proxy-compare: 3.0.0 + + '@zag-js/store@0.64.0': + dependencies: + proxy-compare: 3.0.0 + + '@zag-js/switch@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/switch@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/tabs@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/element-rect': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/tabs@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/element-rect': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/tags-input@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/auto-resize': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/form-utils': 0.62.1 + '@zag-js/interact-outside': 0.62.1 + '@zag-js/live-region': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/tags-input@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/auto-resize': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/form-utils': 0.64.0 + '@zag-js/interact-outside': 0.64.0 + '@zag-js/live-region': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/text-selection@0.62.1': + dependencies: + '@zag-js/dom-query': 0.62.1 + + '@zag-js/text-selection@0.64.0': + dependencies: + '@zag-js/dom-query': 0.64.0 + + '@zag-js/time-picker@0.62.1': + dependencies: + '@internationalized/date': 3.5.5 + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/time-picker@0.64.0': + dependencies: + '@internationalized/date': 3.5.5 + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/toast@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dismissable': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/toast@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dismissable': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/toggle-group@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/toggle-group@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/tooltip@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/popper': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/tooltip@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/popper': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/tree-view@0.62.1': + dependencies: + '@zag-js/anatomy': 0.62.1 + '@zag-js/core': 0.62.1 + '@zag-js/dom-event': 0.62.1 + '@zag-js/dom-query': 0.62.1 + '@zag-js/types': 0.62.1 + '@zag-js/utils': 0.62.1 + + '@zag-js/tree-view@0.64.0': + dependencies: + '@zag-js/anatomy': 0.64.0 + '@zag-js/core': 0.64.0 + '@zag-js/dom-event': 0.64.0 + '@zag-js/dom-query': 0.64.0 + '@zag-js/types': 0.64.0 + '@zag-js/utils': 0.64.0 + + '@zag-js/types@0.62.1': + dependencies: + csstype: 3.1.3 + + '@zag-js/types@0.64.0': + dependencies: + csstype: 3.1.3 + + '@zag-js/utils@0.62.1': {} + + '@zag-js/utils@0.64.0': {} + + acorn@8.12.1: {} + + ansi-colors@4.1.3: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + babel-plugin-jsx-dom-expressions@0.38.1(@babel/core@7.25.2): + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.18.6 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) + '@babel/types': 7.25.6 + html-entities: 2.3.3 + validate-html-nesting: 1.2.2 + + babel-preset-solid@1.8.19(@babel/core@7.25.2): + dependencies: + '@babel/core': 7.25.2 + babel-plugin-jsx-dom-expressions: 0.38.1(@babel/core@7.25.2) + + balanced-match@1.0.2: {} + + binary-extensions@2.3.0: {} + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.23.3: + dependencies: + caniuse-lite: 1.0.30001651 + electron-to-chromium: 1.5.11 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.23.3) + + bundle-n-require@1.1.1: + dependencies: + esbuild: 0.20.2 + node-eval: 2.0.0 + + cac@6.7.14: {} + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.23.3 + caniuse-lite: 1.0.30001651 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001651: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + code-block-writer@12.0.0: {} + + codemirror@6.0.1(@lezer/common@1.2.1): + dependencies: + '@codemirror/autocomplete': 6.18.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.32.0)(@lezer/common@1.2.1) + '@codemirror/commands': 6.6.0 + '@codemirror/language': 6.10.2 + '@codemirror/lint': 6.8.1 + '@codemirror/search': 6.5.6 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.32.0 + transitivePeerDependencies: + - '@lezer/common' + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-name@1.1.3: {} + + confbox@0.1.7: {} + + convert-source-map@2.0.0: {} + + crelt@1.0.6: {} + + crosspath@2.0.0: + dependencies: + '@types/node': 17.0.45 + + cssesc@3.0.0: {} + + cssnano-utils@5.0.0(postcss@8.4.41): + dependencies: + postcss: 8.4.41 + + csstype@3.1.3: {} + + debug@4.3.6: + dependencies: + ms: 2.1.2 + + detect-libc@1.0.3: {} + + electron-to-chromium@1.5.11: {} + + entities@4.5.0: {} + + esbuild@0.20.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.1.2: {} + + escape-string-regexp@1.0.5: {} + + estree-walker@2.0.2: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + file-size@1.0.0: {} + + filesize@10.1.4: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + focus-trap@7.5.4: + dependencies: + tabbable: 6.2.0 + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@11.12.0: {} + + globrex@0.1.2: {} + + graceful-fs@4.2.11: {} + + has-flag@3.0.0: {} + + hookable@5.5.3: {} + + html-entities@2.3.3: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-what@4.1.16: {} + + javascript-stringify@2.1.0: {} + + js-tokens@4.0.0: {} + + jsesc@2.5.2: {} + + json5@2.2.3: {} + + jsonc-parser@3.3.1: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + kleur@4.1.5: {} + + klona@2.0.6: {} + + lightningcss-darwin-arm64@1.25.1: + optional: true + + lightningcss-darwin-x64@1.25.1: + optional: true + + lightningcss-freebsd-x64@1.25.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.25.1: + optional: true + + lightningcss-linux-arm64-gnu@1.25.1: + optional: true + + lightningcss-linux-arm64-musl@1.25.1: + optional: true + + lightningcss-linux-x64-gnu@1.25.1: + optional: true + + lightningcss-linux-x64-musl@1.25.1: + optional: true + + lightningcss-win32-x64-msvc@1.25.1: + optional: true + + lightningcss@1.25.1: + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.25.1 + lightningcss-darwin-x64: 1.25.1 + lightningcss-freebsd-x64: 1.25.1 + lightningcss-linux-arm-gnueabihf: 1.25.1 + lightningcss-linux-arm64-gnu: 1.25.1 + lightningcss-linux-arm64-musl: 1.25.1 + lightningcss-linux-x64-gnu: 1.25.1 + lightningcss-linux-x64-musl: 1.25.1 + lightningcss-win32-x64-msvc: 1.25.1 + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.uniq@4.5.0: {} + + look-it-up@2.1.0: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.11: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + merge-anything@5.1.7: + dependencies: + is-what: 4.1.16 + + merge2@1.4.1: {} + + microdiff@1.3.2: {} + + micromatch@4.0.7: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + mkdirp@3.0.1: {} + + mlly@1.7.1: + dependencies: + acorn: 8.12.1 + pathe: 1.1.2 + pkg-types: 1.1.3 + ufo: 1.5.4 + + ms@2.1.2: {} + + nanoid@3.3.7: {} + + node-eval@2.0.0: + dependencies: + path-is-absolute: 1.0.1 + + node-releases@2.0.18: {} + + normalize-path@3.0.0: {} + + object-path@0.11.8: {} + + outdent@0.8.0: {} + + package-manager-detector@0.1.0: {} + + path-browserify@1.0.1: {} + + path-is-absolute@1.0.1: {} + + pathe@1.1.2: {} + + perfect-debounce@1.0.0: {} + + perfect-freehand@1.2.2: {} + + picocolors@1.0.1: {} + + picomatch@2.3.1: {} + + pkg-types@1.0.3: + dependencies: + jsonc-parser: 3.3.1 + mlly: 1.7.1 + pathe: 1.1.2 + + pkg-types@1.1.3: + dependencies: + confbox: 0.1.7 + mlly: 1.7.1 + pathe: 1.1.2 + + pluralize@8.0.0: {} + + postcss-discard-duplicates@7.0.0(postcss@8.4.41): + dependencies: + postcss: 8.4.41 + + postcss-discard-empty@7.0.0(postcss@8.4.41): + dependencies: + postcss: 8.4.41 + + postcss-merge-rules@7.0.2(postcss@8.4.41): + dependencies: + browserslist: 4.23.3 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.0(postcss@8.4.41) + postcss: 8.4.41 + postcss-selector-parser: 6.1.1 + + postcss-minify-selectors@7.0.2(postcss@8.4.41): + dependencies: + cssesc: 3.0.0 + postcss: 8.4.41 + postcss-selector-parser: 6.1.1 + + postcss-nested@6.0.1(postcss@8.4.41): + dependencies: + postcss: 8.4.41 + postcss-selector-parser: 6.1.1 + + postcss-normalize-whitespace@7.0.0(postcss@8.4.41): + dependencies: + postcss: 8.4.41 + postcss-value-parser: 4.2.0 + + postcss-selector-parser@6.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.4.41: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + + prettier@3.2.5: {} + + proxy-compare@3.0.0: {} + + proxy-memoize@3.0.1: + dependencies: + proxy-compare: 3.0.0 + + queue-microtask@1.2.3: {} + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + reusify@1.0.4: {} + + rollup@4.21.0: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.21.0 + '@rollup/rollup-android-arm64': 4.21.0 + '@rollup/rollup-darwin-arm64': 4.21.0 + '@rollup/rollup-darwin-x64': 4.21.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.21.0 + '@rollup/rollup-linux-arm-musleabihf': 4.21.0 + '@rollup/rollup-linux-arm64-gnu': 4.21.0 + '@rollup/rollup-linux-arm64-musl': 4.21.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.21.0 + '@rollup/rollup-linux-riscv64-gnu': 4.21.0 + '@rollup/rollup-linux-s390x-gnu': 4.21.0 + '@rollup/rollup-linux-x64-gnu': 4.21.0 + '@rollup/rollup-linux-x64-musl': 4.21.0 + '@rollup/rollup-win32-arm64-msvc': 4.21.0 + '@rollup/rollup-win32-ia32-msvc': 4.21.0 + '@rollup/rollup-win32-x64-msvc': 4.21.0 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + semver@6.3.1: {} + + seroval-plugins@1.1.1(seroval@1.1.1): + dependencies: + seroval: 1.1.1 + + seroval@1.1.1: {} + + sisteransi@1.0.5: {} + + solid-icons@1.1.0(solid-js@1.8.21): + dependencies: + solid-js: 1.8.21 + + solid-js@1.8.21: + dependencies: + csstype: 3.1.3 + seroval: 1.1.1 + seroval-plugins: 1.1.1(seroval@1.1.1) + + solid-refresh@0.6.3(solid-js@1.8.21): + dependencies: + '@babel/generator': 7.25.0 + '@babel/helper-module-imports': 7.24.7 + '@babel/types': 7.25.6 + solid-js: 1.8.21 + transitivePeerDependencies: + - supports-color + + source-map-js@1.2.0: {} + + style-mod@4.1.2: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + tabbable@6.2.0: {} + + to-fast-properties@2.0.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-evaluator@1.2.0(typescript@5.5.4): + dependencies: + ansi-colors: 4.1.3 + crosspath: 2.0.0 + object-path: 0.11.8 + typescript: 5.5.4 + + ts-morph@21.0.1: + dependencies: + '@ts-morph/common': 0.22.0 + code-block-writer: 12.0.0 + + ts-pattern@5.0.8: {} + + ts-pattern@5.2.0: {} + + tsconfck@3.0.2(typescript@5.5.4): + optionalDependencies: + typescript: 5.5.4 + + tsconfck@3.1.1(typescript@5.5.4): + optionalDependencies: + typescript: 5.5.4 + + tslib@2.6.3: {} + + typescript@5.3.3: {} + + typescript@5.5.4: {} + + ufo@1.5.4: {} + + undici-types@6.19.6: {} + + universalify@2.0.1: {} + + update-browserslist-db@1.1.0(browserslist@4.23.3): + dependencies: + browserslist: 4.23.3 + escalade: 3.1.2 + picocolors: 1.0.1 + + uqr@0.1.2: {} + + util-deprecate@1.0.2: {} + + validate-html-nesting@1.2.2: {} + + vite-plugin-solid@2.10.2(solid-js@1.8.21)(vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1)): + dependencies: + '@babel/core': 7.25.2 + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.8.19(@babel/core@7.25.2) + merge-anything: 5.1.7 + solid-js: 1.8.21 + solid-refresh: 0.6.3(solid-js@1.8.21) + vite: 5.4.1(@types/node@22.4.0)(lightningcss@1.25.1) + vitefu: 0.2.5(vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1)) + transitivePeerDependencies: + - supports-color + + vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1)): + dependencies: + debug: 4.3.6 + globrex: 0.1.2 + tsconfck: 3.1.1(typescript@5.5.4) + optionalDependencies: + vite: 5.4.1(@types/node@22.4.0)(lightningcss@1.25.1) + transitivePeerDependencies: + - supports-color + - typescript + + vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.41 + rollup: 4.21.0 + optionalDependencies: + '@types/node': 22.4.0 + fsevents: 2.3.3 + lightningcss: 1.25.1 + + vitefu@0.2.5(vite@5.4.1(@types/node@22.4.0)(lightningcss@1.25.1)): + optionalDependencies: + vite: 5.4.1(@types/node@22.4.0)(lightningcss@1.25.1) + + w3c-keyname@2.2.8: {} + + yallist@3.1.1: {} diff --git a/pkgs/ffigenpad/web/postcss.config.cjs b/pkgs/ffigenpad/web/postcss.config.cjs new file mode 100644 index 0000000000..1bfc8f1deb --- /dev/null +++ b/pkgs/ffigenpad/web/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + "@pandacss/dev/postcss": {}, + }, +}; diff --git a/pkgs/ffigenpad/web/src/App.tsx b/pkgs/ffigenpad/web/src/App.tsx new file mode 100644 index 0000000000..45042a5214 --- /dev/null +++ b/pkgs/ffigenpad/web/src/App.tsx @@ -0,0 +1,185 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { TbClipboardCopy, TbExternalLink } from "solid-icons/tb"; +import { + createResource, + createSignal, + lazy, + onMount, + Show, + Suspense, +} from "solid-js"; +import { Center, Flex, HStack, Stack } from "styled-system/jsx"; +import * as dart from "../../bin/ffigenpad.mjs"; +import dartWasm from "../../bin/ffigenpad.wasm?url"; +import createLibClang from "../../bin/libclang.mjs"; +import { BindingsViewer } from "./components/bindings-viewer"; +import { ConfigEditor } from "./components/config-editor"; +import { HeaderEditor } from "./components/header-editor"; +import { Navbar } from "./components/navbar"; +import { Button } from "third_party/ui/button"; +import { Spinner } from "third_party/ui/spinner"; +import { Splitter } from "third_party/ui/splitter"; +import { Tabs } from "third_party/ui/tabs"; +import { Text } from "third_party/ui/text"; +import { $bindings } from "./lib/bindings"; +import { $ffigenConfig } from "./lib/ffigen-config"; +import { registerMemFSListeners } from "./lib/filesystem"; +import { $logs } from "./lib/log"; + +const FileExplorer = lazy(() => import("./components/file-explorer")); +const LogsViewer = lazy(() => import("./components/logs-viewer")); + +/** + * Core app which is loaded after all the wasm files are loaded + */ +function FFIGenPad({ ffigenpad }: { ffigenpad: WebAssembly.Instance }) { + const [logs, setLogs] = $logs; + const [ffigenConfig] = $ffigenConfig; + const [bindings, setBindings] = $bindings; + const [loading, setLoading] = createSignal(false); + + registerMemFSListeners(); + + function generate() { + setLoading(true); + // need to wrap in a timeout to show the loading spinner + setTimeout(() => { + setLogs([]); + dart.invoke(ffigenpad, ffigenConfig()); + setBindings(globalThis.FS.readFile("/output.dart", { encoding: "utf8" })); + setLoading(false); + }, 0); + } + + // generate bindings for default settings on load + onMount(generate); + + function copyBindings() { + navigator.clipboard.writeText(bindings()); + } + + return ( + + + + + + }> + + + + Headers + Config + + + + + + + + + + + + + + + + + + + + + + ); +} + +/** + * THE APP + */ +function App() { + const [ffigenpad] = createResource(async () => { + const libclang = await createLibClang(); + globalThis.FS = libclang.FS; + globalThis.addFunction = libclang.addFunction; + globalThis.removeFunction = libclang.removeFunction; + globalThis.setLogs = $logs[1]; + + const module = new WebAssembly.Module( + await (await fetch(dartWasm)).arrayBuffer(), + ); + const instance: WebAssembly.Instance = await dart.instantiate(module, { + ffi: { + malloc: libclang.wasmExports.malloc, + free: libclang.wasmExports.free, + memory: libclang.wasmMemory, + }, + libclang: libclang.wasmExports, + }); + return instance; + }); + + return ( + + + + + + ffigenpad might take some time to load + + + } + > + + + + ); +} + +export default App; diff --git a/pkgs/ffigenpad/web/src/components/bindings-viewer.tsx b/pkgs/ffigenpad/web/src/components/bindings-viewer.tsx new file mode 100644 index 0000000000..93cd0596cc --- /dev/null +++ b/pkgs/ffigenpad/web/src/components/bindings-viewer.tsx @@ -0,0 +1,62 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { StreamLanguage } from "@codemirror/language"; +import { dart } from "@codemirror/legacy-modes/mode/clike"; +import { EditorState } from "@codemirror/state"; +import { basicSetup, EditorView } from "codemirror"; +import { createEffect, onMount } from "solid-js"; +import { Box } from "styled-system/jsx"; +import { $bindings } from "~/lib/bindings"; +import { $theme, editorThemeConfig } from "~/lib/theme"; + +/** + * Displays output generated by ffigen in a read only codemirror editor + */ +export const BindingsViewer = () => { + const [bindings] = $bindings; + + let editorRef: HTMLDivElement; + let editor: EditorView; + + onMount(() => { + editor = new EditorView({ + doc: bindings(), + extensions: [ + basicSetup, + StreamLanguage.define(dart), + editorThemeConfig.of([$theme.editorTheme()]), + EditorView.theme({ + "&": { + height: "100%", + }, + }), + // set readOnly true + EditorState.readOnly.of(true), + ], + parent: editorRef!, + }); + + return () => { + editor.destroy(); + }; + }); + + createEffect(() => { + if (editor) { + // change the content whenever the generated bindings are updated + editor.dispatch({ + changes: { from: 0, to: editor.state.doc.length, insert: bindings() }, + }); + } + }); + + createEffect(() => { + if (editor) { + editor.dispatch($theme.editorThemeTransaction()); + } + }); + + return ; +}; diff --git a/pkgs/ffigenpad/web/src/components/config-editor.tsx b/pkgs/ffigenpad/web/src/components/config-editor.tsx new file mode 100644 index 0000000000..9e5ad232a1 --- /dev/null +++ b/pkgs/ffigenpad/web/src/components/config-editor.tsx @@ -0,0 +1,55 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { yaml } from "@codemirror/lang-yaml"; +import { basicSetup, EditorView } from "codemirror"; +import { createEffect, onMount } from "solid-js"; +import { Box } from "styled-system/jsx"; +import { $ffigenConfig } from "~/lib/ffigen-config"; +import { $theme, editorThemeConfig } from "~/lib/theme"; + +/** + * Codemirror editor used for editing ffigen config yaml file + */ +export const ConfigEditor = () => { + let editorRef: HTMLDivElement; + let editor: EditorView; + + const [ffigenConfig, setFfigenConfig] = $ffigenConfig; + + onMount(() => { + editor = new EditorView({ + doc: ffigenConfig(), + extensions: [ + basicSetup, + yaml(), + EditorView.domEventHandlers({ + // update the config when editor is not in focus to prevent frequent updates + blur: (_, view) => { + setFfigenConfig(view.state.doc.toString()); + }, + }), + editorThemeConfig.of([$theme.editorTheme()]), + EditorView.theme({ + "&": { + height: "100%", + }, + }), + ], + parent: editorRef!, + }); + + return () => { + editor.destroy(); + }; + }); + + createEffect(() => { + if (editor) { + editor.dispatch($theme.editorThemeTransaction()); + } + }); + + return ; +}; diff --git a/pkgs/ffigenpad/web/src/components/file-explorer.tsx b/pkgs/ffigenpad/web/src/components/file-explorer.tsx new file mode 100644 index 0000000000..2a55748bc6 --- /dev/null +++ b/pkgs/ffigenpad/web/src/components/file-explorer.tsx @@ -0,0 +1,375 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { basename, dirname, join } from "pathe"; +import { + TbChevronRight, + TbFileDots, + TbFilePlus, + TbFileUpload, + TbFolderPlus, + TbTrash, +} from "solid-icons/tb"; +import { createSignal, For, Show } from "solid-js"; +import { Portal } from "solid-js/web"; +import { HStack, Stack } from "styled-system/jsx"; +import { treeView } from "styled-system/recipes"; +import { $filesystem, type FSNode } from "~/lib/filesystem"; +import { Button } from "third_party/ui/button"; +import { Dialog } from "third_party/ui/dialog"; +import { Drawer } from "third_party/ui/drawer"; +import { Editable } from "third_party/ui/editable"; +import { FileUpload } from "third_party/ui/file-upload"; +import { IconButton } from "third_party/ui/icon-button"; +import { Input } from "third_party/ui/input"; +import * as StyledTreeView from "third_party/ui/styled/tree-view"; +import { Text } from "third_party/ui/text"; + +// need to include recipe to add styles for some reason +treeView(); + +/** + * Displays MemFS files located at /home/web_user as file tree with the ability + * to create, rename, delete files and folders + */ +const FileTree = () => { + const { fileTree, helpers } = $filesystem; + const [_, setSelectedFile] = $filesystem.selectedFile; + + // adds a file with the default name as 'file*.h' + const addFile = (parentPathParts: string[], content = "") => { + // get the contents of the folder where the files is being created + const parentContents = helpers.getNode(parentPathParts) as FSNode; + // find possible default name for new file + let i = 1; + while (`file${i}.h` in parentContents) i++; + const name = `file${i}.h`; + globalThis.FS.writeFile( + join("/home/web_user", ...parentPathParts, name), + content, + ); + }; + + // adds a folder with the default name as 'file*.h' + const addFolder = (parentPathParts: string[]) => { + // get the contents of the parent folder + const parentContents = helpers.getNode(parentPathParts) as FSNode; + // find possible default name for new folder + let i = 1; + while (`folder${i}` in parentContents) i++; + const name = `folder${i}`; + globalThis.FS.mkdir(join("/home/web_user", ...parentPathParts, name)); + }; + + const deleteFile = (filePath: string) => { + globalThis.FS.unlink(join("/home/web_user", filePath)); + }; + + // recursively deleted child files and folders + const deleteFolder = (folderPath: string) => { + // get the contents of the folder being deleted + const contents = globalThis.FS.readdir( + join("/home/web_user", folderPath), + ).slice(2); + // recursively delete all content in the folder so it is empty + for (const node of contents) { + const treeValue = `${folderPath}/${node}`; + const mode = globalThis.FS.stat(join("/home/web_user/", treeValue)).mode; + if (globalThis.FS.isFile(mode)) { + deleteFile(treeValue); + } else if (globalThis.FS.isDir(mode)) { + deleteFolder(treeValue); + } + } + // finally remove the empty folder + globalThis.FS.rmdir(join("/home/web_user", folderPath)); + }; + + // renames a file or a folder + const renameEntity = (oldPath: string, newName: string) => { + globalThis.FS.rename( + join("/home/web_user", oldPath), + join("/home/web_user", dirname(oldPath), newName), + ); + }; + + /** + * + * @param node Object in the fileTree represented as a [key, value] array + * @param parentPathParts array of names of parent nodes + */ + const renderNode = ( + node: [string, FSNode | string], + parentPathParts: string[], + ) => { + const [name, children] = node; + // ensures that all values are relative + const pathParts = + name === "/home/web_user" ? [] : [...parentPathParts, name]; + // it is path relative to /home/web_user in MemFS + const path = pathParts.join("/"); + + return ( + + + renameEntity(path, value)} + > + + + ( + + )} + /> + + + + + deleteFile(path)} + > + + + + } + > + {/* rendered when node is a folder and children is an object */} + + + + + + + renameEntity(path, value)} + > + + + ( + + )} + /> + + + + + addFile(pathParts)} + > + + + addFolder(pathParts)} + > + + + deleteFolder(path)} + > + + + + + + + {(child) => renderNode(child, pathParts)} + + + + + ); + }; + + return ( + { + // only open file in editor if the filename ends with .h + if (selectedValue[0].endsWith(".h")) { + setSelectedFile(`/home/web_user/${selectedValue[0]}`); + } + }} + > + + {/* /home/web_user should be used as the base for the tree */} + + {(child) => renderNode(child, [])} + + + + ); +}; + +/* + * A dialog box to upload multiple files from user at once to a specific directory + */ +function UploadFiles() { + const [files, setFiles] = createSignal([]); + const [directory, setDirectory] = createSignal(""); + const [isLoading, setIsLoading] = createSignal(false); + + async function onConfirm() { + setIsLoading(true); + const directoryParts = directory() + .split("/") + .filter((p) => p.trim() !== ""); + let parentPath = "/home/web_user"; + + for (const folder of directoryParts) { + parentPath = join(parentPath, folder); + globalThis.FS.mkdir(parentPath); + } + + for (const file of files()) { + const filePath = join(parentPath, file.name); + globalThis.FS.writeFile(filePath, ""); + globalThis.FS.writeFile(filePath, await file.text()); + } + setIsLoading(false); + } + + return ( + + ( + + )} + /> + + + + + setFiles(files)} + > + + Drop your header files here + ( + + )} + /> + + + + {(fileUpload) => ( + + {(file) => ( + + + + ( + + + + )} + /> + + )} + + )} + + + + + + /home/web_user/ + setDirectory(e.target.value)} + value={directory()} + /> + + + ( + + )} + /> + + + + + + + ); +} + +/** + * Drawer that handles emscripten's MemFS filesystem as a tree + */ +const FileExplorer = () => { + const [selectedFile] = $filesystem.selectedFile; + return ( + + ( + + )} + /> + + + + + Virtual FileSystem + + tip: double click to rename + + + + + + + + + + + + + ); +}; + +export default FileExplorer; diff --git a/pkgs/ffigenpad/web/src/components/header-editor.tsx b/pkgs/ffigenpad/web/src/components/header-editor.tsx new file mode 100644 index 0000000000..668250a9ea --- /dev/null +++ b/pkgs/ffigenpad/web/src/components/header-editor.tsx @@ -0,0 +1,72 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { cpp } from "@codemirror/lang-cpp"; +import { basicSetup, EditorView } from "codemirror"; +import { createEffect, onMount } from "solid-js"; +import { Box } from "styled-system/jsx"; +import { $filesystem } from "~/lib/filesystem"; +import { $theme, editorThemeConfig } from "~/lib/theme"; + +/** + * Codemirror editor for header files, modifying the file that is currently selected + */ +export const HeaderEditor = () => { + let editorRef: HTMLDivElement; + let editor: EditorView; + + const [selectedFile] = $filesystem.selectedFile; + + /** + * file content of the selected file read from MemFS + */ + const selectedFileContent = () => + globalThis.FS.readFile(selectedFile(), { encoding: "utf8" }); + + onMount(() => { + editor = new EditorView({ + doc: selectedFileContent(), + extensions: [ + basicSetup, + cpp(), + EditorView.domEventHandlers({ + // write to MemFS file on editor blur to prevent frequent updates + blur: (_, view) => { + globalThis.FS.writeFile(selectedFile(), view.state.doc.toString()); + }, + }), + editorThemeConfig.of([$theme.editorTheme()]), + EditorView.theme({ + "&": { + height: "100%", + }, + }), + ], + parent: editorRef!, + }); + + return () => { + editor.destroy(); + }; + }); + + createEffect(() => { + if (editor) { + // update the editor content whenever a new file is selected. + editor.dispatch({ + changes: { + from: 0, + to: editor.state.doc.length, + insert: selectedFileContent(), + }, + }); + } + }); + + createEffect(() => { + if (editor) editor.dispatch($theme.editorThemeTransaction()); + }); + + return ; +}; diff --git a/pkgs/ffigenpad/web/src/components/logs-viewer.tsx b/pkgs/ffigenpad/web/src/components/logs-viewer.tsx new file mode 100644 index 0000000000..4673d60c81 --- /dev/null +++ b/pkgs/ffigenpad/web/src/components/logs-viewer.tsx @@ -0,0 +1,98 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { createSignal, For } from "solid-js"; +import { $logs } from "~/lib/log"; +import { Select } from "third_party/ui/select"; +import { Table } from "third_party/ui/table"; +import { TbSelector } from "solid-icons/tb"; + +/** + * level and label pairs as defined by package:logging in dart + */ +const loggingLevels: [number, string][] = [ + [0, "ALL"], + [3, "FINEST"], + [4, "FINER"], + [5, "FINE"], + [7, "CONFIG"], + [8, "INFO"], + [9, "WARNING"], + [10, "SEVERE"], +]; + +const levelLabelMap = new Map(loggingLevels); + +/** + *Dropdown select to set filter for the logs displayed + */ +const LevelSelect = (props: { + level: number; + onLevelChange: (level: number) => void; +}) => { + return ( + item[0].toString()} + itemToString={(item) => item[1]} + onValueChange={({ value }) => { + props.onLevelChange(parseInt(value[0])); + }} + > + + + + + + + + + + {(item) => ( + + {item[1]} + + )} + + + + + ); +}; + +const LogsViewer = () => { + const [logs] = $logs; + + // set default log level to INFO + const [levelFilter, setLevelFilter] = createSignal(8); + const filteredLogs = () => + logs().filter(({ level }) => level >= levelFilter()); + + return ( + + + + + + + Message + + + + + {(log) => ( + + {levelLabelMap.get(log.level)} + {log.message} + + )} + + + + ); +}; + +export default LogsViewer; diff --git a/pkgs/ffigenpad/web/src/components/navbar.tsx b/pkgs/ffigenpad/web/src/components/navbar.tsx new file mode 100644 index 0000000000..a18d5ecb4b --- /dev/null +++ b/pkgs/ffigenpad/web/src/components/navbar.tsx @@ -0,0 +1,78 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import { TbBrandGithub, TbBug, TbMoon, TbSun } from "solid-icons/tb"; +import { Show } from "solid-js"; +import { Divider, HStack } from "styled-system/jsx"; +import { $theme } from "~/lib/theme"; +import { Badge } from "third_party/ui/badge"; +import { Button } from "third_party/ui/button"; +import { Heading } from "third_party/ui/heading"; +import { IconButton } from "third_party/ui/icon-button"; + +/* + * Button that switches the theme + */ +const ThemeSwitcher = () => { + const [darkMode, setDarkMode] = $theme.darkMode; + + return ( + setDarkMode((x) => !x)} variant="ghost"> + }> + + + + ); +}; + +export const Navbar = () => { + return ( + + + + FFIgenPad + + ffigen 14.0.0-wip + libclang 18.1.8 + + +