public void Visit(PostfixExpression_ArrayAccess x) {//TODO for Slices: Omit opIndex overloads if it's obvious that we don't want them -- a[1.. | if (x.Arguments != null) res.CurrentlyTypedArgumentIndex = x.Arguments.Length; res.IsMethodArguments = true; res.ParsedExpression = x; var overloads = new List<AbstractType>(); if (x.PostfixForeExpression == null) return; var b = ExpressionTypeEvaluation.EvaluateType(x.PostfixForeExpression, ctxt); var ov = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(ExpressionTypeEvaluation.OpSliceIdHash, b, ctxt, x, false); if (ov != null) overloads.AddRange(ov); ov = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(ExpressionTypeEvaluation.OpIndexIdHash, b, ctxt, x, false); if (ov != null) overloads.AddRange(ov); if (overloads.Count == 0) { b = DResolver.StripMemberSymbols(b); var toTypeDecl = new DTypeToTypeDeclVisitor(); var aa = b as AssocArrayType; if (aa != null){ var retType = aa.ValueType != null ? aa.ValueType.Accept(toTypeDecl) : null; var dm = new DMethod { Name = "opIndex", Type = retType }; dm.Parameters.Add(new DVariable { Name = "index", Type = aa.KeyType != null ? aa.KeyType.Accept(toTypeDecl) : null }); overloads.Add(new MemberSymbol(dm, aa.ValueType)); if ((aa is ArrayType) && !(aa as ArrayType).IsStaticArray) { dm = new DMethod { Name = "opSlice", Type = retType }; overloads.Add(new MemberSymbol(dm, aa.ValueType)); } } else if (b is PointerType) { b = (b as PointerType).Base; var dm = new DMethod { Name = "opIndex", Type = b != null ? b.Accept(toTypeDecl) : null }; dm.Parameters.Add(new DVariable { Name = "index", Type = new IdentifierDeclaration("size_t") }); overloads.Add(new MemberSymbol(dm, b)); } } res.ResolvedTypesOrMethods = overloads.ToArray(); }
IExpression ParseAsmPrimaryExpression(IBlockNode Scope, IStatement Parent) { switch (laKind) { case OpenSquareBracket: Step (); var e = new PostfixExpression_ArrayAccess (ParseAsmExpression (Scope, Parent)); Expect (CloseSquareBracket); e.EndLocation = t.EndLocation; return e; case Dollar: var ins = Parent as AsmStatement.InstructionStatement; if (ins == null || (!ins.IsJmpFamily && ins.Operation != AsmStatement.InstructionStatement.OpCode.call)) SynErr(Dollar, "The $ operator is only valid on jmp and call instructions!"); Step(); return new TokenExpression(t.Kind) { Location = t.Location, EndLocation = t.EndLocation }; case Literal: Step(); return new IdentifierExpression(t.LiteralValue, t.LiteralFormat, t.Subformat) { Location = t.Location, EndLocation = t.EndLocation }; case This: Step(); return new TokenExpression(This) { Location = t.Location, EndLocation = t.EndLocation }; // AsmTypePrefix case DTokens.Byte: case DTokens.Short: case DTokens.Int: case DTokens.Float: case DTokens.Double: case DTokens.Real: case __LOCAL_SIZE: Step (); return new TokenExpression(t.Kind) { Location = t.Location, EndLocation = t.EndLocation }; case Identifier: Step(); if (AsmRegisterExpression.IsRegister(t.Value)) { string reg = t.Value; if (reg == "ST" && laKind == OpenParenthesis) { reg += "("; Step(); if (Expect(Literal)) { reg += t.LiteralValue.ToString(); if (laKind != CloseParenthesis) SynErr(CloseParenthesis); else Step(); reg += ")"; } } switch (reg) { case "ES": case "CS": case "SS": case "DS": case "GS": case "FS": if (laKind == Colon) { var ex = new AsmRegisterExpression() { Location = t.Location, EndLocation = t.EndLocation, Register = string.Intern(reg) }; Step(); // NOTE: DMD actually allows you to not have an expression after a // segment specifier, however I consider this a bug, and, as // such, am making an expression in that form fail to parse. return new UnaryExpression_SegmentBase() { RegisterExpression = ex, UnaryExpression = ParseAsmExpression(Scope, Parent) }; } goto default; default: // This check is required because of how ST registers are handled. if (AsmRegisterExpression.IsRegister(reg)) return new AsmRegisterExpression() { Location = t.Location, EndLocation = t.EndLocation, Register = string.Intern(reg) }; SynErr(Identifier, "Unknown register!"); return IsEOF ? new TokenExpression(Incomplete) : null; } } else { IExpression outer = new IdentifierExpression(t.Value) { Location = t.Location, EndLocation = t.EndLocation }; while (laKind == Dot) { Step(); if (Expect(Identifier)) outer = new PostfixExpression_Access() { AccessExpression = new IdentifierExpression(t.Value), PostfixForeExpression = outer }; else outer = new TokenExpression(Incomplete); Step(); } return outer; } default: SynErr(Identifier, "Expected a $, literal or an identifier!"); Step(); if (IsEOF) return new TokenExpression(Incomplete); return null; } }
IExpression PostfixExpression(IBlockNode Scope = null) { IExpression leftExpr = null; /* * Despite the following syntax is an explicit UnaryExpression (see http://dlang.org/expression.html#UnaryExpression), * stuff like (MyType).init[] is actually allowed - so it's obviously a PostfixExpression! (Nov 13 2013) */ // ( Type ) . Identifier if (laKind == OpenParenthesis) { Lexer.StartPeek(); OverPeekBrackets(OpenParenthesis, false); var dotToken = Lexer.CurrentPeekToken; if (Lexer.CurrentPeekToken.Kind == DTokens.Dot && (Peek().Kind == DTokens.Identifier || Lexer.CurrentPeekToken.Kind == EOF)) { var wkParsing = AllowWeakTypeParsing; AllowWeakTypeParsing = true; Lexer.PushLookAheadBackup(); Step(); var startLoc = t.Location; var td = Type(Scope); AllowWeakTypeParsing = wkParsing; /* * (a. -- expression: (a.myProp + 2) / b; * (int. -- must be expression anyway * (const).asdf -- definitely unary expression ("type") * (const). -- also treat it as type accessor */ if (td != null && laKind == CloseParenthesis && Lexer.CurrentPeekToken == dotToken) // Also take it as a type declaration if there's nothing following (see Expression Resolving) { Step(); // Skip to ) if (laKind == DTokens.Dot) { Step(); // Skip to . if ((laKind == DTokens.Identifier && Peek(1).Kind != Not && Peek(1).Kind != OpenParenthesis) || IsEOF) { Lexer.PopLookAheadBackup(); Step(); // Skip to identifier leftExpr = new UnaryExpression_Type() { Type = td, AccessIdentifier = t.Value, Location = startLoc, EndLocation = t.EndLocation }; } else Lexer.RestoreLookAheadBackup(); } else Lexer.RestoreLookAheadBackup(); } else Lexer.RestoreLookAheadBackup(); } } // PostfixExpression if(leftExpr == null) leftExpr = PrimaryExpression(Scope); while (!IsEOF) { switch (laKind) { case Dot: Step(); var pea = new PostfixExpression_Access { PostfixForeExpression = leftExpr }; leftExpr = pea; if (laKind == New) pea.AccessExpression = PostfixExpression(Scope); else if (IsTemplateInstance) pea.AccessExpression = TemplateInstance(Scope); else if (Expect(Identifier)) pea.AccessExpression = new IdentifierExpression(t.Value) { Location = t.Location, EndLocation = t.EndLocation }; else if (IsEOF) pea.AccessExpression = new TokenExpression(DTokens.Incomplete); pea.EndLocation = t.EndLocation; break; case Increment: case Decrement: Step(); var peid = t.Kind == Increment ? (PostfixExpression)new PostfixExpression_Increment() : new PostfixExpression_Decrement(); peid.EndLocation = t.EndLocation; peid.PostfixForeExpression = leftExpr; leftExpr = peid; break; // Function call case OpenParenthesis: Step(); var pemc = new PostfixExpression_MethodCall(); pemc.PostfixForeExpression = leftExpr; leftExpr = pemc; if (laKind == CloseParenthesis) Step(); else { pemc.Arguments = ArgumentList(Scope).ToArray(); Expect(CloseParenthesis); } if(IsEOF) pemc.EndLocation = CodeLocation.Empty; else pemc.EndLocation = t.EndLocation; break; // IndexExpression | SliceExpression case OpenSquareBracket: Step (); var loc = t.Location; var args = new List<PostfixExpression_ArrayAccess.IndexArgument> (); if (laKind != CloseSquareBracket) { do { var firstEx = AssignExpression (Scope); // [ AssignExpression .. AssignExpression ] || ArgumentList if (laKind == DoubleDot) { Step (); args.Add (new PostfixExpression_ArrayAccess.SliceArgument (firstEx, AssignExpression (Scope))); } else args.Add (new PostfixExpression_ArrayAccess.IndexArgument (firstEx)); } while(laKind == Comma && Expect (Comma) && laKind != CloseSquareBracket); // Trailing comma allowed https://github.com/aBothe/D_Parser/issues/170 } Expect (CloseSquareBracket); leftExpr = new PostfixExpression_ArrayAccess(args.ToArray()){ EndLocation = t.EndLocation, PostfixForeExpression = leftExpr }; break; default: return leftExpr; } } return leftExpr; }
IExpression ParseAsmBracketExpression(IBlockNode Scope, IStatement Parent) { var left = ParseAsmUnaryExpression(Scope, Parent); while (laKind == OpenSquareBracket) { Step(); left = new PostfixExpression_ArrayAccess(ParseAsmExpression(Scope, Parent)) { PostfixForeExpression = left }; Expect(CloseSquareBracket); (left as PostfixExpression_ArrayAccess).EndLocation = t.EndLocation; } return left; }
public override void Visit(PostfixExpression_ArrayAccess x) { CallExpressionStack.Push(x); base.Visit(x); CallExpressionStack.Pop(); }