public static MultiMethod DefineMultiMethod(Symbol sym, LambdaSignature signature, string doc) { var func = new MultiMethod(signature); sym.FunctionValue = func; sym.Documentation = doc; return(func); }
public ParameterDef(Symbol sym, object specializer = null, Expression initForm = null, Func <object> initFormProc = null, LambdaSignature nestedParameters = null, bool hidden = false) { Sym = sym; Specializer = specializer; NestedParameters = nestedParameters; InitForm = initForm; InitFormProc = initFormProc; Hidden = hidden; if (InitForm != null && InitFormProc == null) { InitFormProc = Runtime.CompileToFunction(initForm); } }
public static Expression FillDataFrame(LambdaSignature signature, DynamicMetaObject[] input, ref BindingRestrictions restrictions) { var elementType = typeof(object); var offset = 0; var output = new List <Expression>(); if (signature.ArgModifier == Symbols.RawParams) { var tail = new List <Expression>(); for (var i = offset; i < input.Length; ++i) { tail.Add(Expression.Convert(input[i].Expression, elementType)); } var tailExpr = Expression.NewArrayInit(elementType, tail); return(tailExpr); } for (offset = 0; offset < signature.RequiredArgsCount; ++offset) { if (offset >= input.Length) { throw new LispException("Missing required parameters"); } output.Add(Expression.Convert(input[offset].Expression, elementType)); } if (offset != signature.Parameters.Count) { var mod = signature.ArgModifier; if (mod == Symbols.Rest || mod == Symbols.Body || mod == Symbols.Params || mod == Symbols.Vector) { var tail = new List <Expression>(); for (var i = offset; i < input.Length; ++i) { tail.Add(Expression.Convert(input[i].Expression, elementType)); } var tailExpr = Expression.NewArrayInit(elementType, tail); if (mod == Symbols.Rest || mod == Symbols.Body) { var conversion = Expression.Call(Runtime.AsListMethod, tailExpr); output.Add(conversion); } else if (mod == Symbols.Params) { output.Add(tailExpr); } else if (mod == Symbols.Vector) { var conversion = Expression.Call(Runtime.AsVectorMethod, tailExpr); output.Add(conversion); } } else if (mod == Symbols.Optional) { for (var i = offset; i < input.Length && i < signature.Parameters.Count; ++i) { output.Add(Expression.Convert(input[i].Expression, elementType)); } for (var i = input.Length; i < signature.Parameters.Count; ++i) { var expr = signature.Parameters[i].InitForm ?? Expression.Constant(null); output.Add(expr); } if (input.Length > signature.Parameters.Count) { throw new LispException("Too many arguments supplied"); } } else if (mod == Symbols.Key) { var firstKey = offset; var usedKeys = 0; for (var i = firstKey; i < input.Length; i += 2) { if (!Runtime.Keywordp(input[i].Value) || i + 1 == input.Length) { throw new LispException("Invalid keyword/value list"); } var keywordRestriction = BindingRestrictions.GetExpressionRestriction(Expression.Equal(input[i].Expression, Expression.Constant(input[i].Value))); restrictions = restrictions.Merge(keywordRestriction); } for (var i = offset; i < signature.Parameters.Count; ++i) { Expression val = null; for (var j = firstKey; j + 1 < input.Length; j += 2) { if (signature.Parameters[i].Sym.Name == ((Symbol)input[j].Value).Name) { val = input[j + 1].Expression; ++usedKeys; break; } } if (val == null) { output.Add(signature.Parameters[i].InitForm ?? Expression.Constant(null)); } else { output.Add(Expression.Convert(val, elementType)); } } } } if (signature.WholeArg != null) { var tail = new List <Expression>(); for (var i = 0; i < input.Length; ++i) { tail.Add(Expression.Convert(input[i].Expression, elementType)); } var tailExpr = Expression.NewArrayInit(elementType, tail); var conversion = Expression.Call(Runtime.AsListMethod, tailExpr); output.Add(conversion); } return(Expression.NewArrayInit(elementType, output)); }
public Exception FillDataFrame(LambdaSignature signature, object[] input, object[] output, int offsetOutput, object env, Cons wholeMacroForm) { var offset = 0; var firstKey = -1; var usedKeys = 0; var haveAll = false; var firstArg = 0; if (signature.Kind != LambdaKind.Macro && signature.RequiredArgsCount > 0) { // This does not work for nested parameters. var n = signature.RequiredArgsCount; if (input.Length < n) { throw new LispException("Missing required parameters"); } Array.Copy(input, 0, output, offsetOutput, n); offsetOutput += n; firstArg = n; offset = n; } for (var iArg = firstArg; !haveAll && iArg < signature.Parameters.Count; ++iArg) { var mod = (iArg < signature.RequiredArgsCount) ? null : signature.ArgModifier; var arg = signature.Parameters[iArg]; object val; if (mod == Symbols.Params) { var buf = new object[input.Length - offset]; Array.Copy(input, offset, buf, 0, buf.Length); val = buf; haveAll = true; } else if (mod == Symbols.Vector) { var v = new Vector(input.Length - offset); for (var i = offset; i < input.Length; ++i) { v.Add(input[i]); } val = v; haveAll = true; } else if (mod == Symbols.Rest || mod == Symbols.Body) { Cons list = null; for (var i = input.Length - 1; i >= offset; --i) { list = new Cons(input[i], list); } val = list; haveAll = true; } else if (mod == Symbols.Key) { if (firstKey == -1) { firstKey = offset; for (var i = firstKey; i < input.Length; i += 2) { if (!Runtime.Keywordp(input[i]) || i + 1 == input.Length) { throw new LispException("Invalid keyword/value list"); } } } val = Runtime.MissingValue; for (var i = firstKey; i + 1 < input.Length; i += 2) { if (arg.Sym.Name == ((Symbol)input[i]).Name) { val = input[i + 1]; ++usedKeys; break; } } } else if (offset < input.Length) { val = input[offset]; ++offset; } else if (mod == Symbols.Optional) { val = Runtime.MissingValue; } else { throw new LispException("Missing required argument: {0}", arg.Sym); } if (val == Runtime.MissingValue) { if (arg.InitFormProc != null) { val = arg.InitFormProc(); } else { val = null; } } if (arg.NestedParameters != null) { // required macro parameter var nestedInput = Runtime.AsArray((IEnumerable)val); FillDataFrame(arg.NestedParameters, nestedInput, output, offsetOutput, env, null); offsetOutput += arg.NestedParameters.Names.Count; } else { output[offsetOutput++] = val; } } if (signature.WholeArg != null) { Cons list = wholeMacroForm; if (list == null) { for (var i = input.Length - 1; i >= 0; --i) { list = new Cons(input[i], list); } } int j = output.Length - 1 - ((signature.EnvArg != null) ? 1 : 0); output[j] = list; haveAll = true; } if (signature.EnvArg != null) { int j = output.Length - 1; output[j] = env; } if (offset < input.Length && !haveAll && firstKey == -1) { throw new LispException("Too many parameters supplied"); } return(null); }
public ParameterDef(Symbol sym, object specializer = null, Expression initForm = null, Func<object> initFormProc = null, LambdaSignature nestedParameters = null, bool hidden = false) { Sym = sym; Specializer = specializer; NestedParameters = nestedParameters; InitForm = initForm; InitFormProc = initFormProc; Hidden = hidden; if (InitForm != null && InitFormProc == null) { InitFormProc = Runtime.CompileToFunction(initForm); } }
public MultiMethod(LambdaSignature signature) { Signature = signature; RequiredArgsCount = signature.RequiredArgsCount; }
public static LambdaSignature CompileFormalArgs(Cons args, AnalysisScope scope, LambdaKind kind) { var signature = new LambdaSignature(kind); signature.ArgModifier = null; bool wantWholeArgName = false; bool wantEnvArgName = false; foreach (object item in ToIter(args)) { if (wantWholeArgName) { signature.WholeArg = (Symbol)item; wantWholeArgName = false; } else if (wantEnvArgName) { signature.EnvArg = (Symbol)item; wantEnvArgName = false; } else if (item is Symbol) { var sym = (Symbol)item; if (sym == Symbols.Whole) { if (kind != LambdaKind.Macro) { throw new LispException("&whole parameter can only be used for a macro"); } wantWholeArgName = true; } else if (sym == Symbols.Environment) { if (kind != LambdaKind.Macro) { throw new LispException("&environment parameter can only be used for a macro"); } wantEnvArgName = true; } else if (sym == Symbols.Optional || sym == Symbols.Key || sym == Symbols.Rest || sym == Symbols.Body || sym == Symbols.Params || sym == Symbols.Vector || sym == Symbols.RawParams) { if (signature.ArgModifier != null) { throw new LispException("Only one modifier can be used: &key, &optional, &rest, &body, &vector, ¶ms or &rawparams"); } signature.ArgModifier = sym; signature.RequiredArgsCount = signature.Parameters.Count; continue; } else { var arg = new ParameterDef(sym); signature.Parameters.Add(arg); signature.Names.Add(sym); } } else if (item is Cons) { var list = (Cons)item; if (signature.ArgModifier == Symbols.Key || signature.ArgModifier == Symbols.Optional) { var sym = (Symbol)First(list); var initForm = Second(list); if (initForm == null) { signature.Parameters.Add(new ParameterDef(sym)); signature.Names.Add(sym); } else { var initForm2 = Compile(initForm, scope); signature.Parameters.Add(new ParameterDef(sym, initForm: initForm2)); signature.Names.Add(sym); } } else if (signature.ArgModifier == null && kind == LambdaKind.Macro) { var nestedArgs = CompileFormalArgs(list, scope, kind); var arg = new ParameterDef(null, nestedParameters: nestedArgs); signature.Parameters.Add(arg); signature.Names.AddRange(nestedArgs.Names); } else if (signature.ArgModifier == null && kind == LambdaKind.Method) { var sym = (Symbol)First(list); var type = Second(list); if (type == null) { var arg = new ParameterDef(sym); signature.Parameters.Add(arg); signature.Names.Add(sym); } else if (type is Cons && First(type) == FindSymbol("lisp:eql")) { // Compile time constants! var expr = Eval(Second(type)); var arg = new ParameterDef(sym, specializer: new EqlSpecializer(expr)); signature.Parameters.Add(arg); signature.Names.Add(sym); } else { if (!Symbolp(type) || Keywordp(type)) { throw new LispException("Invalid type specifier: {0}", type); } var realType = GetType((Symbol)type); var arg = new ParameterDef(sym, specializer: realType); signature.Parameters.Add(arg); signature.Names.Add(sym); } } else { throw new LispException("Invalid CONS in lambda parameter list"); } } } if (signature.ArgModifier == null) { signature.RequiredArgsCount = signature.Parameters.Count; } //if (kind == LambdaKind.Function) { var sym = signature.ArgModifier; if (sym == Symbols.RawParams) { if (signature.Parameters.Count != 1) { throw new LispException("&rawparams: parameter count must be one."); } } else if (sym == Symbols.Rest || sym == Symbols.Body || sym == Symbols.Params || sym == Symbols.Vector) { if (signature.RequiredArgsCount + 1 != signature.Parameters.Count) { throw new LispException("Invalid placement of &rest or similar modifier."); } } } return signature; }
public static Vector GetLambdaArgumentNames(LambdaSignature signature) { var v = new Vector(); for (var i = 0; i < signature.Names.Count; ++i) { if (signature.Names[i] != Symbols.Underscore) { if (i >= signature.Parameters.Count || !signature.Parameters[i].Hidden) { v.Add(signature.Names[i]); } } } if (signature.WholeArg != null) { v.Add(signature.WholeArg); } if (signature.EnvArg != null) { v.Add(signature.EnvArg); } return v; }