protected override object?Visit(Expression.StructValue sval) { base.Visit(sval); // Check if it's even a struct type var instanceType = System.EvaluateType(sval.StructType); if (!(instanceType is Type.Struct structType)) { // TODO throw new NotImplementedException("Can't instantiate non-struct!"); } // Check if all fields are instantiated exactly once and with their proper type var remainingFields = structType.Fields.ToDictionary(f => f.Key, f => f.Value); var alreadyInitialized = new Dictionary <string, IParseTreeElement?>(); foreach (var field in sval.Fields) { if (!remainingFields.Remove(field.Name, out var declaredField)) { // Either already initialized, or unknown field if (structType.Fields.ContainsKey(field.Name)) { System.Report(new DoubleInitializationError(structType, field.Name) { TypeInitializer = sval.StructType?.ParseTreeNode, FirstInitialized = alreadyInitialized[field.Name], SecondInitialized = field.ParseTreeNode, }); } else { System.Report(new UnknownInitializedFieldError(structType, field.Name) { TypeInitializer = sval.StructType?.ParseTreeNode, UnknownInitialized = field.ParseTreeNode, SimilarExistingNames = remainingFields.Keys .Where(n => StringMetrics.OptimalStringAlignmentDistance(n, field.Name) <= 2), }); } } else { // Types need to match var assignedType = System.TypeOf(field.Value); if (!assignedType.Equals(declaredField.Type.Value)) { System.Report(new TypeMismatchError(declaredField.Type.Value, assignedType) { Context = "struct value initialization", Defined = declaredField.Definition?.ParseTreeNode, Wrong = field.ParseTreeNode, }); } alreadyInitialized.Add(field.Name, field.ParseTreeNode); } } if (remainingFields.Count > 0) { System.Report(new MissingInitializationError(structType, remainingFields.Keys) { TypeInitializer = sval.StructType?.ParseTreeNode, }); } return(null); }
private Expression ParsePostfixExpression(ExprState state) { var result = ParseAtomicExpression(state); while (true) { var peek = Peek(); if (PostfixOperators.Contains(peek.Type)) { var op = Next(); result = new Expression.Postfix(result, op); } else if (peek.Type == TokenType.OpenParen) { var openParen = Expect(null, null, TokenType.OpenParen); // Call expression var args = new List <WithComma <Expression> >(); while (Peek().Type != TokenType.CloseParen) { var arg = ParseExpression(ExprState.None); var hasComma = Match(TokenType.Comma, out var comma); args.Add(new WithComma <Expression>(arg, comma)); if (!hasComma) { break; } } var closeParen = Expect("call expression", openParen, TokenType.CloseParen); result = new Expression.Call(result, openParen, args, closeParen); } else if (peek.Type == TokenType.OpenBracket) { var openBracket = Expect(null, null, TokenType.OpenBracket); // Subscript expression var index = ParseExpression(ExprState.None); var closeBracket = Expect("subscript expression", openBracket, TokenType.CloseBracket); result = new Expression.Subscript(result, openBracket, index, closeBracket); } else if (!state.HasFlag(ExprState.TypeOnly) && !state.HasFlag(ExprState.NoBraced) && peek.Type == TokenType.OpenBrace) { // Struct instantiation var openBrace = Expect(null, null, TokenType.OpenBrace); var fields = new List <Expression.StructValue.Field>(); while (Peek().Type != TokenType.CloseBrace) { fields.Add(ParseStructValueField()); } var closeBrace = Expect("struct instantiation", openBrace, TokenType.CloseBrace); result = new Expression.StructValue(result, openBrace, fields, closeBrace); } else if (peek.Type == TokenType.Dot) { // Dot path var dot = Expect(null, null, TokenType.Dot); var ident = Expect("dot path expression", null, TokenType.Identifier); result = new Expression.DotPath(result, dot, ident); } else { break; } } return(result); }