Exemplo n.º 1
0
        public override Yarn.IType VisitDeclare_statement(YarnSpinnerParser.Declare_statementContext context)
        {
            string description = Compiler.GetDocumentComments(tokens, context);

            // Get the name of the variable we're declaring
            var    variableContext = context.variable();
            string variableName    = variableContext.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.
                string v = $"{existingExplicitDeclaration.Name} has already been declared in {existingExplicitDeclaration.SourceFileName}, line {existingExplicitDeclaration.SourceFileLine}";
                this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, v));
                return(BuiltinTypes.Undefined);
            }

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

            // Did the source code name an explicit type?
            if (context.type != null)
            {
                Yarn.IType explicitType;

                if (KeywordsToBuiltinTypes.TryGetValue(context.type.Text, out explicitType) == false)
                {
                    // The type name provided didn't map to a built-in
                    // type. Look for the type in our Types collection.
                    explicitType = this.Types.FirstOrDefault(t => t.Name == context.type.Text);

                    if (explicitType == null)
                    {
                        // We didn't find a type by this name.
                        string v = $"Unknown type {context.type.Text}";
                        this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, v));
                        return(BuiltinTypes.Undefined);
                    }
                }

                // Check that the type we've found is compatible with the
                // type of the value that was provided - if it doesn't,
                // that's a type error
                if (TypeUtil.IsSubType(explicitType, value.Type) == false)
                {
                    string v = $"Type {context.type.Text} does not match value {context.value().GetText()} ({value.Type.Name})";
                    this.diagnostics.Add(new Diagnostic(this.sourceFileName, context, v));
                    return(BuiltinTypes.Undefined);
                }
            }

            // 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,
                Type           = value.Type,
                DefaultValue   = value.InternalValue,
                Description    = description,
                SourceFileName = this.sourceFileName,
                SourceNodeName = this.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 = false,
            };

            this.NewDeclarations.Add(declaration);

            return(value.Type);
        }
Exemplo n.º 2
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);
        }