Commits

Michael Tindal  committed fad3520

Add partial function applications, add custom operators.

  • Participants
  • Parent commits 6f0bc72

Comments (0)

Files changed (15)

File Classes/Core/SVFunction.h

     id defaultValue_;
     BOOL isVarArgs_;
     BOOL isFunction_;
+    BOOL isLiteral_;
     id value_;
     Class type_;
 }
 
 @property (assign) NSUInteger index;
 @property (copy) NSString * name, *selName;
-@property (assign) BOOL hasDefault, isVarArgs, isFunction;
+@property (assign) BOOL hasDefault, isVarArgs, isFunction, isLiteral;
 @property (retain) id defaultValue, value;
 @end
 
 @interface SVFunction : SVBlock {
     @package
     NSMutableArray * arguments_;
+    NSArray * partialArguments_;
     id name_;
     BOOL isCall_;
     BOOL isBridged_;
     BOOL isNative_;
+    BOOL isPartial_;
+    BOOL isBackwardPipe_;
+    BOOL skipPartialCheck_;
     SVNativeFunction * nativeFunc_;
     void * bridgedFunc_;
     NSString * signature_;
 @property (retain) NSMutableArray * arguments;
 @property (retain) id name;
 @property (retain) SVFunction * yieldFunc;
+@property (assign) BOOL isBackwardPipe;
 @end
 
 @interface SVClassFunction : SVFunction {

File Classes/Core/SVFunction.m

 
 - (NSString *) stringValueWithDepth:(NSInteger)d isFunctionArgument:(BOOL)f isInClass:(BOOL)c;
 
-@property (assign) BOOL isCall, isBridged, isNative;
+@property (assign) BOOL isCall, isBridged, isNative, isPartial, skipPartialCheck;
 @property (retain) SVNativeFunction * nativeFunc;
 @property (assign) void * bridgedFunc;
 @property (retain) NSMutableDictionary * lcontext;
+@property (retain) NSArray * partialArguments;
 @end
 
 @implementation SVFunctionArgument
 
 
 @synthesize index = index_, name = name_, selName = selName_, hasDefault = hasDefault_, isVarArgs = isVarArgs_, defaultValue =
-    defaultValue_, value = value_, type = type_, isFunction = isFunction_;
+    defaultValue_, value = value_, type = type_, isFunction = isFunction_, isLiteral = isLiteral_;
 @end
 
 @implementation SVNativeFunction
     self = [super init];
     if (self) {
         self.arguments = args;
+        self.isPartial = YES;
+        for (SVFunctionArgument * arg in self.arguments) {
+            if(arg.name)
+                self.isPartial = NO;
+        }
         self.isCall = YES;
         if ([_name isKindOfClass:[SVSymbol class]]) {
             self.name = [_name to_s];
                                                                                     @"Symbol %@ is not a function (%@)", funcName,
                                                                                     func] userInfo:nil]);
     }
-
+    
+    if (func.isPartial) {
+        NSMutableArray* newArguments = [NSMutableArray arrayWithArray:self.arguments];
+        if (self.isBackwardPipe) {
+            for(int i = 0; i < func.partialArguments.count; i++) {
+                [newArguments addObject:[func.partialArguments objectAtIndex:i]];
+            }
+        } else {
+            for(int i = func.partialArguments.count - 1; i >= 0; i--) {
+                [newArguments insertObject:[func.partialArguments objectAtIndex:i] atIndex:0];
+            }
+        }
+        SVFunction * nf = [SVFunction functionCallWithName:func.name arguments:newArguments];
+        nf.skipPartialCheck = YES;
+        return [nf evaluateWithContext:context];
+    }
+    
+    NSUInteger argc = self.arguments.count;
+    if(self.yieldFunc)
+        argc++;
+    
+    NSUInteger fc = func.arguments.count;
+    for (SVFunctionArgument* xarg in func.arguments) {
+        if(xarg.hasDefault)
+            fc--;
+    }
+    
+    if (!self.skipPartialCheck && (self.isPartial && (argc < fc))) {
+        SVFunction * partialFunction = [SVFunction functionCallWithName:func arguments:nil];
+        partialFunction.partialArguments = self.arguments;
+        partialFunction.isPartial = YES;
+        return partialFunction;
+    }
+    
     if (func.isNative) {
         NSMutableDictionary * _context = [NSMutableDictionary dictionary];
         [_context setObject:context forKey:SV_PARENT_CONTEXT_KEY];
             sym.value = varargs;
             break;
         } else {
-            sym.value = [arg.value evaluateWithContext:context];
+            if(xarg.isLiteral) {
+                if(!([arg.value isKindOfClass:[SVVariable class]] || [arg.value isKindOfClass:[SVSymbol class]])) {
+                    OCLog(@"silver",warning,@"An identifier or symbol must be passed to literal argument.");
+                    return nil;
+                } else {
+                    sym.value = [arg.value isKindOfClass:[SVVariable class]] ? [arg.value varName] : [arg.value name];
+                }
+            } else
+                sym.value = [arg.value evaluateWithContext:context];
         }
     }
 
 @synthesize bridgedFunc = bridgedFunc_;
 @synthesize lcontext = lcontext_;
 @synthesize yieldFunc = yieldFunc_;
+@synthesize isPartial = isPartial_;
+@synthesize partialArguments = partialArguments_;
+@synthesize isBackwardPipe = isBackwardPipe_;
+@synthesize skipPartialCheck = skipPartialCheck_;
 @end
 
 @implementation SVClassFunction

File Classes/Operators/SVControlOperations.m

             _context = [_context objectForKey:SV_PARENT_CONTEXT_KEY];
         } while (!func && _context);
         if (!func) {
+            NSLog(@"No yield function");
             return nil;
         }
     }

File Classes/Parser/SVToken.h

 #define REGEX() NSString* str = STCFRetain(); \
         Parse(context.parser,TK_REGEX,TK_(TK_REGEX,[str substringWithRange:NSMakeRange(2,[str length]-3)]),context);
 #define SYMBOL() Parse(context.parser,TK_SYMBOL,TK(TK_SYMBOL),context);
+#define OP() Parse(context.parser,TK_OP,TK(TK_OP),context);
 
 @interface SVToken : NSObject {
     @private

File Classes/Parser/silver.lemon

 %left LOGICALOR.
 %left LOGICALXOR.
 %left LOGICALAND.
-%left COMPARE EQUAL WHENCOMP WHENNOT NOTEQUAL REGEXMATCH REGEXNOMATCH.
+%left COMPARE EQUAL WHENCOMP WHENNOT NOTEQUAL REGEXMATCH REGEXNOMATCH OP.
 %left LESSTHANEQUAL LESSTHAN GREATERTHAN GREATERTHANEQUAL.
 %right UPLUS UMINUS REF.
 %left BITWISEXOR BITWISEOR.
 arg(A) ::= arg(L) LOGICALOR arg(R). { A = CFRetain([[SVLogicalOrOperator alloc] initWithLeftHandOperand:L rightHandOperand:R]); }
 arg(A) ::= arg(L) LOGICALXOR arg(R). { A = CFRetain([[SVLogicalXorOperator alloc] initWithLeftHandOperand:L rightHandOperand:R]); }
 arg(A) ::= arg(L) FORWARDPIPE arg(R). { A = CFRetain([SVFunction functionCallWithName:R arguments:[NSMutableArray arrayWithObject:[SVFunctionArgument argumentWithName:nil value:L]]]); }
-arg(A) ::= arg(L) BACKWARDPIPE arg(R). { A = CFRetain([SVFunction functionCallWithName:L arguments:[NSMutableArray arrayWithObject:[SVFunctionArgument argumentWithName:nil value:R]]]); }
+arg(A) ::= arg(L) BACKWARDPIPE arg(R). { 
+    SVFunction* func = CFRetain([SVFunction functionCallWithName:L arguments:[NSMutableArray arrayWithObject:[SVFunctionArgument argumentWithName:nil value:R]]]);
+    func.isBackwardPipe = YES;
+    A = func;
+}
+arg(A) ::= arg(L) OP(O) arg(R). { O_(L,R,[O tokenData],A); }
 arg(A) ::= DEFINED IDENTIFIER(I). { A = CFRetain([SVDefinedStatement statementWithVariable:[I tokenData]]); }
 arg(A) ::= DEFINED LPAREN IDENTIFIER(I) RPAREN. { A = CFRetain([SVDefinedStatement statementWithVariable:[I tokenData]]); }
 arg(A) ::= DEFINED symbol(S). { A = CFRetain([SVDefinedStatement statementWithVariable:[S to_s]]); }
     arg.defaultValue = E;
     D = CFRetain(arg);
 }
+darg(D) ::= COLON IDENTIFIER(I). {
+    SVFunctionArgument * arg = [SVFunctionArgument argumentWithName:[I tokenData]];
+    arg.isLiteral = YES;
+    D = CFRetain(arg);
+}
 
 literal(L) ::= NUMBER(N). { L = CFRetain([N tokenData]); }
 literal(L) ::= STRING(S). { L = CFRetain([SVCreateStringStatement statementWithString:[S tokenData]]); }
 fname(F) ::= UMINUS. { F = CFRetain(@"-@"); }
 fname(F) ::= BRACKETS. { F = CFRetain(@"[]"); }
 fname(F) ::= BRACKETSASSIGN. { F = CFRetain(@"[]="); }
+fname(F) ::= OP(O). { F = CFRetain([O tokenData]); }

File Classes/Parser/silver.rl

 
     # regular expression string
     '%/' . [^/]* . '/' { REGEX() };
-    no_regex_char = '/' | newline;
-    '/' . ^no_regex_char* . '/' { REGEX() };
+
+    ('+' | '-' | '=' | '!' | '~' | '<' | '>' | '&' | '|' | '^' | '%' | '*' | '/' | '@' | '?')+ { OP() };
 
     '@selector(' { SB; fgoto selector; };
 

File Tests/SVAccessTests.m

     P(var);
     assertThat(var,is(equalTo(expect)));
 }
+
+-(void) testNegativeIndex {
+    PC(@"[1,2,3][-1];");
+    P(var);
+    assertThat(var,is(equalTo(N(3))));
+}
+
+-(void) testIndexRange {
+    NSArray * expect = [NSArray arrayWithObjects:@"to",@"you",nil];
+    PC(@"['hello','to','you'][1..2];");
+    P(var);
+    assertThat(var,is(equalTo(expect)));
+}
 @end

File Tests/SVClassSystemTests.m

     
     P(var);
     NSNumber* num = N(20);
+    
     var = [num sub:N(10)];
     assertThat(var,is(equalTo(N(10))));
 }
 }
 
 -(void) testTask {
-    PC(@"class Task { def initWithName(name,action:act) { @name = name; @action = act; self; }; def execute(*args) { args = flatten(args); for(dep in @deps) { args = Tasks[dep.to_s].execute(args); }; @action(args); }; };"
+    PC(@"class Task { def initWithName(name,action:act) { @name = name; @action = act; self; }; def execute(*args) { args = flatten(args); for(dep in @deps) { args = Tasks[dep].execute(args); }; @action(args); }; };"
         "Tasks = {};"
         "def task(__x,&body) {"
         "  name='';deps=[];"
         "    name = __x.allKeys[0];"
         "    deps = __x[name];"
         "    if(!deps.is?(:NSArray)) { deps = [deps]; };"
-        "    name = name.to_s if name.is?(:SVSymbol);"
         "  } else {"
         "    name = __x;"
-        "    name = name.to_s if name.is?(:SVSymbol);"
         "  };"
         "  t = Task.alloc.initWithName(name,action:body);"
         "  t.deps = deps if deps;"
         "  args[0] *= 2;"
         "  args;"
         "};"
-        "x = Tasks[:multiply2.to_s].execute(10)[0];"
+        "x = Tasks[:multiply2].execute(10)[0];"
         "x;"
        );
     P(var);

File Tests/SVFlowTests.m

 }
 
 -(void) testSwitchRegex1 {
-    PC(@"str = 'Hello world'; switch(str) { case /el+/: { 10; } case /blah/: { 20; } };");
+    PC(@"str = 'Hello world'; switch(str) { case %/el+/: { 10; } case %/blah/: { 20; } };");
     P(var);
     assertThat(var,is(equalTo(N(10))));
 }
 
 -(void) testSwitchRegex2 {
-    PC(@"str = 'Hello world'; switch(str) { case /blah/: { 10; } case /el+/: { 20; } };");
+    PC(@"str = 'Hello world'; switch(str) { case %/blah/: { 10; } case %/el+/: { 20; } };");
     P(var);
     assertThat(var,is(equalTo(N(20))));
 }
 
 -(void) testSwitchRegexDefault {
-    PC(@"str = 'Hello world'; switch(sr) { case /blah/: { 10; } case /foo/: { 20; } default: { 30; } };");
+    PC(@"str = 'Hello world'; switch(sr) { case %/blah/: { 10; } case %/foo/: { 20; } default: { 30; } };");
     P(var);
     assertThat(var,is(equalTo(N(30))));
 }

File Tests/SVFunctionTests.m

 -(void) testForeachDefined {
     PC(@"def foreach(__d,&body) {" 
         "   var = __d.allKeys[0];" 
-        "   arr = __d[var];" 
-        "   var = var.to_s if var.is?(:SVSymbol);" 
+        "   arr = __d[var];"
         "   for(i = 0; i < arr.count; i+=1) {" 
         "       eval('#{var} = arr[i]; body();');" 
         "   };" 
     
     assertThat(var,is(equalTo(N(6))));
 }
-@end
+
+-(void) testPartialFunctionCall {
+    PC(@"def add(x,y) { return x + y; }; add1 = add(1); [add1(1),add1(2),add1(3)];");
+    P(var);
+    
+    assertThat(var,is(equalTo([NSArray arrayWithObjects:N(2),N(3),N(4),nil])));
+}
+
+-(void) testPartialFunctionCallForward {
+    PC(@"def add(x,y) { return x + y; }; add1 = add(1); [1 |> add1,2 |> add1,3 |> add1];");
+    P(var);
+    
+    assertThat(var,is(equalTo([NSArray arrayWithObjects:N(2),N(3),N(4),nil])));
+}
+
+-(void) testPartialFunctionCallBackward {
+    PC(@"def div(x,y) { return y / x; }; div20 = div(20); [div20 <| 2,div20 <| 5,div20 <| 10];");
+    P(var);
+    
+    assertThat(var,is(equalTo([NSArray arrayWithObjects:N(10),N(4),N(2),nil])));
+}
+@end

File Tests/SVOperatorTests.m

     P(var);
     assertThat(var,is(equalTo(BL(YES))));
 }
+
+- (void) testCustomOp {
+    PC(@"class NSNumber { def <==>(other) { return (self + other) / (other/2); }; }; 8 <==> 8;");
+    P(var);
+    assertThat(var,is(equalTo(N(4))));
+}
 @end

File Tests/SVVariableTests.m

 
 -(void) testParallelAssignmentWildcardOnlyRhs {
     NSArray* expect = [NSArray arrayWithObjects:N(1),N(2),N(3),nil];
-    PC(@"pb=[1,2,3]; pa,pb,pc=*pb;");
+    PC(@"pb=[1,2,3]; pa,pb,pc = *pb;");
     P(var);
     assertThat(var,is(equalTo(expect)));
 }
 
 -(void) testParallelAssignmentWildcardRhsAtEnd {
     NSArray *expect = [NSArray arrayWithObjects:N(1),N(2),N(3),nil];
-    PC(@"pb=[2,3];pa,pb,pc=1,*pb;");
+    PC(@"pb=[2,3];pa,pb,pc = 1,*pb;");
     P(var);
     assertThat(var,is(equalTo(expect)));
 }
 
 -(void) testParallelAssignmentWildcardRhsInMiddle {
     NSArray *expect = [NSArray arrayWithObjects:N(1),N(2),N(3),N(4),nil];
-    PC(@"pb=[2,3];pa,pb,pc,pd=1,*pb,4;");
+    PC(@"pb=[2,3];pa,pb,pc,pd = 1,*pb,4;");
     P(var);
     assertThat(var,is(equalTo(expect)));
 }
 
 -(void) testParallelAssignmentWildcardLhsRhs {
     NSArray *expect = [NSArray arrayWithObjects:N(1),N(2),N(3),nil];
-    PC(@"pb=[1,2,3];*pa=*pb;");
+    PC(@"pb=[1,2,3];*pa = *pb;");
     P(var);
     assertThat(var,is(equalTo(expect)));
 }

File scripts/core.sv

     }
 
     def [](i) {
-        return self.objectAtIndex(i)
+        if(i.is?(:NSArray)) {
+            ret = [];
+            for(x = 0; x < i.count; x+=1) {
+                ret << self.objectAtIndex(i[x]);
+            };
+            return ret;
+        } else if(i >= 0) {
+            return self.objectAtIndex(i)
+        } else {
+            return self.objectAtIndex(self.count + i);
+        };
     }
 
     def []=(i,v) {
         return self.objectForKey(k)
     }
 
+    def k(i) {
+        return self.allKeys[i]
+    }
+
     def []=(k,v) {
         self.setObject(v,forKey:k)
         return self.objectForKey(k)
     }
 }
+

File scripts/ext.sv

 
 def isNode?(n) { return n.isKindOfClass(SVNode.class); };
 
-def eval(n) { def node(s) { SVNode.createNodeFromSource(s); }; b = node(n); return b.evaluateWithContext($:); };
+def eval(n) { nslog(n); def node(s) { SVNode.createNodeFromSource(s); }; b = node(n); return b.evaluateWithContext($:); };

File tools/sv/smelt/tasks/compilation.sv

         }; 
     };
     @m_objects = {};
-    @arch.each: { |architecture| @m_objects[architecture] = []; };
-    @m_files.each: { |sourceName| @arch.each: { |architecture|
+    @arch.each { |architecture| @m_objects[architecture] = []; };
+    @m_files.each { |sourceName| @arch.each: { |architecture|
         objectName = @"build/#{architecture}";
         objectName << sourceName.fileName.stringByReplacingPathExtensionWith('o');
         @m_objects[architecture] << objectName;