diff --git a/appinventor/schemekit/src/SCMProcedure.h b/appinventor/schemekit/src/SCMProcedure.h index 2970090370..a30c41cbf9 100644 --- a/appinventor/schemekit/src/SCMProcedure.h +++ b/appinventor/schemekit/src/SCMProcedure.h @@ -16,6 +16,11 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithProcedure:(pic_value)procedure interpreter:(SCMInterpreter *)interpreter; - (nullable id)invoke; - (nullable id)invokeWithArguments:(NSArray * _Nonnull)arguments; +- (NSInteger)numberOfArguments; +- (BOOL)variadic; + +@property(readonly) NSInteger numberOfArguments; +@property(readonly) BOOL variadic; @end diff --git a/appinventor/schemekit/src/SCMProcedure.m b/appinventor/schemekit/src/SCMProcedure.m index 70d4d20e26..d0a6e16eab 100644 --- a/appinventor/schemekit/src/SCMProcedure.m +++ b/appinventor/schemekit/src/SCMProcedure.m @@ -4,6 +4,9 @@ // http://www.apache.org/licenses/LICENSE-2.0 #import "SCMProcedure.h" +#import "picrin.h" +#include "picrin/private/object.h" +#include "picrin/private/vm.h" #import "SCMInterpreter-Private.h" @interface SCMProcedure () { @@ -90,4 +93,20 @@ - (nonnull id)copyWithZone:(nullable NSZone *)zone { return [interpreter_ apply:self.value to:arguments]; } +- (NSInteger)numberOfArguments { + if (pic_type(interpreter_.state, value_) == PIC_TYPE_IREP) { + struct proc *proc = pic_proc_ptr(interpreter_.state, value_); + return (NSInteger) proc->u.i.irep->argc - 1; + } + return 0; +} + +- (BOOL)variadic { + if (pic_type(interpreter_.state, value_) == PIC_TYPE_IREP) { + struct proc *proc = pic_proc_ptr(interpreter_.state, value_); + return proc->u.i.irep->varg; + } + return NO; +} + @end diff --git a/appinventor/schemekit/tests/SCMProcedureTests.m b/appinventor/schemekit/tests/SCMProcedureTests.m index f60ef5c84b..72bc0d0604 100644 --- a/appinventor/schemekit/tests/SCMProcedureTests.m +++ b/appinventor/schemekit/tests/SCMProcedureTests.m @@ -40,4 +40,22 @@ - (void)testApplyWithArgs { XCTAssertEqual(4, result.intValue); } +- (void)testNumArgs { + [interpreter evalForm:@"(yail:invoke *test-environment* 'setObject:forKey: (lambda (x y) (+ x y)) \"proc3\")"]; + XCTAssertNil(interpreter.exception); + SCMProcedure *proc = (SCMProcedure *) env[@"proc3"]; + XCTAssertNotNil(proc); + XCTAssertEqual(2, proc.numberOfArguments); + XCTAssertFalse(proc.variadic); +} + +- (void)testVariadic { + [interpreter evalForm:@"(yail:invoke *test-environment* 'setObject:forKey: (lambda (x y . z) #f) \"proc4\")"]; + XCTAssertNil(interpreter.exception); + SCMProcedure *proc = (SCMProcedure *) env[@"proc4"]; + XCTAssertNotNil(proc); + XCTAssertEqual(2, proc.numberOfArguments); + XCTAssertTrue([proc variadic]); +} + @end