private object InvokeMethodSymbol(MethodSymbol method, List<Ast> args) { // create a new memory scope. this is where arguments will get defined // we wont overwrite any memory values since they will all be local here MemorySpaces.CreateScope(); var count = 0; if (method.MethodDeclr.Arguments.Count != args.Count) { throw new InvalidSyntax(String.Format("Wrong number of arguments passed to method {0}. Got {1}, expected {2}", method.MethodDeclr.MethodName.Token.TokenValue, args.Count, method.MethodDeclr.Arguments.Count)); } foreach (VarDeclrAst expectedArgument in method.MethodDeclr.Arguments) { var currentArgument = args[count]; var oldmemory = MemorySpaces.Current; // if the argument is coming from somewhere else, make sure to be able to // load the argument from its preferred space. if (currentArgument.CallingMemory != null) { MemorySpaces.Current = currentArgument.CallingMemory; } var value = GetValue(Exec(currentArgument)); // since we were just loading values from the argument space // switch back to the current space so we can assign the argument value // into our local working memory MemorySpaces.Current = oldmemory; if (expectedArgument.VariableValue == null) { MemorySpaces.Current.Define(expectedArgument.Token.TokenValue, value); } else { MemorySpaces.Current.Assign(expectedArgument.Token.TokenValue, value); } // if the passed in argument is a word and not a literal (like string or bool) then // pull its value from memory so we can match type to the target type var resolvedSymbol = (currentArgument.Token.TokenType == TokenType.Word ? MemorySpaces.Current.Get(currentArgument.Token.TokenValue) : args[count]) as Symbol; var resolvedType = resolvedSymbol != null ? resolvedSymbol.Type : currentArgument.AstSymbolType; if (currentArgument is MethodDeclr) { resolvedType = new BuiltInType(ExpressionTypes.Method); } if (!TokenUtil.EqualOrPromotable(expectedArgument.AstSymbolType, resolvedType)) { throw new InvalidSyntax(String.Format("Cannot pass argument {0} of type {1} to function {2} as argument {3} of type {4}", currentArgument.Token.TokenValue, currentArgument.AstSymbolType.TypeName, method.MethodDeclr.MethodName.Token.TokenValue, expectedArgument.VariableName.Token.TokenValue, expectedArgument.AstSymbolType.TypeName)); } count++; } var val = Exec(method.MethodDeclr.Body); MemorySpaces.PopScope(); return val; }
private void VariableDeclaration(VarDeclrAst varDeclrAst) { if (varDeclrAst.VariableValue == null) { var symbol = varDeclrAst.CurrentScope.Resolve(varDeclrAst.VariableName.Token.TokenValue); var space = MemorySpaces.Current; space.Define(symbol.Name, TokenType.Nil); return; } var variableValue = varDeclrAst.VariableValue.ConvertedExpression ?? varDeclrAst.VariableValue; // if the rhs of a variable is not a method, then execute it, if (variableValue.AstType != AstTypes.MethodDeclr) { var value = GetValue(Exec(variableValue)); if (value != null) { var symbol = varDeclrAst.CurrentScope.Resolve(varDeclrAst.VariableName.Token.TokenValue); var space = MemorySpaces.Current; if (variableValue.IsLink) { space.Link(symbol.Name, variableValue.Token.TokenValue); } else { space.Define(symbol.Name, value); } } } else { var symbol = varDeclrAst.CurrentScope.Resolve(varDeclrAst.VariableName.Token.TokenValue); var resolvedMethod = varDeclrAst.CurrentScope.Resolve(variableValue.Token.TokenValue) as MethodSymbol; // make sure to create a NEW method symbol. this way each time we declare this item // it will create a local copy and get its own memory space for closures. // if we shared the same method symbol then all instances of the same declaration would share the memory space, // which may not be what we want given class instances having their own spaces var localMethodCopy = new MethodSymbol(resolvedMethod.Name, resolvedMethod.Type, resolvedMethod.MethodDeclr); var space = MemorySpaces.Current; if (variableValue is LambdaDeclr) { localMethodCopy.Environment = space; } space.Define(symbol.Name, localMethodCopy); } }
private LambdaDeclr CreateCurriedMethod(FuncInvoke ast, MethodSymbol functionType) { var srcMethod = functionType.MethodDeclr; var fixedAssignments = new List<VarDeclrAst>(); var count = 0; foreach (var argValue in ast.Arguments) { var srcArg = srcMethod.Arguments[count] as VarDeclrAst; var token = new Token(srcArg.DeclarationType.Token.TokenType, argValue.Token.TokenValue); var declr = new VarDeclrAst(token, srcArg.Token, new Expr(argValue.Token)); // if we're creating a curry using a variable then we need to resolve the variable type // otherwise we can make a symbol for the literal var newArgType = argValue.Token.TokenType == TokenType.Word ? ast.CurrentScope.Resolve(argValue).Type : ScopeUtil.CreateSymbolType(argValue); // create a symbol type for the target we're invoking on so we can do type checking var targetArgType = ScopeUtil.CreateSymbolType(srcArg.DeclarationType); if (!TokenUtil.EqualOrPromotable(newArgType, targetArgType)) { throw new InvalidSyntax(String.Format("Cannot pass argument {0} of type {1} to partial function {2} as argument {3} of type {4}", argValue.Token.TokenValue, newArgType.TypeName, srcMethod.MethodName.Token.TokenValue, srcArg.VariableName.Token.TokenValue, targetArgType.TypeName)); } fixedAssignments.Add(declr); count++; } var newBody = fixedAssignments.Concat(srcMethod.Body.ScopedStatements).ToList(); var curriedMethod = new LambdaDeclr(srcMethod.Arguments.Skip(ast.Arguments.Count).ToList(), new ScopeDeclr(newBody)); SetScope(curriedMethod); return curriedMethod; }