Browse Source

Add auto converting for export values, add string(chinese:english:) and string(english:chinese:)

xcbosa-itx 2 years ago
parent
commit
4c132f31f5

BIN
.DS_Store


+ 1 - 0
TestApp/zh-Hans.lproj/LaunchScreen.strings

@@ -0,0 +1 @@
+

+ 5 - 0
XCTreeLang.xcodeproj/project.pbxproj

@@ -141,6 +141,7 @@
 		7520C4572A283CCC0010E7F8 /* TestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TestApp.entitlements; sourceTree = "<group>"; };
 		7543DAF22A52C6EE00958AAA /* XCTLArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLArray.swift; sourceTree = "<group>"; };
 		7543DAF42A52C89200958AAA /* XCTLTypeMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLTypeMapper.swift; sourceTree = "<group>"; };
+		7543DAF62A52F92200958AAA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
 		756916862A2851DF005FF14B /* XCTLStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLStream.swift; sourceTree = "<group>"; };
 		756916882A286A90005FF14B /* XCTLSetStatement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLSetStatement.swift; sourceTree = "<group>"; };
 		7569168D2A2896FE005FF14B /* XCTLReturnStatement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLReturnStatement.swift; sourceTree = "<group>"; };
@@ -490,6 +491,7 @@
 			knownRegions = (
 				en,
 				Base,
+				"zh-Hans",
 			);
 			mainGroup = 7520C3D02A283AFC0010E7F8;
 			productRefGroup = 7520C3DB2A283AFC0010E7F8 /* Products */;
@@ -607,6 +609,7 @@
 			isa = PBXVariantGroup;
 			children = (
 				7520C44F2A283CA80010E7F8 /* Base */,
+				7543DAF62A52F92200958AAA /* zh-Hans */,
 			);
 			name = LaunchScreen.storyboard;
 			sourceTree = "<group>";
@@ -618,6 +621,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@@ -681,6 +685,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";

BIN
XCTreeLang.xcodeproj/project.xcworkspace/xcuserdata/xcbosa.xcuserdatad/UserInterfaceState.xcuserstate


+ 49 - 1
XCTreeLang/Runtime/XCTLRuntimeContext.swift

@@ -50,6 +50,40 @@ internal class XCTLRuntimeContext: XCTLRuntimeAbstractContext {
             }
             return .void
         }), forName: "string:")
+        self.setValue(XCTLRuntimeVariable(funcImpl: {
+            if $0.count == 2,
+               let s1 = $0.first,
+               let s2 = $0.last {
+                if s1.type != .typeString {
+                    return XCTLRuntimeVariable(type: .typeString, rawValue: NSLocalizedString(s1.stringValue, comment: ""))
+                }
+                if s2.type != .typeString {
+                    return XCTLRuntimeVariable(type: .typeString, rawValue: NSLocalizedString(s2.stringValue, comment: ""))
+                }
+                if NSLocale.preferredLanguages.first?.hasPrefix("zh") ?? false || NSLocale.preferredLanguages.first?.hasPrefix("ch") ?? false {
+                    return s2
+                }
+                return s1
+            }
+            return .void
+        }), forNames: "stringWithEnglish:chinese:", "stringWithEn:ch:")
+        self.setValue(XCTLRuntimeVariable(funcImpl: {
+            if $0.count == 2,
+               let s1 = $0.first,
+               let s2 = $0.last {
+                if s1.type != .typeString {
+                    return XCTLRuntimeVariable(type: .typeString, rawValue: NSLocalizedString(s1.stringValue, comment: ""))
+                }
+                if s2.type != .typeString {
+                    return XCTLRuntimeVariable(type: .typeString, rawValue: NSLocalizedString(s2.stringValue, comment: ""))
+                }
+                if NSLocale.preferredLanguages.first?.hasPrefix("zh") ?? false || NSLocale.preferredLanguages.first?.hasPrefix("ch") ?? false {
+                    return s1
+                }
+                return s2
+            }
+            return .void
+        }), forNames: "stringWithChinese:english:", "stringWithCh:en:")
         self.setValue(XCTLRuntimeVariable(funcImpl: {
             fatalError($0.first?.stringValue ?? "fatalError from XCT")
         }), forName: "appFatalError:")
@@ -206,7 +240,21 @@ internal class XCTLRuntimeContext: XCTLRuntimeAbstractContext {
     
     internal func applyNativeObjectMutations() {
         for it in self.nativeObjectMutations {
-            self.nativeObjectInstance.setValue(it.1, forKey: it.0)
+            let name = it.0
+            let value = it.1
+            guard let property = class_getProperty(self.nativeObjectInstance.classForCoder, name),
+                  let propertyAttributes = property_getAttributes(property),
+                  let propertyAttributes = NSString(cString: propertyAttributes, encoding: String.Encoding.utf8.rawValue) as? String else {
+                print("[XCTLWarning] The export name \(name) does not match a valid @property in nativeInstance, did the property use static callable such as Swift? Use setValueForKey.")
+                self.nativeObjectInstance.setValue(value.nativeValue, forKey: name)
+                continue
+            }
+            do {
+                let value = try value.nativeValue(typeId: propertyAttributes[propertyAttributes.index(after: propertyAttributes.startIndex)])
+                self.nativeObjectInstance.setValue(value, forKey: name)
+            } catch let err {
+                fatalError("[XCTLEngine] \(err)")
+            }
         }
     }
     

+ 83 - 0
XCTreeLang/Runtime/XCTLRuntimeVariable.swift

@@ -120,6 +120,89 @@ public class XCTLRuntimeVariable: NSObject {
         }
     }
     
+    public func nativeValue(typeId: Character) throws -> Any {
+        switch typeId {
+        case "i":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return Int32(nativeValue)
+        case "I":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return UInt32(nativeValue)
+        case "s":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return Int16(nativeValue)
+        case "S":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return UInt16(nativeValue)
+        case "f":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return Float(nativeValue)
+        case "d":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return nativeValue
+        case "l":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return Int64(nativeValue)
+        case "L":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return UInt64(nativeValue)
+        case "q":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return Int64(nativeValue)
+        case "Q":
+            guard let nativeValue = self.nativeValue as? Double else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return UInt64(nativeValue)
+        case "c":
+            guard let nativeValue = self.nativeValue as? Double else {
+                guard let nativeValue = self.nativeValue as? String else {
+                    throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+                }
+                return Int8((nativeValue.first ?? " ").utf8.first!)
+            }
+            return Int8(nativeValue)
+        case "C":
+            guard let nativeValue = self.nativeValue as? Double else {
+                guard let nativeValue = self.nativeValue as? String else {
+                    throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+                }
+                return UInt8((nativeValue.first ?? " ").utf8.first!)
+            }
+            return UInt8(nativeValue)
+        case "b":
+            guard let nativeValue = self.nativeValue as? Bool else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return nativeValue
+        case "@":
+            guard let nativeValue = self.nativeValue as? NSObject else {
+                throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: typeId.description, nativeType: self.type.rawValue)
+            }
+            return nativeValue
+        default:
+            throw XCTLRuntimeError.cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: "\(typeId) (Unknown TypeId)", nativeType: self.type.rawValue)
+        }
+    }
+    
     public func executeFunc(arg: [XCTLRuntimeVariable]) throws -> XCTLRuntimeVariable {
         return try self.rawFunction!(arg)
     }

+ 4 - 0
XCTreeLang/XCTLRuntimeError.swift

@@ -35,6 +35,8 @@ public enum XCTLRuntimeError: Error, CustomStringConvertible, CustomNSError {
     
     case invalidReferencingObject
     
+    case cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: String, nativeType: String)
+    
     public var description: String {
         switch self {
         case .importUnknownMember(variableName: let variableName):
@@ -71,6 +73,8 @@ public enum XCTLRuntimeError: Error, CustomStringConvertible, CustomNSError {
             return "callingTypeEncodingError"
         case .invalidReferencingObject:
             return "invalidReferencingObject"
+        case .cannotCastObjectToNativeTypeWhenSetProperty(runtimeType: let type, nativeType: let ntype):
+            return "cannotCastObjectToNativeTypeWhenSetProperty: \(type) to \(ntype)"
         }
     }