示例#1
0
        private Yarn.Type CheckOperation(ParserRuleContext context, ParserRuleContext[] terms, string operationType, params Yarn.Type[] permittedTypes)
        {
            var termTypes = new List <Yarn.Type>();

            var expressionType = Yarn.Type.Undefined;

            foreach (var expression in terms)
            {
                // Visit this expression, and determine its type.
                Yarn.Type type = Visit(expression);

                if (type != Yarn.Type.Undefined)
                {
                    termTypes.Add(type);
                    if (expressionType == Yarn.Type.Undefined)
                    {
                        // This is the first concrete type we've seen. This
                        // will be our expression type.
                        expressionType = type;
                    }
                }
            }

            if (permittedTypes.Length == 1 && expressionType == Yarn.Type.Undefined)
            {
                // If we aren't sure of the expression type from
                // parameters, but we only have one permitted one, then
                // assume that the expression type is the single permitted
                // type.
                expressionType = permittedTypes.First();
            }

            if (expressionType == Yarn.Type.Undefined)
            {
                // We still don't know what type of expression this is, and
                // don't have a reasonable guess.
                throw new TypeException(context, $"Type of expression {context.GetText()} can't be determined without more context. Use a type cast on at least one of the terms (e.g. the string(), number(), bool() functions)", sourceFileName);
            }

            // Were any of the terms variables for which we don't currently
            // have a declaration for?

            // Start by building a list of all terms that are variables.
            var variableNames = terms
                                .OfType <YarnSpinnerParser.ExpressionContext>()
                                .Select(c => c.GetChild <YarnSpinnerParser.ValueVarContext>(0))
                                .Where(c => c != null)
                                .Select(v => v.variable().VAR_ID().GetText())
                                .Distinct();

            // Build the list of variable names that we don't have a
            // declaration for. We'll check for explicit declarations first.
            var undefinedVariableNames = variableNames
                                         .Where(name => Declarations.Any(d => d.Name == name) == false);

            if (undefinedVariableNames.Count() > 0)
            {
                // We have references to variables that we don't have a an
                // explicit declaration for! Time to create implicit
                // references for them!

                // Get the position of this reference in the file
                int positionInFile = context.Start.Line;

                // The start line of the body is the line after the delimiter
                int nodePositionInFile = this.currentNodeContext.BODY_START().Symbol.Line + 1;

                foreach (var undefinedVariableName in undefinedVariableNames)
                {
                    // Generate a declaration for this variable here.
                    var decl = new Declaration {
                        Name            = undefinedVariableName,
                        DeclarationType = Declaration.Type.Variable,
                        Description     = $"{System.IO.Path.GetFileName(sourceFileName)}, node {currentNodeName}, line {positionInFile - nodePositionInFile}",
                        ReturnType      = expressionType,
                        DefaultValue    = DefaultValueForType(expressionType),
                        SourceFileName  = sourceFileName,
                        SourceFileLine  = positionInFile,
                        SourceNodeName  = currentNodeName,
                        SourceNodeLine  = positionInFile - nodePositionInFile,
                        IsImplicit      = true,
                    };
                    NewDeclarations.Add(decl);
                }
            }

            // All types must be same as the expression type (which is the
            // first defined type we encountered when going through the
            // terms)
            if (termTypes.All(t => t == expressionType) == false)
            {
                // Not all the term types we found were the expression
                // type.
                var typeList = string.Join(", ", termTypes);
                throw new TypeException(context, $"All terms of {operationType} must be the same, not {typeList}", sourceFileName);
            }

            // The expression type must match one of the permitted types.
            // If the type we've found is one of these permitted types,
            // return it - the expression is valid, and we're done.
            if (permittedTypes.Contains(expressionType))
            {
                return(expressionType);
            }
            else
            {
                // The expression type wasn't valid!
                var permittedTypesList = string.Join(" or ", permittedTypes);
                var typeList           = string.Join(", ", termTypes);

                throw new TypeException(context, $"Terms of '{operationType}' must be {permittedTypesList}, not {typeList}", sourceFileName);
            }
        }
示例#2
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);
        }
示例#3
0
        private Yarn.IType CheckOperation(ParserRuleContext context, ParserRuleContext[] terms, Operator operationType, string operationDescription, params Yarn.IType[] permittedTypes)
        {
            var termTypes = new List <Yarn.IType>();

            var expressionType = BuiltinTypes.Undefined;

            foreach (var expression in terms)
            {
                // Visit this expression, and determine its type.
                Yarn.IType type = Visit(expression);

                if (type != BuiltinTypes.Undefined)
                {
                    termTypes.Add(type);
                    if (expressionType == BuiltinTypes.Undefined)
                    {
                        // This is the first concrete type we've seen. This
                        // will be our expression type.
                        expressionType = type;
                    }
                }
            }

            if (permittedTypes.Length == 1 && expressionType == BuiltinTypes.Undefined)
            {
                // If we aren't sure of the expression type from
                // parameters, but we only have one permitted one, then
                // assume that the expression type is the single permitted
                // type.
                expressionType = permittedTypes.First();
            }

            if (expressionType == BuiltinTypes.Undefined)
            {
                // We still don't know what type of expression this is, and
                // don't have a reasonable guess.

                // Last-ditch effort: is the operator that we were given
                // valid in exactly one type? In that case, we'll decide
                // it's that type.
                var typesImplementingMethod = types
                                              .Where(t => t.Methods != null)
                                              .Where(t => t.Methods.ContainsKey(operationType.ToString()));

                if (typesImplementingMethod.Count() == 1)
                {
                    // Only one type implements the operation we were
                    // given. Given no other information, we will assume
                    // that it is this type.
                    expressionType = typesImplementingMethod.First();
                }
                else if (typesImplementingMethod.Count() > 1)
                {
                    // Multiple types implement this operation.
                    IEnumerable <string> typeNames = typesImplementingMethod.Select(t => t.Name);

                    string message = $"Type of expression \"{context.GetTextWithWhitespace()}\" can't be determined without more context (the compiler thinks it could be {string.Join(", or ", typeNames)}). Use a type cast on at least one of the terms (e.g. the string(), number(), bool() functions)";

                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));
                    return(BuiltinTypes.Undefined);
                }
                else
                {
                    // No types implement this operation (??)
                    string message = $"Type of expression \"{context.GetTextWithWhitespace()}\" can't be determined without more context. Use a type cast on at least one of the terms (e.g. the string(), number(), bool() functions)";
                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));
                    return(BuiltinTypes.Undefined);
                }
            }

            // Were any of the terms variables for which we don't currently
            // have a declaration for?

            // Start by building a list of all terms that are variables.
            // These are either variable values, or variable names . (The
            // difference between these two is that a ValueVarContext
            // occurs in syntax where the value of the variable is used
            // (like an expression), while a VariableContext occurs in
            // syntax where it's just a variable name (like a set
            // statements)

            // All VariableContexts in the terms of this expression (but
            // not in the children of those terms)
            var variableContexts = terms
                                   .Select(c => c.GetChild <YarnSpinnerParser.ValueVarContext>(0)?.variable())
                                   .Concat(terms.Select(c => c.GetChild <YarnSpinnerParser.VariableContext>(0)))
                                   .Concat(terms.OfType <YarnSpinnerParser.VariableContext>())
                                   .Concat(terms.OfType <YarnSpinnerParser.ValueVarContext>().Select(v => v.variable()))
                                   .Where(c => c != null);

            // Build the list of variable contexts that we don't have a
            // declaration for. We'll check for explicit declarations first.
            var undefinedVariableContexts = variableContexts
                                            .Where(v => Declarations.Any(d => d.Name == v.VAR_ID().GetText()) == false)
                                            .Distinct();

            if (undefinedVariableContexts.Count() > 0)
            {
                // We have references to variables that we don't have a an
                // explicit declaration for! Time to create implicit
                // references for them!

                // Get the position of this reference in the file
                int positionInFile = context.Start.Line;

                // The start line of the body is the line after the delimiter
                int nodePositionInFile = this.currentNodeContext.BODY_START().Symbol.Line + 1;

                foreach (var undefinedVariableContext in undefinedVariableContexts)
                {
                    // Generate a declaration for this variable here.
                    var decl = new Declaration
                    {
                        Name           = undefinedVariableContext.VAR_ID().GetText(),
                        Description    = $"Implicitly declared in {System.IO.Path.GetFileName(sourceFileName)}, node {currentNodeName}",
                        Type           = expressionType,
                        DefaultValue   = DefaultValueForType(expressionType),
                        SourceFileName = sourceFileName,
                        SourceNodeName = currentNodeName,
                        Range          = new Range
                        {
                            Start =
                            {
                                Line      = undefinedVariableContext.Start.Line - 1,
                                Character = undefinedVariableContext.Start.Column,
                            },
                            End =
                            {
                                Line      = undefinedVariableContext.Stop.Line - 1,
                                Character = undefinedVariableContext.Stop.Column + undefinedVariableContext.Stop.Text.Length,
                            },
                        },
                        IsImplicit = true,
                    };
                    NewDeclarations.Add(decl);
                }
            }

            // All types must be same as the expression type (which is the
            // first defined type we encountered when going through the
            // terms)
            if (termTypes.All(t => t == expressionType) == false)
            {
                // Not all the term types we found were the expression
                // type.
                var    typeList = string.Join(", ", termTypes.Select(t => t.Name));
                string message  = $"All terms of {operationDescription} must be the same, not {typeList}";
                this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));
                return(BuiltinTypes.Undefined);
            }

            // We've now determined that this expression is of
            // expressionType. In case any of the terms had an undefined
            // type, we'll define it now.
            foreach (var term in terms)
            {
                if (term is YarnSpinnerParser.ExpressionContext expression)
                {
                    if (expression.Type == BuiltinTypes.Undefined)
                    {
                        expression.Type = expressionType;
                    }

                    if (expression.Type is FunctionType functionType && functionType.ReturnType == BuiltinTypes.Undefined)
                    {
                        functionType.ReturnType = expressionType;
                    }
                }
            }

            if (operationType != Operator.None)
            {
                // We need to validate that the type we've selected actually
                // implements this operation.
                var implementingType = TypeUtil.FindImplementingTypeForMethod(expressionType, operationType.ToString());

                if (implementingType == null)
                {
                    string message = $"{expressionType.Name} has no implementation defined for {operationDescription}";
                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));
                    return(BuiltinTypes.Undefined);
                }
            }

            // Is this expression is required to be one of the specified types?
            if (permittedTypes.Count() > 0)
            {
                // Is the type that we've arrived at compatible with one of
                // the permitted types?
                if (permittedTypes.Any(t => TypeUtil.IsSubType(t, expressionType)))
                {
                    // It's compatible! Great, return the type we've
                    // determined.
                    return(expressionType);
                }
                else
                {
                    // The expression type wasn't valid!
                    var permittedTypesList = string.Join(" or ", permittedTypes.Select(t => t?.Name ?? "undefined"));
                    var typeList           = string.Join(", ", termTypes.Select(t => t.Name));

                    string message = $"Terms of '{operationDescription}' must be {permittedTypesList}, not {typeList}";
                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));
                    return(BuiltinTypes.Undefined);
                }
            }
            else
            {
                // We weren't given a specific type. The expression type is
                // therefore only valid if it can use the provided
                // operator.

                // Find a type in 'expressionType's hierarchy that
                // implements this method.
                var implementingTypeForMethod = TypeUtil.FindImplementingTypeForMethod(expressionType, operationType.ToString());

                if (implementingTypeForMethod == null)
                {
                    // The type doesn't have a method for handling this
                    // operator, and neither do any of its supertypes. This
                    // expression is therefore invalid.

                    string message = $"Operator {operationDescription} cannot be used with {expressionType.Name} values";
                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));

                    return(BuiltinTypes.Undefined);
                }
                else
                {
                    return(expressionType);
                }
            }
        }
示例#4
0
        public override Yarn.IType VisitSet_statement([NotNull] YarnSpinnerParser.Set_statementContext context)
        {
            var variableContext   = context.variable();
            var expressionContext = context.expression();

            if (expressionContext == null || variableContext == null)
            {
                return(BuiltinTypes.Undefined);
            }

            var expressionType = base.Visit(expressionContext);
            var variableType   = base.Visit(variableContext);

            var variableName = variableContext.GetText();

            ParserRuleContext[] terms = { variableContext, expressionContext };

            Yarn.IType type;

            Operator @operator;

            switch (context.op.Type)
            {
            case YarnSpinnerLexer.OPERATOR_ASSIGNMENT:
                // Straight assignment supports any assignment, as long
                // as it's consistent; we already know the type of the
                // expression, so let's check to see if it's assignable
                // to the type of the variable
                if (variableType != BuiltinTypes.Undefined && TypeUtil.IsSubType(variableType, expressionType) == false)
                {
                    string message = $"{variableName} ({variableType?.Name ?? "undefined"}) cannot be assigned a {expressionType?.Name ?? "undefined"}";
                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, message));
                }
                else if (variableType == BuiltinTypes.Undefined && expressionType != BuiltinTypes.Undefined)
                {
                    // This variable was undefined, but we have a
                    // defined type for the value it was set to. Create
                    // an implicit declaration for the variable!

                    // The start line of the body is the line after the delimiter
                    int nodePositionInFile = this.currentNodeContext.BODY_START().Symbol.Line + 1;

                    // Generate a declaration for this variable here.
                    var decl = new Declaration
                    {
                        Name           = variableName,
                        Description    = $"Implicitly declared in {System.IO.Path.GetFileName(sourceFileName)}, node {currentNodeName}",
                        Type           = expressionType,
                        DefaultValue   = DefaultValueForType(expressionType),
                        SourceFileName = sourceFileName,
                        SourceNodeName = currentNodeName,
                        Range          = new Range
                        {
                            Start =
                            {
                                Line      = variableContext.Start.Line - 1,
                                Character = variableContext.Start.Column,
                            },
                            End =
                            {
                                Line      = variableContext.Stop.Line - 1,
                                Character = variableContext.Stop.Column + variableContext.GetText().Length,
                            },
                        },
                        IsImplicit = true,
                    };
                    NewDeclarations.Add(decl);
                }
                break;

            case YarnSpinnerLexer.OPERATOR_MATHS_ADDITION_EQUALS:
                // += supports strings and numbers
                @operator = CodeGenerationVisitor.TokensToOperators[YarnSpinnerLexer.OPERATOR_MATHS_ADDITION];
                type      = CheckOperation(context, terms, @operator, context.op.Text);
                break;

            case YarnSpinnerLexer.OPERATOR_MATHS_SUBTRACTION_EQUALS:
                // -=, *=, /=, %= supports only numbers
                @operator = CodeGenerationVisitor.TokensToOperators[YarnSpinnerLexer.OPERATOR_MATHS_SUBTRACTION];
                type      = CheckOperation(context, terms, @operator, context.op.Text);
                break;

            case YarnSpinnerLexer.OPERATOR_MATHS_MULTIPLICATION_EQUALS:
                @operator = CodeGenerationVisitor.TokensToOperators[YarnSpinnerLexer.OPERATOR_MATHS_MULTIPLICATION];
                type      = CheckOperation(context, terms, @operator, context.op.Text);
                break;

            case YarnSpinnerLexer.OPERATOR_MATHS_DIVISION_EQUALS:
                @operator = CodeGenerationVisitor.TokensToOperators[YarnSpinnerLexer.OPERATOR_MATHS_DIVISION];
                type      = CheckOperation(context, terms, @operator, context.op.Text);
                break;

            case YarnSpinnerLexer.OPERATOR_MATHS_MODULUS_EQUALS:
                @operator = CodeGenerationVisitor.TokensToOperators[YarnSpinnerLexer.OPERATOR_MATHS_MODULUS];
                type      = CheckOperation(context, terms, @operator, context.op.Text);
                break;

            default:
                throw new InvalidOperationException($"Internal error: {nameof(VisitSet_statement)} got unexpected operand {context.op.Text}");
            }

            if (expressionType == BuiltinTypes.Undefined)
            {
                // We don't know what this is set to, so we'll have to
                // assume it's ok. Return the variable type, if known.
                return(variableType);
            }

            return(expressionType);
        }
示例#5
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();
                functionType.ReturnType = 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
            {
                functionType = functionDeclaration.Type as FunctionType;
                if (functionType == null)
                {
                    throw new InvalidOperationException($"Internal error: decl's type is not a {nameof(FunctionType)}");
                }
            }

            // 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);
        }
示例#6
0
        public override Yarn.Type VisitDeclare_statement(YarnSpinnerParser.Declare_statementContext context)
        {
            // Get the name of the variable we're declaring
            string variableName = context.variable().GetText();

            // Does this variable name already exist in our declarations?
            var existingExplicitDeclaration = Declarations.Where(d => d.IsImplicit == false).FirstOrDefault(d => d.Name == variableName);

            if (existingExplicitDeclaration != null)
            {
                // Then this is an error, because you can't have two explicit declarations for the same variable.
                throw new TypeException(context, $"{existingExplicitDeclaration.Name} has already been declared in {existingExplicitDeclaration.SourceFileName}, line {existingExplicitDeclaration.SourceFileLine}", sourceFileName);
            }

            // Figure out the value and its type
            var constantValueVisitor = new ConstantValueVisitor(sourceFileName);
            var value = constantValueVisitor.Visit(context.value());

            // Do we have an explicit type declaration?
            if (context.type() != null)
            {
                Yarn.Type explicitType;

                // Get its type
                switch (context.type().typename.Type)
                {
                case YarnSpinnerLexer.TYPE_STRING:
                    explicitType = Yarn.Type.String;
                    break;

                case YarnSpinnerLexer.TYPE_BOOL:
                    explicitType = Yarn.Type.Bool;
                    break;

                case YarnSpinnerLexer.TYPE_NUMBER:
                    explicitType = Yarn.Type.Number;
                    break;

                default:
                    throw new ParseException(context, $"Unknown type {context.type().GetText()}");
                }

                // Check that it matches - if it doesn't, that's a type
                // error
                if (explicitType != value.type)
                {
                    throw new TypeException(context, $"Type {context.type().GetText()} does not match value {context.value().GetText()} ({value.type})", sourceFileName);
                }
            }

            // Get the variable declaration, if we have one
            string description = null;

            if (context.Description != null)
            {
                description = context.Description.Text.Trim('"');
            }

            // We're done creating the declaration!

            int positionInFile = context.Start.Line;

            // The start line of the body is the line after the delimiter
            int nodePositionInFile = this.currentNodeContext.BODY_START().Symbol.Line + 1;

            var declaration = new Declaration
            {
                Name            = variableName,
                ReturnType      = value.type,
                DefaultValue    = value.value,
                Description     = description,
                DeclarationType = Declaration.Type.Variable,
                SourceFileName  = sourceFileName,
                SourceFileLine  = positionInFile,
                SourceNodeName  = currentNodeName,
                SourceNodeLine  = positionInFile - nodePositionInFile,
                IsImplicit      = false,
            };

            this.NewDeclarations.Add(declaration);

            return(value.type);
        }