コード例 #1
0
ファイル: Compiler.cs プロジェクト: wzzwzz687510/YarnSpinner
        // all we need do is visit the function itself, it will handle everything
        public override int VisitValueFunc(YarnSpinnerParser.ValueFuncContext context)
        {
            Visit(context.function());

            return(0);
        }
コード例 #2
0
 /// <summary>
 /// Visit a parse tree produced by the <c>valueFunc</c>
 /// labeled alternative in <see cref="YarnSpinnerParser.value"/>.
 /// <para>
 /// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
 /// on <paramref name="context"/>.
 /// </para>
 /// </summary>
 /// <param name="context">The parse tree.</param>
 /// <return>The visitor result.</return>
 public virtual Result VisitValueFunc([NotNull] YarnSpinnerParser.ValueFuncContext context)
 {
     return(VisitChildren(context));
 }
コード例 #3
0
        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);
        }
コード例 #4
0
 /// <summary>
 /// Exit a parse tree produced by the <c>valueFunc</c>
 /// labeled alternative in <see cref="YarnSpinnerParser.value"/>.
 /// <para>The default implementation does nothing.</para>
 /// </summary>
 /// <param name="context">The parse tree.</param>
 public virtual void ExitValueFunc([NotNull] YarnSpinnerParser.ValueFuncContext context)
 {
 }
コード例 #5
0
        public override Yarn.Type VisitValueFunc(YarnSpinnerParser.ValueFuncContext context)
        {
            string functionName = context.function().FUNC_ID().GetText();

            Declaration functionDeclaration = Declarations
                                              .Where(d => d.DeclarationType == Declaration.Type.Function)
                                              .FirstOrDefault(d => d.Name == functionName);

            if (functionDeclaration == null)
            {
                // We don't have a declaration for this function. Create an
                // implicit one.
                functionDeclaration = new Declaration {
                    Name            = functionName,
                    DeclarationType = Declaration.Type.Function,
                    IsImplicit      = true,
                    ReturnType      = Yarn.Type.Undefined,
                    Description     = $"Implicit declaration of function at {sourceFileName}:{context.Start.Line}:{context.Start.Column}",
                    SourceFileName  = sourceFileName,
                    SourceFileLine  = context.Start.Line,
                    SourceNodeName  = currentNodeName,
                    SourceNodeLine  = context.Start.Line - (this.currentNodeContext.BODY_START().Symbol.Line + 1),
                };

                // 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.
                functionDeclaration.Parameters = context.function().expression()
                                                 .Select(e => new Declaration.Parameter {
                    Type = Yarn.Type.Undefined
                })
                                                 .ToArray();

                NewDeclarations.Add(functionDeclaration);
            }

            // Check each parameter of the function
            var suppliedParameters = context.function().expression();

            Declaration.Parameter[] expectedParameters = functionDeclaration.Parameters;
            if (suppliedParameters.Length != expectedParameters.Length)
            {
                // Wrong number of parameters supplied
                var parameters = expectedParameters.Length == 1 ? "parameter" : "parameters";
                throw new TypeException(context, $"Function {functionName} expects {expectedParameters.Length} {parameters}, but received {suppliedParameters.Length}", sourceFileName);
            }

            for (int i = 0; i < expectedParameters.Length; i++)
            {
                var suppliedParameter = suppliedParameters[i];

                var expectedType = expectedParameters[i].Type;

                var suppliedType = this.Visit(suppliedParameter);

                if (expectedType == Yarn.Type.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].Type = suppliedType;
                    expectedType = suppliedType;
                }

                if (suppliedType != expectedType)
                {
                    throw new TypeException(context, $"{functionName} parameter {i + 1} expects a {expectedType}, not a {suppliedType}", sourceFileName);
                }
            }

            // Cool, all the parameters check out!

            // Finally, return the return type of this function.
            return(functionDeclaration.ReturnType);
        }