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); }
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); }