protected void Add(string name, IBoundDecl arg, IBoundDecl returnType, Func<Value[], Value> func) { int id = mFunctions.Count; var foreignFunction = new ForeignFunction(name, id, arg, returnType); mFunctions[id] = new KeyValuePair<ForeignFunction, Func<Value[], Value>>(foreignFunction, func); }
public ICallable Instantiate(BindingContext context, IEnumerable <IBoundDecl> typeArgs, IBoundDecl argType) { bool dummy; Struct.BuildContext(context, ParameterType, argType, ref typeArgs, out dummy); // bail if we couldn't get the right number of type arguments if ((typeArgs == null) || (Struct.TypeParameters.Count != typeArgs.Count())) { return(null); } // instantiate the structure var structure = Struct.Instantiate(context.Compiler, typeArgs); // now build the auto functions for it ICallable instantiated = null; foreach (ICallable function in structure.BuildFunctions()) { // add to the symbol table so they are only instantiated once context.Compiler.Functions.Add(function); if ((Name == function.Name) && function.GetType().Equals(FunctionType)) { instantiated = function; } } return(instantiated); }
private static IUnboundExpr Match(BindingContext context, IBoundDecl decl, IPattern caseExpr, IUnboundExpr value, IDictionary <string, IUnboundExpr> variables) { var matcher = new PatternMatcher(context, decl, value, caseExpr, variables); return(caseExpr.Accept(matcher)); }
/// <summary> /// Infers the types of the given collection of named type arguments from the given collection /// of parameters. /// </summary> /// <param name="typeArgNames">The names of the type parameters.</param> /// <param name="parameters"></param> /// <returns></returns> public static IList <IBoundDecl> Infer(IEnumerable <string> typeParameters, IUnboundDecl parameterType, IBoundDecl argType) { var inferrer = new TypeArgInferrer(typeParameters); inferrer.mParamTypes.Push(parameterType); bool dummy = argType.Accept(inferrer); inferrer.mParamTypes.Pop(); // if the inference failed (like from a type collision) then fail if (inferrer.mFailed) { return(null); } // if any type argument is left unfilled then fail if (inferrer.mTypeArguments.Contains(null)) { return(null); } return(inferrer.mTypeArguments); }
public static string UniqueName(string name, IEnumerable<IBoundDecl> typeArgs, IBoundDecl paramType) { string typeArgString = ((typeArgs != null) && typeArgs.Any()) ? "[" + typeArgs.JoinAll(", ") + "]" : ""; return name + " " + typeArgString + paramType.ToString(); }
public ICallable Instantiate(BindingContext context, IEnumerable <IBoundDecl> typeArgs, IBoundDecl argType) { // should have three args: an int, an array, and a value var argTuple = argType as BoundTupleType; if (argTuple == null) { return(null); } // index if (argTuple.Fields[0] != Decl.Int) { return(null); } // array var arrayType = argTuple.Fields[1] as BoundArrayType; if (arrayType == null) { return(null); } // value if (!DeclComparer.TypesMatch(argTuple.Fields[2], arrayType.ElementType)) { return(null); } // make the intrinsic return(new Intrinsic("__Call<-", OpCode.StoreArray, FuncType.Create(argTuple, Decl.Unit))); }
IBoundExpr IUnboundExprVisitor<IBoundExpr>.Visit(FuncRefExpr expr) { IBoundDecl paramType = null; if (expr.ParamType != null) { paramType = TypeBinder.Bind(mContext, expr.ParamType); } var callable = mContext.Compiler.Functions.Find(mContext, expr.Name.Name, expr.Name.TypeArgs, paramType); var function = callable as Function; //### bob: to support intrinsics, we'll need to basically create wrapper functions // that have the same type signature as the intrinsic and that do nothing but // call the intrinsic and return. then, we can get a reference to that wrapper. // // to support foreign functions, we can either do the same thing, or change the // way function references work. if a function reference can be distinguished // between being a regular function, a foreign one (or later a closure), then // we can get rid of ForeignFuncCallExpr and just use CallExpr for foreign calls // too. if (function == null) throw new NotImplementedException("Can only get references to user-defined functions. Intrinsics, auto-generated, and foreign function references aren't supported yet."); return new BoundFuncRefExpr(function); }
public BindingContext BuildContext(BindingContext callingContext, IUnboundDecl parameterType, IBoundDecl argType, ref IEnumerable <IBoundDecl> typeArgs, out bool canInferArgs) { // try to infer the args if not passed in IList <IBoundDecl> inferredTypeArgs = TypeArgInferrer.Infer(TypeParameters, parameterType, argType); canInferArgs = inferredTypeArgs != null; if (canInferArgs) { typeArgs = inferredTypeArgs; } if (typeArgs.IsEmpty()) { typeArgs = null; } // include the open namespaces of the calling context. this was the instantiated // generic has access to everything that the instantiation call site has access // to var searchSpace = new NameSearchSpace(BaseType.SearchSpace, callingContext.SearchSpace); return(new BindingContext(callingContext.Compiler, searchSpace, TypeParameters, typeArgs)); }
public ICallable Instantiate(BindingContext context, IEnumerable <IBoundDecl> typeArgs, IBoundDecl argType) { // should have two args: an int and an array var argTuple = argType as BoundTupleType; if (argTuple == null) { return(null); } if (argTuple.Fields[0] != Decl.Int) { return(null); } var arrayType = argTuple.Fields[1] as BoundArrayType; if (arrayType == null) { return(null); } // make the intrinsic return(new Intrinsic("__Call", OpCode.LoadArray, FuncType.Create(argTuple, arrayType.ElementType))); }
protected void Add(string name, IBoundDecl arg, IBoundDecl returnType, Func <Value[], Value> func) { int id = mFunctions.Count; var foreignFunction = new ForeignFunction(name, id, arg, returnType); mFunctions[id] = new KeyValuePair <ForeignFunction, Func <Value[], Value> >(foreignFunction, func); }
public static string UniqueName(string name, IEnumerable <IBoundDecl> typeArgs, IBoundDecl paramType) { string typeArgString = ((typeArgs != null) && typeArgs.Any()) ? "[" + typeArgs.JoinAll(", ") + "]" : ""; return(name + " " + typeArgString + paramType.ToString()); }
public static void Validate(MatchExpr expr, IBoundDecl valueType) { foreach (var matchCase in expr.Cases) { var usedVariables = new Dictionary <string, bool>(); matchCase.Pattern.Accept(new ShapeChecker(valueType, usedVariables)); } }
private PatternMatcher(BindingContext context, IBoundDecl decl, IUnboundExpr value, IPattern caseExpr, IDictionary <string, IUnboundExpr> variables) { mContext = context; mDecl = decl; mValue = value; mVariables = variables; mC = new CodeBuilder(context.NameGenerator, caseExpr.Position); }
/// <summary> /// Creates a new bound declaration. /// </summary> public Decl(IBoundDecl bound) { if (bound == null) { throw new ArgumentNullException("bound"); } Bound = bound; }
/// <summary> /// Defines a local variable with the given name and type. /// </summary> /// <param name="name">Variable name.</param> /// <param name="type">Variable type.</param> /// <param name="isMutable"><c>true</c> if the variable is mutable.</param> public void Define(string name, IBoundDecl type, bool isMutable) { mStruct.Define(name, type); mVariableMutability[name] = isMutable; // track the highwater mNumVariables = Math.Max(mNumVariables, mStruct.Fields.Count); }
private Coverage(IBoundDecl matchType) { mMatchType = matchType; // since unit has exactly one value, if we've got a coverage for it // at all, it's fully covered. this handles union cases where the // value type is unit. the presence of the union case at all means // it's fully-covered. if (mMatchType == Decl.Unit) { FullyCovered = true; } }
public ICallable Instantiate(BindingContext context, IEnumerable <IBoundDecl> typeArgs, IBoundDecl argType) { var arrayType = argType as BoundArrayType; if (arrayType == null) { return(null); } // make the intrinsic return(new Intrinsic("Size", OpCode.SizeArray, FuncType.Create(arrayType, Decl.Int))); }
private bool TryFind(string name, IEnumerable <IBoundDecl> typeArguments, IBoundDecl paramType, out ICallable bound) { string uniqueName = Callable.UniqueName(name, typeArguments, paramType); // look up by unique name if (mCallables.TryGetValue(uniqueName, out bound)) { return(true); } // wasn't found return(false); }
protected Definition(Position position, string name, IEnumerable<IBoundDecl> typeArgs) { Position = position; mName = name; if (typeArgs == null) { TypeArguments = new IBoundDecl[0]; } else { TypeArguments = typeArgs.ToArray(); } }
public LoadExpr(IBoundExpr structure, IBoundDecl type, int index) { if (structure == null) { throw new ArgumentNullException("structure"); } if (type == null) { throw new ArgumentNullException("type"); } Struct = structure; Type = type; Index = index; }
private ICallable LookUpFunction(BindingContext context, string fullName, IList <IUnboundDecl> typeArgs, IBoundDecl argType) { // with this line uncommented, the "InferredGenericUsesExplicitType" test // passes, but the self-hosting compiler doesn't compile. the line after // the next will get the compiler to break at a different point (earlier? // later?), but breaks the test // the first line is newer and (i think) correct. the old line is what it was // doing before. var boundTypeArgs = TypeBinder.Bind(context, typeArgs); //var boundTypeArgs = TypeBinder.Bind(new BindingContext(context.Compiler, context.SearchSpace), typeArgs); string uniqueName = Callable.UniqueName(fullName, boundTypeArgs, argType); // try the already bound functions ICallable callable; if (TryFind(fullName, boundTypeArgs, argType, out callable)) { return(callable); } // try to instantiate a generic foreach (var generic in mGenerics) { // names must match if (generic.Name != fullName) { continue; } ICallable instance = generic.Instantiate(context, boundTypeArgs, argType); //### bob: there's a bug here. it doesn't check that the *unique* names of the two functions // match, just the base names. i think this means it could incorrectly collide: // List'Int () // List'Bool () // but i'm not positive if (instance != null) { return(instance); } } // couldn't find it return(null); }
public FuncType(Position position, IBoundDecl parameter, IBoundDecl returnType) { if (parameter == null) { throw new ArgumentNullException("parameter"); } if (returnType == null) { throw new ArgumentNullException("returnType"); } Position = position; Parameter = new Decl(parameter); Return = new Decl(returnType); }
public static bool TypesMatch(IBoundDecl parameter, IBoundDecl argument) { // if they're the same object, they must match if (ReferenceEquals(parameter, argument)) return true; // if they're different types, they can't match if (!parameter.GetType().Equals(argument.GetType())) return false; // types that return false here do so because if they did match, // the above ReferenceEquals check should have been true. since // we got here, they must not match. return parameter.Match( atomic => false, array => TypesMatch(array.ElementType, ((BoundArrayType)argument).ElementType), func => { var argFunc = (FuncType)argument; return TypesMatch(func.Parameter.Bound, argFunc.Parameter.Bound) && TypesMatch(func.Return.Bound, argFunc.Return.Bound); }, record => { var argRecord = (BoundRecordType)argument; if (record.Fields.Count != argRecord.Fields.Count) return false; // fields must match foreach (var pair in record.Fields.Zip(argRecord.Fields)) { if (pair.Item1.Key != pair.Item2.Key) return false; if (!TypesMatch(pair.Item1.Value, pair.Item2.Value)) return false; } return true; }, tuple => { var argTuple = (BoundTupleType)argument; if (tuple.Fields.Count != argTuple.Fields.Count) return false; // fields must match return tuple.Fields.Zip(argTuple.Fields).All(TypesMatch); }, structType => false, union => false, foreign => foreign.Name == ((ForeignType)argument).Name); }
public static void Validate(MatchExpr expr, IBoundDecl valueType) { var coverage = new Coverage(valueType); foreach (var matchCase in expr.Cases) { if (coverage.CoverPattern(matchCase.Pattern)) { throw new CompileException(matchCase.Position, "This pattern will never be matched because previous patterns cover it."); } } // make sure the cases are exhaustive if (!coverage.FullyCovered) { throw new CompileException(expr.Position, "Not all possible values will be matched."); } }
public static IBoundDecl[] Expand(this IBoundDecl decl) { // the unit type expands to no values if (ReferenceEquals(decl, Decl.Unit)) { return(new IBoundDecl[0]); } // a tuple expands to its fields BoundTupleType tuple = decl as BoundTupleType; if (tuple != null) { return(tuple.Fields.ToArray()); } // everything else expands to just itself return(new IBoundDecl[] { decl }); }
/// <summary> /// Looks for a function with the given name in all of the currently used namespaces. /// </summary> public ICallable Find(BindingContext context, string name, IList <IUnboundDecl> typeArgs, IBoundDecl argType) { //### bob: eventually, this should also do koenig lookup to search in the // namespaces available to the arguments of the function // see: http://en.wikipedia.org/wiki/Argument_dependent_name_lookup foreach (var potentialName in context.SearchSpace.SearchFor(name)) { var bound = LookUpFunction(context, potentialName, typeArgs, argType); if (bound != null) { return(bound); } } // not found return(null); }
public ICallable Instantiate(BindingContext context, IEnumerable <IBoundDecl> typeArgs, IBoundDecl argType) { bool canInfer; var genericContext = BuildContext(context, BaseType.Type.Parameter.Unbound, argType, ref typeArgs, out canInfer); // bail if we couldn't get the right number of type arguments if ((typeArgs == null) || (TypeParameters.Count != typeArgs.Count())) { return(null); } // create a new bound function type with the type arguments applied FuncType funcType = BaseType.Type.CloneFunc(); TypeBinder.Bind(genericContext, funcType); // make sure the concrete argument types of this instance match what we're actually given if (!DeclComparer.TypesMatch(funcType.Parameter.Bound, argType)) { return(null); } // create a new unbound function with the proper type Function instance = new Function(BaseType.Position, BaseType.BaseName, funcType, BaseType.ParamNames, BaseType.Body.Unbound, typeArgs, canInfer); instance.BindSearchSpace(BaseType.SearchSpace); // don't instantiate it multiple times // note that this must happen *before* the function is bound, in case the // newly instantiated generic function is recursive. context.Compiler.Functions.Add(instance); // bind it with the type arguments in context FunctionBinder.Bind(genericContext, instance); return(instance); }
private bool TryInferParam(IBoundDecl argType) { // see if the parameter type on top of the stack is a generic type NamedType named = ParamType as NamedType; if (named == null) { return(false); } // see if the named type is a generic type (instead of an actual concrete named type) int typeParamIndex = mTypeParamNames.IndexOf(named.Name); if (typeParamIndex == -1) { return(false); } // it is, so infer it from the arg if (mTypeArguments[typeParamIndex] == null) { // first time inferring the arg mTypeArguments[typeParamIndex] = argType; } else { // already inferred, make sure it matches if (!DeclComparer.TypesMatch(mTypeArguments[typeParamIndex], argType)) { // can't infer the same type parameter to multiple different types // example: Foo'A (a A, b A) // Foo (123, "string") mFailed = true; } } return(true); }
/// <summary> /// Looks for a function with the given name in all of the currently used namespaces. /// </summary> public ICallable Find(BindingContext context, string name, IList<IUnboundDecl> typeArgs, IBoundDecl argType) { //### bob: eventually, this should also do koenig lookup to search in the // namespaces available to the arguments of the function // see: http://en.wikipedia.org/wiki/Argument_dependent_name_lookup foreach (var potentialName in context.SearchSpace.SearchFor(name)) { var bound = LookUpFunction(context, potentialName, typeArgs, argType); if (bound != null) return bound; } // not found return null; }
public static T Match <T>(this IBoundDecl decl, Func <AtomicDecl, T> atomicCallback, Func <BoundArrayType, T> arrayCallback, Func <FuncType, T> funcCallback, Func <BoundRecordType, T> recordCallback, Func <BoundTupleType, T> tupleCallback, Func <Struct, T> structCallback, Func <Union, T> unionCallback, Func <ForeignType, T> foreignCallback) { if (decl == null) { throw new ArgumentNullException("decl"); } var atomic = decl as AtomicDecl; if (atomic != null) { return(atomicCallback(atomic)); } var array = decl as BoundArrayType; if (array != null) { return(arrayCallback(array)); } var func = decl as FuncType; if (func != null) { return(funcCallback(func)); } var record = decl as BoundRecordType; if (record != null) { return(recordCallback(record)); } var tuple = decl as BoundTupleType; if (tuple != null) { return(tupleCallback(tuple)); } var structType = decl as Struct; if (structType != null) { return(structCallback(structType)); } var union = decl as Union; if (union != null) { return(unionCallback(union)); } var foreign = decl as ForeignType; if (foreign != null) { return(foreignCallback(foreign)); } throw new ArgumentException("Unknown declaration type."); }
public ICallable Instantiate(BindingContext context, IEnumerable<IBoundDecl> typeArgs, IBoundDecl argType) { // should have three args: an int, an array, and a value var argTuple = argType as BoundTupleType; if (argTuple == null) return null; // index if (argTuple.Fields[0] != Decl.Int) return null; // array var arrayType = argTuple.Fields[1] as BoundArrayType; if (arrayType == null) return null; // value if (!DeclComparer.TypesMatch(argTuple.Fields[2], arrayType.ElementType)) return null; // make the intrinsic return new Intrinsic("__Call<-", OpCode.StoreArray, FuncType.Create(argTuple, Decl.Unit)); }
public BoundArrayType(IBoundDecl elementType) { ElementType = elementType; }
private bool TryFind(string name, IEnumerable<IBoundDecl> typeArguments, IBoundDecl paramType, out ICallable bound) { string uniqueName = Callable.UniqueName(name, typeArguments, paramType); // look up by unique name if (mCallables.TryGetValue(uniqueName, out bound)) return true; // wasn't found return false; }
/// <summary> /// Creates a new bound declaration. /// </summary> public Decl(IBoundDecl bound) { if (bound == null) throw new ArgumentNullException("bound"); Bound = bound; }
private ICallable LookUpFunction(BindingContext context, string fullName, IList<IUnboundDecl> typeArgs, IBoundDecl argType) { // with this line uncommented, the "InferredGenericUsesExplicitType" test // passes, but the self-hosting compiler doesn't compile. the line after // the next will get the compiler to break at a different point (earlier? // later?), but breaks the test // the first line is newer and (i think) correct. the old line is what it was // doing before. var boundTypeArgs = TypeBinder.Bind(context, typeArgs); //var boundTypeArgs = TypeBinder.Bind(new BindingContext(context.Compiler, context.SearchSpace), typeArgs); string uniqueName = Callable.UniqueName(fullName, boundTypeArgs, argType); // try the already bound functions ICallable callable; if (TryFind(fullName, boundTypeArgs, argType, out callable)) return callable; // try to instantiate a generic foreach (var generic in mGenerics) { // names must match if (generic.Name != fullName) continue; ICallable instance = generic.Instantiate(context, boundTypeArgs, argType); //### bob: there's a bug here. it doesn't check that the *unique* names of the two functions // match, just the base names. i think this means it could incorrectly collide: // List'Int () // List'Bool () // but i'm not positive if (instance != null) return instance; } // couldn't find it return null; }
public static bool TypesMatch(IBoundDecl parameter, IBoundDecl argument) { // if they're the same object, they must match if (ReferenceEquals(parameter, argument)) { return(true); } // if they're different types, they can't match if (!parameter.GetType().Equals(argument.GetType())) { return(false); } // types that return false here do so because if they did match, // the above ReferenceEquals check should have been true. since // we got here, they must not match. return(parameter.Match( atomic => false, array => TypesMatch(array.ElementType, ((BoundArrayType)argument).ElementType), func => { var argFunc = (FuncType)argument; return TypesMatch(func.Parameter.Bound, argFunc.Parameter.Bound) && TypesMatch(func.Return.Bound, argFunc.Return.Bound); }, record => { var argRecord = (BoundRecordType)argument; if (record.Fields.Count != argRecord.Fields.Count) { return false; } // fields must match foreach (var pair in record.Fields.Zip(argRecord.Fields)) { if (pair.Item1.Key != pair.Item2.Key) { return false; } if (!TypesMatch(pair.Item1.Value, pair.Item2.Value)) { return false; } } return true; }, tuple => { var argTuple = (BoundTupleType)argument; if (tuple.Fields.Count != argTuple.Fields.Count) { return false; } // fields must match return tuple.Fields.Zip(argTuple.Fields).All(TypesMatch); }, structType => false, union => false, foreign => foreign.Name == ((ForeignType)argument).Name)); }
public Field(string name, IBoundDecl type, byte index) : this(name, index) { Type = new Decl(type); }
public ICallable Instantiate(BindingContext context, IEnumerable<IBoundDecl> typeArgs, IBoundDecl argType) { // should have two args: an int and an array var argTuple = argType as BoundTupleType; if (argTuple == null) return null; if (argTuple.Fields[0] != Decl.Int) return null; var arrayType = argTuple.Fields[1] as BoundArrayType; if (arrayType == null) return null; // make the intrinsic return new Intrinsic("__Call", OpCode.LoadArray, FuncType.Create(argTuple, arrayType.ElementType)); }
public ICallable Instantiate(BindingContext context, IEnumerable<IBoundDecl> typeArgs, IBoundDecl argType) { var arrayType = argType as BoundArrayType; if (arrayType == null) return null; // make the intrinsic return new Intrinsic("Size", OpCode.SizeArray, FuncType.Create(arrayType, Decl.Int)); }
public void Define(string name, IBoundDecl type) { Fields.Add(new Field(name, type, (byte)Fields.Count)); }
private ShapeChecker(IBoundDecl type, IDictionary <string, bool> usedVariables) { mType = type; mUsedVariables = usedVariables; }