public void SetSelfParameter(AstTypeDefinitionIntrinsic type) { Ast.Guard(!FunctionType.Parameters.Any(), "A Self parameter has to be first."); var parameter = new AstFunctionParameterDefinition(AstIdentifierIntrinsic.Self); parameter.SetTypeReference(AstTypeReferenceType.From(type)); FunctionType.AddParameter(parameter); }
public void TestFunctionTypeBuilderCanBuildTypes() { // Given var expectedFunctionType = new FunctionType(); expectedFunctionType.ReturnType = BuiltinTypes.String; expectedFunctionType.AddParameter(BuiltinTypes.String); expectedFunctionType.AddParameter(BuiltinTypes.Number); var functionType = new FunctionTypeBuilder() .WithParameter(BuiltinTypes.String) .WithParameter(BuiltinTypes.Number) .WithReturnType(BuiltinTypes.String) .FunctionType; // Then Assert.Equal(expectedFunctionType.Parameters.Count, functionType.Parameters.Count); Assert.Equal(expectedFunctionType.Parameters[0], functionType.Parameters[0]); Assert.Equal(expectedFunctionType.Parameters[1], functionType.Parameters[1]); Assert.Equal(expectedFunctionType.ReturnType, functionType.ReturnType); }
public override Yarn.IType VisitValueFunc(YarnSpinnerParser.ValueFuncContext context) { string functionName = context.function_call().FUNC_ID().GetText(); Declaration functionDeclaration = Declarations .Where(d => d.Type is FunctionType) .FirstOrDefault(d => d.Name == functionName); FunctionType functionType; if (functionDeclaration == null) { // We don't have a declaration for this function. Create an // implicit one. functionType = new FunctionType(); // because it is an implicit declaration we will use the type hint to give us a return type functionType.ReturnType = context.Hint != BuiltinTypes.Undefined ? context.Hint : BuiltinTypes.Undefined; functionDeclaration = new Declaration { Name = functionName, Type = functionType, IsImplicit = true, Description = $"Implicit declaration of function at {sourceFileName}:{context.Start.Line}:{context.Start.Column}", SourceFileName = sourceFileName, SourceNodeName = currentNodeName, Range = new Range { Start = { Line = context.Start.Line - 1, Character = context.Start.Column, }, End = { Line = context.Stop.Line - 1, Character = context.Stop.Column + context.Stop.Text.Length, }, }, }; // Create the array of parameters for this function based // on how many we've seen in this call. Set them all to be // undefined; we'll bind their type shortly. var parameterTypes = context.function_call().expression() .Select(e => BuiltinTypes.Undefined) .ToList(); foreach (var parameterType in parameterTypes) { functionType.AddParameter(parameterType); } NewDeclarations.Add(functionDeclaration); } else { var a = (FunctionType)functionDeclaration.Type; functionType = functionDeclaration.Type as FunctionType; if (functionType == null) { throw new InvalidOperationException($"Internal error: decl's type is not a {nameof(FunctionType)}"); } // we have an existing function but its undefined // if we also have a type hint we can use that to update it if (functionType.ReturnType == BuiltinTypes.Undefined && context.Hint != BuiltinTypes.Undefined) { NewDeclarations.Remove(functionDeclaration); functionType.ReturnType = context.Hint; functionDeclaration.Type = functionType; NewDeclarations.Add(functionDeclaration); } } // Check each parameter of the function var suppliedParameters = context.function_call().expression(); var expectedParameters = functionType.Parameters; if (suppliedParameters.Length != expectedParameters.Count()) { // Wrong number of parameters supplied var parameters = expectedParameters.Count() == 1 ? "parameter" : "parameters"; this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, $"Function {functionName} expects {expectedParameters.Count()} {parameters}, but received {suppliedParameters.Length}")); return(functionType.ReturnType); } for (int i = 0; i < expectedParameters.Count(); i++) { var suppliedParameter = suppliedParameters[i]; var expectedType = expectedParameters[i]; var suppliedType = this.Visit(suppliedParameter); if (expectedType == BuiltinTypes.Undefined) { // The type of this parameter hasn't yet been bound. // Bind this parameter type to what we've resolved the // type to. expectedParameters[i] = suppliedType; expectedType = suppliedType; } if (TypeUtil.IsSubType(expectedType, suppliedType) == false) { this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, $"{functionName} parameter {i + 1} expects a {expectedType?.Name ?? "undefined"}, not a {suppliedType?.Name ?? "undefined"}")); return(functionType.ReturnType); } } // Cool, all the parameters check out! // Finally, return the return type of this function. return(functionType.ReturnType); }