Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/swift/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
39 changes: 39 additions & 0 deletions packages/swift/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "OpenUI",
platforms: [
.macOS(.v13),
.iOS(.v16)
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "OpenUILang",
targets: ["OpenUILang"]),
.library(
name: "OpenUISwiftUI",
targets: ["OpenUISwiftUI"]),
.executable(
name: "SwiftUIChat",
targets: ["SwiftUIChat"])
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "OpenUILang"),
.target(
name: "OpenUISwiftUI",
dependencies: ["OpenUILang"]),
.executableTarget(
name: "SwiftUIChat",
dependencies: ["OpenUILang", "OpenUISwiftUI"]),
.testTarget(
name: "OpenUILangTests",
dependencies: ["OpenUILang"])
]
)
40 changes: 40 additions & 0 deletions packages/swift/Sources/OpenUILang/AST.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
public indirect enum ASTNode {
case comp(name: String, args: [ASTNode], mappedProps: [String: ASTNode]?)
case str(String)
case num(Double)
case bool(Bool)
case null
case arr([ASTNode])
case obj([(String, ASTNode)])
case ref(String)
case ph(String)
case stateRef(String)
case runtimeRef(name: String, refType: String)
case binOp(op: String, left: ASTNode, right: ASTNode)
case unaryOp(op: String, operand: ASTNode)
case ternary(cond: ASTNode, then: ASTNode, `else`: ASTNode)
case member(obj: ASTNode, field: String)
case index(obj: ASTNode, index: ASTNode)
case assign(target: String, value: ASTNode)

public var isRuntimeExpr: Bool {
switch self {
case .stateRef, .runtimeRef, .binOp, .unaryOp, .ternary, .member, .index, .assign:
return true
default:
return false
}
}
}

public struct CallNode {
public let callee: String
public let args: [ASTNode]
}

public enum Statement {
case value(id: String, expr: ASTNode)
case state(id: String, initExpr: ASTNode)
case query(id: String, call: CallNode, expr: ASTNode, deps: [String]?)
case mutation(id: String, call: CallNode, expr: ASTNode)
}
55 changes: 55 additions & 0 deletions packages/swift/Sources/OpenUILang/Library.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Foundation

public struct ComponentDef {
public let name: String
public let description: String
public let signature: String
public let params: [String]

public init(name: String, description: String, signature: String) {
self.name = name
self.description = description
self.signature = signature

// Extract parameter names from signature, e.g., "Button(label: String, action: String)" -> ["label", "action"]
// "VStack(children: [Any])" -> ["children"]
var extractedParams: [String] = []
if let startRange = signature.range(of: "("), let endRange = signature.range(of: ")", options: .backwards, range: startRange.upperBound..<signature.endIndex) {
let argsString = String(signature[startRange.upperBound..<endRange.lowerBound])
let args = argsString.split(separator: ",")
for arg in args {
let trimmed = arg.trimmingCharacters(in: .whitespaces)
if let colonRange = trimmed.range(of: ":") {
let paramName = String(trimmed[..<colonRange.lowerBound]).trimmingCharacters(in: .whitespaces)
extractedParams.append(paramName)
} else {
let parts = trimmed.split(separator: " ")
if let first = parts.first {
extractedParams.append(String(first).trimmingCharacters(in: .whitespaces))
}
}
}
}
self.params = extractedParams
}
}

public protocol AnyComponentRenderer {
// In OpenUISwiftUI we will cast this to AnyView
func render(props: [String: Any], children: [Any]) -> Any
}

public class ComponentLibrary {
public private(set) var components: [String: ComponentDef] = [:]
public var root: String?

public init() {}

public func register(component: ComponentDef) {
components[component.name] = component
}

public func setRoot(_ root: String) {
self.root = root
}
}
Loading