Sfoglia il codice sorgente

WIP: Add runtime class

xcbosa mbp16 2 anni fa
parent
commit
a99746c83f

+ 42 - 0
XCTreeLang.xcodeproj/project.pbxproj

@@ -54,6 +54,11 @@
 		756916952A28C622005FF14B /* XCTLForStatement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756916942A28C622005FF14B /* XCTLForStatement.swift */; };
 		756916972A28DFE7005FF14B /* XCTLBreakStatement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756916962A28DFE7005FF14B /* XCTLBreakStatement.swift */; };
 		756916992A28E1D9005FF14B /* XCTLContinueStatement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756916982A28E1D9005FF14B /* XCTLContinueStatement.swift */; };
+		7569169C2A28ED2E005FF14B /* XCTLRuntimeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7569169B2A28ED2E005FF14B /* XCTLRuntimeType.swift */; };
+		756916A12A28FE20005FF14B /* XCTLRuntimeTypeInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = 7569169F2A28FE20005FF14B /* XCTLRuntimeTypeInstance.h */; };
+		756916A22A28FE20005FF14B /* XCTLRuntimeTypeInstance.m in Sources */ = {isa = PBXBuildFile; fileRef = 756916A02A28FE20005FF14B /* XCTLRuntimeTypeInstance.m */; };
+		756916A52A28FF05005FF14B /* module.modulemap in Sources */ = {isa = PBXBuildFile; fileRef = 756916A42A28FF05005FF14B /* module.modulemap */; };
+		756916A72A28FF3D005FF14B /* module.modulemap in Sources */ = {isa = PBXBuildFile; fileRef = 756916A62A28FF3D005FF14B /* module.modulemap */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -132,6 +137,11 @@
 		756916942A28C622005FF14B /* XCTLForStatement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLForStatement.swift; sourceTree = "<group>"; };
 		756916962A28DFE7005FF14B /* XCTLBreakStatement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLBreakStatement.swift; sourceTree = "<group>"; };
 		756916982A28E1D9005FF14B /* XCTLContinueStatement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLContinueStatement.swift; sourceTree = "<group>"; };
+		7569169B2A28ED2E005FF14B /* XCTLRuntimeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTLRuntimeType.swift; sourceTree = "<group>"; };
+		7569169F2A28FE20005FF14B /* XCTLRuntimeTypeInstance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XCTLRuntimeTypeInstance.h; sourceTree = "<group>"; };
+		756916A02A28FE20005FF14B /* XCTLRuntimeTypeInstance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XCTLRuntimeTypeInstance.m; sourceTree = "<group>"; };
+		756916A42A28FF05005FF14B /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
+		756916A62A28FF3D005FF14B /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -185,6 +195,7 @@
 				7520C40C2A283B1E0010E7F8 /* XCTLRuntimeError.swift */,
 				7520C4162A283B1E0010E7F8 /* XCTLEngine.swift */,
 				7520C40B2A283B1E0010E7F8 /* XCTLGenerateProtocol.swift */,
+				756916A62A28FF3D005FF14B /* module.modulemap */,
 			);
 			path = XCTreeLang;
 			sourceTree = "<group>";
@@ -240,6 +251,7 @@
 		7520C40D2A283B1E0010E7F8 /* Runtime */ = {
 			isa = PBXGroup;
 			children = (
+				7569169A2A28ED20005FF14B /* Type */,
 				7520C40E2A283B1E0010E7F8 /* XCTLRuntimeVariable.swift */,
 				7520C40F2A283B1E0010E7F8 /* XCTLRuntimeSubContext.swift */,
 				7520C4102A283B1E0010E7F8 /* XCTLRuntimeVariableType.swift */,
@@ -290,6 +302,25 @@
 			path = NativeTypes;
 			sourceTree = "<group>";
 		};
+		7569169A2A28ED20005FF14B /* Type */ = {
+			isa = PBXGroup;
+			children = (
+				756916A82A28FFD8005FF14B /* Instance */,
+				7569169B2A28ED2E005FF14B /* XCTLRuntimeType.swift */,
+			);
+			path = Type;
+			sourceTree = "<group>";
+		};
+		756916A82A28FFD8005FF14B /* Instance */ = {
+			isa = PBXGroup;
+			children = (
+				7569169F2A28FE20005FF14B /* XCTLRuntimeTypeInstance.h */,
+				756916A02A28FE20005FF14B /* XCTLRuntimeTypeInstance.m */,
+				756916A42A28FF05005FF14B /* module.modulemap */,
+			);
+			path = Instance;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -298,6 +329,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				7520C3E92A283AFC0010E7F8 /* XCTreeLang.h in Headers */,
+				756916A12A28FE20005FF14B /* XCTLRuntimeTypeInstance.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -404,6 +436,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				7520C42B2A283B1E0010E7F8 /* XCTLElseStatement.swift in Sources */,
+				7569169C2A28ED2E005FF14B /* XCTLRuntimeType.swift in Sources */,
 				7520C4212A283B1E0010E7F8 /* XCTLNextthanStatement.swift in Sources */,
 				7520C4342A283B1E0010E7F8 /* XCTLRuntimeAbstractContext.swift in Sources */,
 				7520C4352A283B1E0010E7F8 /* XCTLRuntimeContext.swift in Sources */,
@@ -424,6 +457,7 @@
 				7520C42D2A283B1E0010E7F8 /* XCTLListStatement.swift in Sources */,
 				7520C4222A283B1E0010E7F8 /* XCTLInitStatement.swift in Sources */,
 				756916872A2851DF005FF14B /* XCTLStream.swift in Sources */,
+				756916A22A28FE20005FF14B /* XCTLRuntimeTypeInstance.m in Sources */,
 				7520C41E2A283B1E0010E7F8 /* XCTLImmediateStatement.swift in Sources */,
 				756916892A286A90005FF14B /* XCTLSetStatement.swift in Sources */,
 				756916972A28DFE7005FF14B /* XCTLBreakStatement.swift in Sources */,
@@ -434,6 +468,8 @@
 				7520C4202A283B1E0010E7F8 /* XCTLRootStatement.swift in Sources */,
 				756916932A28C4B6005FF14B /* XCTLRange.swift in Sources */,
 				7520C42A2A283B1E0010E7F8 /* XCTLMorethanStatement.swift in Sources */,
+				756916A52A28FF05005FF14B /* module.modulemap in Sources */,
+				756916A72A28FF3D005FF14B /* module.modulemap in Sources */,
 				7520C4292A283B1E0010E7F8 /* XCTLEqualthanStatement.swift in Sources */,
 				7569168E2A2896FE005FF14B /* XCTLReturnStatement.swift in Sources */,
 				7520C4192A283B1E0010E7F8 /* XCTLCompileTimeError.swift in Sources */,
@@ -617,6 +653,7 @@
 					"@executable_path/Frameworks",
 					"@loader_path/Frameworks",
 				);
+				MACH_O_TYPE = mh_dylib;
 				MARKETING_VERSION = 1.0;
 				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
 				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20";
@@ -624,6 +661,8 @@
 				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
 				SKIP_INSTALL = YES;
 				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_INCLUDE_PATHS = "$(SRCROOT)/XCTreeLang/Runtime/Type/Instance";
+				SWIFT_OBJC_BRIDGING_HEADER = "";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2";
@@ -650,6 +689,7 @@
 					"@executable_path/Frameworks",
 					"@loader_path/Frameworks",
 				);
+				MACH_O_TYPE = mh_dylib;
 				MARKETING_VERSION = 1.0;
 				MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
 				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20";
@@ -657,6 +697,8 @@
 				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
 				SKIP_INSTALL = YES;
 				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_INCLUDE_PATHS = "$(SRCROOT)/XCTreeLang/Runtime/Type/Instance";
+				SWIFT_OBJC_BRIDGING_HEADER = "";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};

+ 2 - 0
XCTreeLang/Lex/XCTLLexer.swift

@@ -88,6 +88,8 @@ internal class XCTLLexer {
                 return XCTLToken(type: .typeBreak, rawValue: buffer)
             case "continue":
                 return XCTLToken(type: .typeContinue, rawValue: buffer)
+            case "class":
+                return XCTLToken(type: .typeClass, rawValue: buffer)
             default:
                 return XCTLToken(type: .typeIdentifier, rawValue: buffer)
             }

+ 1 - 0
XCTreeLang/Lex/XCTLTokenType.swift

@@ -54,5 +54,6 @@ internal enum XCTLTokenType: String {
     case typeIn
     case typeBreak
     case typeContinue
+    case typeClass
     
 }

+ 20 - 0
XCTreeLang/Runtime/Type/Instance/XCTLRuntimeTypeInstance.h

@@ -0,0 +1,20 @@
+//
+//  XCTLRuntimeTypeInstance.h
+//  XCTreeLang
+//
+//  Created by 邢铖 on 2023/6/2.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface XCTLRuntimeTypeInstance : NSObject
+
++ (instancetype)makeNativeUseMetaType:(id)metaType runtimeContext:(id)context;
+
+- (id)metaTypeForSelf;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 167 - 0
XCTreeLang/Runtime/Type/Instance/XCTLRuntimeTypeInstance.m

@@ -0,0 +1,167 @@
+//
+//  XCTLRuntimeTypeInstance.m
+//  XCTreeLang
+//
+//  Created by 邢铖 on 2023/6/2.
+//
+
+#import "XCTLRuntimeTypeInstance.h"
+#import <XCTreeLang/XCTreeLang-Swift.h>
+
+extern const int methodIMPSlotCnt;
+extern const IMP methodIMPSlotR[9];
+extern const char methodIMPSoltRType[9][20];
+extern id variableGetterMethodIMP(id self, SEL aSelector);
+extern void variableSetterMethodIMP(id self, SEL aSelector, id newValue);
+
+@interface XCTLRuntimeTypeInstance ()
+
+@property (nonatomic, assign) BOOL alreadyMakeNativeType;
+
+@property (nonatomic, weak) XCTLRuntimeType *metaType;
+@property (nonatomic, strong) id runtimeContext;
+@property (nonatomic, copy) NSArray<XCTLRuntimeFunctionDef *> *runtimeFuncDefs;
+@property (nonatomic, copy) NSDictionary<NSString *, NSString *> *runtimeTypeNameWithClasses;
+
+@property (nonatomic, strong) NSMutableDictionary<NSString *, NSObject *> *runtimeVariables;
+@property (nonatomic, assign) Class klass;
+
+@end
+
+@implementation XCTLRuntimeTypeInstance
+
++ (instancetype)makeNativeUseMetaType:(id)metaType runtimeContext:(id)context {
+    XCTLRuntimeType *meta = metaType;
+    Class klass = objc_duplicateClass(self.class,
+                                      [[meta.runtimeClassName stringByAppendingFormat:@"_Sub_%p", self] cStringUsingEncoding:NSUTF8StringEncoding],
+                                      0);
+    XCTLRuntimeTypeInstance *instance = class_createInstance(klass, 0);
+    instance = [instance initWithMetaType:meta
+                        andRuntimeContext:context
+                               onSubClass:klass];
+    [instance makeNativeType];
+    return instance;
+}
+
+- (instancetype)initWithMetaType:(XCTLRuntimeType *)metaType
+               andRuntimeContext:(id)context
+                      onSubClass:(Class)klass {
+    self = [super init];
+    self.metaType = metaType;
+    self.runtimeContext = context;
+    self.klass = klass;
+    return self;
+}
+
+- (NSMutableDictionary<NSString *,NSObject *> *)runtimeVariables {
+    if (!_runtimeVariables) {
+        _runtimeVariables = [NSMutableDictionary new];
+    }
+    return _runtimeVariables;
+}
+
+- (id)metaTypeForSelf {
+    return self.metaType;
+}
+
+- (void)makeNativeType {
+    if (self.alreadyMakeNativeType) {
+        return;
+    }
+    self.alreadyMakeNativeType = true;
+    
+    self.runtimeTypeNameWithClasses = [self.metaType makeVariableTable];
+    for (NSString *key in self.runtimeTypeNameWithClasses) {
+        self.runtimeVariables[key] = NSNull.null;
+        class_addMethod(self.klass,
+                        NSSelectorFromString(key),
+                        (IMP)variableGetterMethodIMP,
+                        "@@:");
+    }
+    
+    self.runtimeFuncDefs = [self.metaType makeRuntimeFuncDef];
+    for (XCTLRuntimeFunctionDef *def in self.runtimeFuncDefs) {
+        if (def.argumentCount > methodIMPSlotCnt - 1) {
+            NSLog(@"Can not create native function for %@: %ld arguments, max %d", def.selector, (long)def.argumentCount, methodIMPSlotCnt - 1);
+        }
+        class_addMethod(self.klass,
+                        NSSelectorFromString(def.selector),
+                        methodIMPSlotR[def.argumentCount],
+                        methodIMPSoltRType[def.argumentCount]);
+    }
+}
+
+- (BOOL)respondsToSelector:(SEL)aSelector {
+    NSString *selector = NSStringFromSelector(aSelector);
+    for (XCTLRuntimeFunctionDef *def in self.runtimeFuncDefs) {
+        if ([def.selector isEqualToString:selector]) {
+            return true;
+        }
+    }
+    return false;
+}
+
+- (id)valueForKey:(NSString *)key {
+    NSObject *anyObject = self.runtimeVariables[key];
+    if (anyObject == nil) {
+        return [super valueForKey:key];
+    }
+    return anyObject;
+}
+
+@end
+
+id variableGetterMethodIMP(id self, SEL aSelector) {
+    return NSNull.null;
+}
+
+void variableSetterMethodIMP(id self, SEL aSelector, id newValue) {
+    return;
+}
+
+static id methodIMPSlot0R(id self, SEL aSelector) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot1R(id self, SEL aSelector, id obj0) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot2R(id self, SEL aSelector, id obj0, id obj1) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot3R(id self, SEL aSelector, id obj0, id obj1, id obj2) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot4R(id self, SEL aSelector, id obj0, id obj1, id obj2, id obj3) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot5R(id self, SEL aSelector, id obj0, id obj1, id obj2, id obj3, id obj4) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot6R(id self, SEL aSelector, id obj0, id obj1, id obj2, id obj3, id obj4, id obj5) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot7R(id self, SEL aSelector, id obj0, id obj1, id obj2, id obj3, id obj4, id obj5, id obj6) {
+    return NSNull.null;
+}
+
+static id methodIMPSlot8R(id self, SEL aSelector, id obj0, id obj1, id obj2, id obj3, id obj4, id obj5, id obj6, id obj7) {
+    return NSNull.null;
+}
+    
+const int methodIMPSlotCnt = 9;
+
+const IMP methodIMPSlotR[methodIMPSlotCnt] = {
+    (IMP)methodIMPSlot0R, (IMP)methodIMPSlot1R, (IMP)methodIMPSlot2R, (IMP)methodIMPSlot3R, (IMP)methodIMPSlot4R,
+    (IMP)methodIMPSlot5R, (IMP)methodIMPSlot6R, (IMP)methodIMPSlot7R, (IMP)methodIMPSlot8R
+};
+
+const char methodIMPSoltRType[methodIMPSlotCnt][20] = {
+    "@@:", "@@:@", "@@:@@", "@@:@@@", "@@:@@@@", "@@:@@@@@", "@@:@@@@@@", "@@:@@@@@@@", "@@:@@@@@@@@"
+};

+ 4 - 0
XCTreeLang/Runtime/Type/Instance/module.modulemap

@@ -0,0 +1,4 @@
+module XCTLRuntimeTypeInstanceModule {
+    header "XCTLRuntimeTypeInstance.h"
+    export *
+}

+ 81 - 0
XCTreeLang/Runtime/Type/XCTLRuntimeType.swift

@@ -0,0 +1,81 @@
+//
+//  XCTLRuntimeType.swift
+//  XCTreeLang
+//
+//  Created by 邢铖 on 2023/6/1.
+//
+
+import Foundation
+import XCTLRuntimeTypeInstanceModule
+
+@objcMembers
+public class XCTLRuntimeFunctionDef: NSObject {
+    public var selector: String
+    public var argumentCount: Int
+    
+    public init(selector: String, argumentCount: Int) {
+        self.selector = selector
+        self.argumentCount = argumentCount
+    }
+}
+
+@objcMembers
+public class XCTLRuntimeType: NSObject {
+    
+    private var variableNameWithTypeTable = [String : String]()
+    private var paragraphTable = [String : XCTLParagraphStatement]()
+    private let klassName: String
+    
+    internal init(variableNameWithTypeTable: [String : String] = [String : String](), paragraphTable: [String : XCTLParagraphStatement] = [String : XCTLParagraphStatement](), className: String) {
+        self.variableNameWithTypeTable = variableNameWithTypeTable
+        self.paragraphTable = paragraphTable
+        self.klassName = className
+    }
+    
+    public func addVariable(name: String, type: String) throws {
+        if self.variableNameWithTypeTable.keys.contains(type) {
+            throw XCTLCompileTimeError.duplicatedMemberVariable(name: type)
+        }
+        self.variableNameWithTypeTable[name] = type
+    }
+    
+    internal func addParagraph(name: String, paragraph: XCTLParagraphStatement) throws {
+        if self.paragraphTable.keys.contains(name) {
+            throw XCTLCompileTimeError.duplicatedMemberParagraph(name: name)
+        }
+        self.paragraphTable[name] = paragraph
+    }
+    
+    internal func invokeParagraph(_ name: String,
+                                  forInstance instance: XCTLRuntimeTypeInstance,
+                                  inContext context: XCTLRuntimeAbstractContext,
+                                  withArgs args: [XCTLRuntimeVariable]) throws -> XCTLRuntimeVariable {
+        guard let paragraph = self.paragraphTable[name] else {
+            throw XCTLRuntimeError.unknownMethodForName(name: name)
+        }
+        var args = args
+        args.insert(XCTLRuntimeVariable(rawObject: instance), at: 0)
+        return try paragraph.doRealEvaluate(inContext: context, withArgs: args)
+    }
+    
+    public func makeRuntimeFuncDef() -> [XCTLRuntimeFunctionDef] {
+        var defs = [XCTLRuntimeFunctionDef]()
+        for it in self.paragraphTable {
+            defs.append(XCTLRuntimeFunctionDef(selector: it.key, argumentCount: it.value.argumentIdList.count))
+        }
+        return defs
+    }
+    
+    public func makeVariableTable() -> [String : String] {
+        return self.variableNameWithTypeTable
+    }
+    
+    public func runtimeClassName() -> String {
+        return self.klassName
+    }
+    
+    public func invokeParagraph(_ name: String, forInstance: XCTLRuntimeTypeInstance, inContext: Any, withArgs args: [NSObject]) {
+        
+    }
+    
+}

+ 3 - 0
XCTreeLang/XCTLCompileTimeError.swift

@@ -17,4 +17,7 @@ public enum XCTLCompileTimeError: Error {
     case unexpectParentStatementType(expect: String, butGot: String)
     case tooMuchParagraphDefinitionForName(name: String)
     
+    case duplicatedMemberVariable(name: String)
+    case duplicatedMemberParagraph(name: String)
+    
 }

+ 1 - 0
XCTreeLang/XCTLRuntimeError.swift

@@ -25,6 +25,7 @@ public enum XCTLRuntimeError: Error {
     case invalidListFrame
     
     case variableNotImplementProtocol(protocolName: String)
+    case unknownMethodForName(name: String)
     
 }
 

+ 3 - 0
XCTreeLang/module.modulemap

@@ -0,0 +1,3 @@
+framework module XCTreeLang {
+   export *
+}