Skip to content

Commit

Permalink
Merge pull request #127 from Peefy/feat-swift-lib
Browse files Browse the repository at this point in the history
feat: kcl swift lib
  • Loading branch information
Peefy authored Jul 28, 2024
2 parents 082b057 + e34063c commit 6d56e23
Show file tree
Hide file tree
Showing 17 changed files with 5,060 additions and 1 deletion.
52 changes: 52 additions & 0 deletions .github/workflows/swift-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: swift-test

on:
push:
branches:
- main
- master
tags:
- '*'
pull_request:
branches:
- main
paths:
- "swift/**"
- ".github/workflows/swift-test.yaml"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true

permissions:
contents: read

jobs:
build-and-test:
defaults:
run:
working-directory: "swift"
strategy:
matrix:
os: [macos-12, macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install dependencies
if: "contains(matrix.os, 'ubuntu-latest')"
run: |
sudo apt-get update
sudo apt-get install libgtest-dev ninja-build
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.79
override: true
components: clippy, rustfmt
- name: Setup Swift toolchain
uses: swift-actions/setup-swift@v1
with:
swift-version: 5
- name: Build and run tests
run: make test
3 changes: 2 additions & 1 deletion spec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ run:
protoc spec.proto --python_out ../python/kcl_lib/api
protoc spec.proto --go_out ../go/api
protoc spec.proto --csharp_out ../dotnet/KclLib/api
protoc spec.proto --cpp_out ../cpp/src/api
// brew install swift-protobuf
protoc spec.proto --swift_out=Visibility=Public:../swift/Sources/KclLib
12 changes: 12 additions & 0 deletions swift/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.netrc

/KclLib/.build
/KclLib/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
/KclLib/.swiftpm/config/registries.json
/KclLib/Sources/CKclLib/lib
11 changes: 11 additions & 0 deletions swift/.swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 1,
"lineLength": 100,
"indentation": {
"spaces": 4
},
"maximumBlankLines": 1,
"respectsExistingLineBreaks": true,
"lineBreakBeforeControlFlowKeywords": true,
"lineBreakBeforeEachArgument": true
}
15 changes: 15 additions & 0 deletions swift/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "kcl-lib-c"
version = "0.10.0-alpha.1"
edition = "2021"
publish = false

[lib]
crate-type = ["cdylib", "staticlib"]
doc = false

[build-dependencies]
cbindgen = "0.26.0"

[dependencies]
kclvm-api = { git = "https://github.com/kcl-lang/kcl", version = "0.10.0-alpha.1" }
24 changes: 24 additions & 0 deletions swift/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
INCLUDE_DIR=./Sources/CKclLib/include
LIB_DIR=./Sources/CKclLib/lib

.PHONY: all
all: build

.PHONY: build
build: cargo
swift build

.PHONY: cargo
cargo:
cargo build -r
mkdir -p $(LIB_DIR)
cp ./target/release/libkcl_lib_c.a $(LIB_DIR)

.PHONY: test
test: cargo
swift test

.PHONY: clean
clean:
cargo clean
rm -rf $(LIB_DIR)
14 changes: 14 additions & 0 deletions swift/Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "e17d61f26df0f0e06f58f6977ba05a097a720106",
"version" : "1.27.1"
}
}
],
"version" : 2
}
34 changes: 34 additions & 0 deletions swift/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "KclLib",
products: [
.library(
name: "KclLib",
targets: ["KclLib"]
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.27.0"),
],
targets: [
.systemLibrary(name: "CKclLib"),
.target(
name: "KclLib",
dependencies: [
"CKclLib",
.product(name: "SwiftProtobuf", package: "swift-protobuf")
],
linkerSettings: [
.unsafeFlags(["-L", "Sources/CKclLib/lib"])
]
),
.testTarget(
name: "KclLibTests",
dependencies: ["KclLib"]
),
]
)
29 changes: 29 additions & 0 deletions swift/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# KCL Artifact Library for Swift

This repo is under development, PRs welcome!

## Developing

If you build on macos, you can set the environment to prevent link errors.

**Prerequisites**

+ Swift 5.8+
+ Cargo

```shell
# Set cargo build target on macos
export MACOSX_DEPLOYMENT_TARGET='10.13'
```

**Build**

```shell
make
```

**Test**

```shell
make test
```
21 changes: 21 additions & 0 deletions swift/Sources/CKclLib/include/kcl_lib_c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _KCL_FFI_H
#define _KCL_FFI_H

#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

uintptr_t callNative(const uint8_t *name_ptr,
uintptr_t name_len,
const uint8_t *args_ptr,
uintptr_t args_len,
uint8_t *result_ptr);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif /* _KCL_FFI_H */
6 changes: 6 additions & 0 deletions swift/Sources/CKclLib/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module CKclLib [system] {
header "include/kcl_lib_c.h"
link "kcl_lib_c"

export *
}
112 changes: 112 additions & 0 deletions swift/Sources/KclLib/API.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import Foundation
import SwiftProtobuf
import CKclLib

public class API: Service {
private static let ERROR_PREFIX = "ERROR:"

public init() {}

// Parses a single KCL file and returns its Abstract Syntax Tree (AST) as a JSON string.
public func parseFile(_ args: ParseFile_Args) throws -> ParseFile_Result {
return try ParseFile_Result(serializedBytes: callNative(name: "KclvmService.ParseFile", args: try args.serializedBytes()))
}

// Parses a KCL program and returns the Abstract Syntax Tree (AST) in JSON format.
public func parseProgram(_ args: ParseProgram_Args) throws -> ParseProgram_Result {
return try ParseProgram_Result(serializedBytes: callNative(name: "KclvmService.ParseProgram", args: try args.serializedBytes()))
}

// Loads a KCL package and retrieves AST, symbol, type, and definition information.
public func loadPackage(_ args: LoadPackage_Args) throws -> LoadPackage_Result {
return try LoadPackage_Result(serializedBytes: callNative(name: "KclvmService.LoadPackage", args: try args.serializedBytes()))
}

// Executes a KCL file with provided arguments.
public func execProgram(_ args: ExecProgram_Args) throws -> ExecProgram_Result {
return try ExecProgram_Result(serializedBytes: callNative(name: "KclvmService.ExecProgram", args: try args.serializedBytes()))
}

// Overrides specified elements in a KCL file according to given arguments.
public func overrideFile(_ args: OverrideFile_Args) throws -> OverrideFile_Result {
return try OverrideFile_Result(serializedBytes: callNative(name: "KclvmService.OverrideFile", args: try args.serializedBytes()))
}

// Lists all variables declared in a KCL file.
public func listVariables(_ args: ListVariables_Args) throws -> ListVariables_Result {
return try ListVariables_Result(serializedBytes: callNative(name: "KclvmService.ListVariables", args: try args.serializedBytes()))
}

// Lists all options defined in a KCL program.
public func listOptions(_ args: ParseProgram_Args) throws -> ListOptions_Result {
return try ListOptions_Result(serializedBytes: callNative(name: "KclvmService.ListOptions", args: try args.serializedBytes()))
}

// Retrieves the full schema type mapping for a KCL program.
public func getSchemaTypeMapping(_ args: GetSchemaTypeMapping_Args) throws -> GetSchemaTypeMapping_Result {
return try GetSchemaTypeMapping_Result(serializedBytes: callNative(name: "KclvmService.GetSchemaTypeMapping", args: try args.serializedBytes()))
}

// Formats source code according to KCL style guidelines.
public func formatCode(_ args: FormatCode_Args) throws -> FormatCode_Result {
return try FormatCode_Result(serializedBytes: callNative(name: "KclvmService.FormatCode", args: try args.serializedBytes()))
}

// Formats KCL files or directories to conform to style guidelines.
public func formatPath(_ args: FormatPath_Args) throws -> FormatPath_Result {
return try FormatPath_Result(serializedBytes: callNative(name: "KclvmService.FormatPath", args: try args.serializedBytes()))
}

// Runs linting checks on KCL files and reports errors and warnings.
public func lintPath(_ args: LintPath_Args) throws -> LintPath_Result {
return try LintPath_Result(serializedBytes: callNative(name: "KclvmService.LintPath", args: try args.serializedBytes()))
}

// Validates a data string against a schema defined in a KCL code string.
public func validateCode(_ args: ValidateCode_Args) throws -> ValidateCode_Result {
return try ValidateCode_Result(serializedBytes: callNative(name: "KclvmService.ValidateCode", args: try args.serializedBytes()))
}

// Builds configuration from settings files.
public func loadSettingsFiles(_ args: LoadSettingsFiles_Args) throws -> LoadSettingsFiles_Result {
return try LoadSettingsFiles_Result(serializedBytes: callNative(name: "KclvmService.LoadSettingsFiles", args: try args.serializedBytes()))
}

// Renames symbols across files within a KCL package.
public func rename(_ args: Rename_Args) throws -> Rename_Result {
return try Rename_Result(serializedBytes: callNative(name: "KclvmService.Rename", args: try args.serializedBytes()))
}

// Renames symbols in source code without modifying files directly.
public func renameCode(_ args: RenameCode_Args) throws -> RenameCode_Result {
return try RenameCode_Result(serializedBytes: callNative(name: "KclvmService.RenameCode", args: try args.serializedBytes()))
}

// Executes tests on KCL packages using specified test arguments.
public func test(_ args: Test_Args) throws -> Test_Result {
return try Test_Result(serializedBytes: callNative(name: "KclvmService.Test", args: try args.serializedBytes()))
}

// Updates dependencies for a KCL project based on defined specifications.
public func updateDependencies(_ args: UpdateDependencies_Args) throws -> UpdateDependencies_Result {
return try UpdateDependencies_Result(serializedBytes: callNative(name: "KclvmService.UpdateDependencies", args: try args.serializedBytes()))
}

// Retrieves version information about the KCL service.
public func getVersion(_ args: GetVersion_Args) throws -> GetVersion_Result {
return try GetVersion_Result(serializedBytes: callNative(name: "KclvmService.GetVersion", args: try args.serializedBytes()))
}

private func callNative(name: String, args: Data) -> Data {
// Convert name to byte array
let nameBytes = [UInt8](name.utf8)
var resultBuf = [UInt8](repeating: 0, count: 2048 * 2048)
let resultLength = CKclLib.callNative(nameBytes, UInt(nameBytes.count), [UInt8](args), UInt(args.count), &resultBuf)
let result = Data(bytes: resultBuf, count: Int(resultLength))
let resultString = String(bytes: result, encoding: .utf8) ?? ""
if resultString.isEmpty || !resultString.hasPrefix(API.ERROR_PREFIX) {
return result
}
fatalError(String(resultString.dropFirst(API.ERROR_PREFIX.count)))
}
}
Loading

0 comments on commit 6d56e23

Please sign in to comment.