diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 809bb2ae2c7..7a6f698a8fa 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -30,6 +30,7 @@ namespace swift { class Lexer; class Sema; class Expr; + class FuncExpr; class Stmt; class BraceStmt; class Type; @@ -62,8 +63,6 @@ namespace swift { class Parser { llvm::SourceMgr &SourceMgr; Lexer &L; - ASTContext &Context; - Sema &S; /// Tok - This is the current token being considered by the parser. Token Tok; @@ -71,6 +70,9 @@ class Parser { Parser(const Parser&) = delete; void operator=(const Parser&) = delete; public: + ASTContext &Context; + Sema &S; + Parser(unsigned BufferID, ASTContext &Ctx); ~Parser(); @@ -163,10 +165,14 @@ private: ParseResult parseExprUnary(const char *Message = 0); ParseResult parseExprIdentifier(); Expr *parseExprOperator(); + ParseResult parseExprNumericConstant(); ParseResult parseExprDollarIdentifier(); ParseResult parseExprParen(); ParseResult parseExprFunc(); + Expr *actOnIdentifierExpr(Identifier Text, SMLoc Loc); + FuncExpr *actOnFuncExprStart(SMLoc FuncLoc, Type FuncTy); + // Statement Parsing ParseResult parseStmtOtherThanAssignment(); ParseResult parseStmtBrace(const char *Message = 0); @@ -174,6 +180,10 @@ private: ParseResult parseStmtIf(); ParseResult parseStmtWhile(); + /// actOnCondition - Handle a condition to an if/while statement, inserting + /// the call that will convert to a 1-bit type. + Expr *actOnCondition(Expr *Cond); + }; } // end namespace swift diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 506ba8c5aec..8184502c87a 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -18,6 +18,7 @@ #include "ParseResult.h" #include "Scope.h" #include "Sema.h" +#include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/Types.h" #include "swift/AST/ASTContext.h" @@ -145,8 +146,7 @@ ParseResult Parser::parseExprPrimary(const char *Message) { ParseResult Result; switch (Tok.getKind()) { case tok::numeric_constant: - Result = S.expr.ActOnNumericConstant(Tok.getText(), Tok.getLoc()); - consumeToken(tok::numeric_constant); + Result = parseExprNumericConstant(); break; case tok::dollarident: // $1 @@ -250,6 +250,24 @@ ParseResult Parser::parseExprPrimary(const char *Message) { return Result; } +ParseResult Parser::parseExprNumericConstant() { + StringRef Text = Tok.getText(); + SMLoc Loc = consumeToken(tok::numeric_constant); + + // The integer literal must fit in 64-bits. + unsigned long long Val; + if (Text.getAsInteger(0, Val)) { + error(Loc, "invalid immediate for integer literal, value too large"); + return ParseResult::getSemaError(); + } + + // The type of an integer literal is always "integer_literal_type", which + // should be defined by the library. + Identifier TyName = Context.getIdentifier("integer_literal_type"); + Type Ty = S.decl.LookupTypeName(TyName, Loc)->getAliasType(Context); + return new (Context) IntegerLiteralExpr(Text, Loc, Ty); +} + /// expr-identifier: /// dollarident ParseResult Parser::parseExprDollarIdentifier() { @@ -284,9 +302,7 @@ Expr *Parser::parseExprOperator() { Identifier Name; parseIdentifier(Name, ""); - ParseResult Result = S.expr.ActOnIdentifierExpr(Name, Loc); - assert(Result.isSuccess() && "operator reference failed?"); - return Result.get(); + return actOnIdentifierExpr(Name, Loc); } /// parseExprIdentifier - Parse an identifier expression: @@ -301,7 +317,7 @@ ParseResult Parser::parseExprIdentifier() { parseIdentifier(Name, ""); if (Tok.isNot(tok::coloncolon)) - return S.expr.ActOnIdentifierExpr(Name, Loc); + return actOnIdentifierExpr(Name, Loc); SMLoc ColonColonLoc = consumeToken(tok::coloncolon); @@ -311,7 +327,23 @@ ParseResult Parser::parseExprIdentifier() { "::' expression")) return true; - return S.expr.ActOnScopedIdentifierExpr(Name, Loc, ColonColonLoc, Name2,Loc2); + + // Note: this is very simplistic support for scoped name lookup, extend when + // needed. + TypeAliasDecl *TypeScopeDecl = S.decl.LookupTypeName(Name, Loc); + + return new (Context) UnresolvedScopedIdentifierExpr(TypeScopeDecl, Loc, + ColonColonLoc, Loc2, + Name2); +} + +Expr *Parser::actOnIdentifierExpr(Identifier Text, SMLoc Loc) { + ValueDecl *D = S.decl.LookupValueName(Text); + + if (D == 0) + return new (Context) UnresolvedDeclRefExpr(Text, Loc); + + return new (Context) DeclRefExpr(D, Loc); } @@ -370,11 +402,26 @@ ParseResult Parser::parseExprParen() { if (AnySubExprSemaErrors) return ParseResult::getSemaError(); - return S.expr.ActOnTupleExpr(LPLoc, SubExprs.data(), - SubExprNames.empty()?0 : SubExprNames.data(), - SubExprs.size(), RPLoc); + Expr **NewSubExprs = + Context.AllocateCopy(SubExprs.data(), + SubExprs.data()+SubExprs.size()); + + Identifier *NewSubExprsNames = 0; + if (!SubExprNames.empty()) + NewSubExprsNames = + Context.AllocateCopy(SubExprNames.data(), + SubExprNames.data()+SubExprs.size()); + + bool IsGrouping = false; + if (SubExprs.size() == 1 && + (SubExprNames.empty() || SubExprNames[0].empty())) + IsGrouping = true; + + return new (Context) TupleExpr(LPLoc, NewSubExprs, NewSubExprsNames, + SubExprs.size(), RPLoc, IsGrouping); } + /// parseExprFunc - Parse a func expression. /// /// expr-func: @@ -402,7 +449,7 @@ ParseResult Parser::parseExprFunc() { // The arguments to the func are defined in their own scope. Scope FuncBodyScope(S.decl); - FuncExpr *FE = S.expr.ActOnFuncExprStart(FuncLoc, Ty); + FuncExpr *FE = actOnFuncExprStart(FuncLoc, Ty); // Then parse the expression. ParseResult Body; @@ -414,3 +461,98 @@ ParseResult Parser::parseExprFunc() { FE->Body = Body.get(); return FE; } + + +/// FuncTypePiece - This little enum is used by AddFuncArgumentsToScope to keep +/// track of where in a function type it is currently looking. This affects how +/// the decls are processed and created. +enum class FuncTypePiece { + Function, // Looking at the initial functiontype itself. + Input, // Looking at the input to the function type + Output // Looking at the output to the function type. +}; + +/// AddFuncArgumentsToScope - Walk the type specified for a Func object (which +/// is known to be a FunctionType on the outer level) creating and adding named +/// arguments to the current scope. This causes redefinition errors to be +/// emitted. +static void AddFuncArgumentsToScope(Type Ty, + SmallVectorImpl &AccessPath, + FuncTypePiece Mode, + SMLoc FuncLoc, + SmallVectorImpl &ArgDecls, + Parser &P) { + // Handle the function case first. + if (Mode == FuncTypePiece::Function) { + FunctionType *FT = cast(Ty.getPointer()); + AccessPath.push_back(0); + AddFuncArgumentsToScope(FT->Input, AccessPath, FuncTypePiece::Input, + FuncLoc, ArgDecls, P); + + AccessPath.back() = 1; + + // If this is a->b->c then we treat b as an input, not (b->c) as an output. + if (isa(FT->Result.getPointer())) + AddFuncArgumentsToScope(FT->Result, AccessPath, + FuncTypePiece::Function, FuncLoc, ArgDecls, P); + else + AddFuncArgumentsToScope(FT->Result, AccessPath, + FuncTypePiece::Output, FuncLoc, ArgDecls, P); + AccessPath.pop_back(); + return; + } + + // Otherwise, we're looking at an input or output to the func. The only type + // we currently dive into is the humble tuple, which can be recursive. This + // should dive in syntactically. + /// + /// Note that we really *do* want dyn_cast here, not getAs, because we do not + /// want to look through type aliases or other sugar, we want to see what the + /// user wrote in the func declaration. + TupleType *TT = dyn_cast(Ty.getPointer()); + if (TT == 0) return; + + + AccessPath.push_back(0); + + // For tuples, recursively processes their elements (to handle cases like: + // (x : (a : int, b : int), y : int) -> ... + // and create decls for any named elements. + for (unsigned i = 0, e = TT->Fields.size(); i != e; ++i) { + AccessPath.back() = 1; + AddFuncArgumentsToScope(TT->Fields[i].Ty, AccessPath, Mode, FuncLoc, + ArgDecls, P); + + // If this field is named, create the argument decl for it. + Identifier Name = TT->Fields[i].Name; + // Ignore unnamed fields. + if (Name.get() == 0) continue; + + + // Create the argument decl for this named argument. + ArgDecl *AD = new (P.Context) ArgDecl(FuncLoc, Name, TT->Fields[i].Ty); + ArgDecls.push_back(AD); + + // Eventually we should mark the input/outputs as readonly vs writeonly. + //bool isInput = Mode == FuncTypePiece::Input; + + P.S.decl.AddToScope(AD); + } + + AccessPath.pop_back(); +} + + +FuncExpr *Parser::actOnFuncExprStart(SMLoc FuncLoc, Type FuncTy) { + SmallVector AccessPath; + SmallVector ArgDecls; + AddFuncArgumentsToScope(FuncTy, AccessPath, FuncTypePiece::Function, + FuncLoc, ArgDecls, *this); + + ArrayRef Args = ArgDecls; + + return new (Context) FuncExpr(FuncLoc, FuncTy, Context.AllocateCopy(Args)); +} + + + diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index ed68cff0fc2..a8653bf889f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -27,6 +27,18 @@ #include "llvm/ADT/Twine.h" using namespace swift; +/// ActOnCondition - Handle a condition to an if/while statement, inserting +/// the call that will convert to a 1-bit type. +Expr *Parser::actOnCondition(Expr *Cond) { + assert(Cond); + + // The condition needs to be convertible to a logic value. Build a call to + // "convertToLogicValue" passing in the condition as an argument. + Identifier C2LVFuncId = Context.getIdentifier("convertToLogicValue"); + Expr *C2LVFunc = actOnIdentifierExpr(C2LVFuncId, Cond->getLocStart()); + + return new (Context) CallExpr(C2LVFunc, Cond, Type()); +} /// stmt-brace-item: @@ -249,7 +261,7 @@ ParseResult Parser::parseStmtIf() { ElseBody.isSemaError()) return ParseResult::getSemaError(); - Expr *Cond = S.expr.ActOnCondition(Condition.get()); + Expr *Cond = actOnCondition(Condition.get()); Stmt *ElseBodyStmt = 0; if (!ElseBody.isAbsent()) @@ -276,7 +288,7 @@ ParseResult Parser::parseStmtWhile() { if (Condition.isSemaError() || Body.isSemaError()) return ParseResult::getSemaError(); - Expr *Cond = S.expr.ActOnCondition(Condition.get()); + Expr *Cond = actOnCondition(Condition.get()); return new (Context) WhileStmt(WhileLoc, Cond, Body.get()); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 35896543ce4..3f0f279ce36 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -479,7 +479,7 @@ FuncDecl *Parser::parseDeclFunc() { { Scope FnBodyScope(S.decl); - FE = S.expr.ActOnFuncExprStart(FuncLoc, FuncTy); + FE = actOnFuncExprStart(FuncLoc, FuncTy); // Then parse the expression. NullablePtr Body; diff --git a/lib/Parse/Sema.cpp b/lib/Parse/Sema.cpp index 2abed3978b0..2584130332f 100644 --- a/lib/Parse/Sema.cpp +++ b/lib/Parse/Sema.cpp @@ -20,7 +20,7 @@ using namespace swift; Sema::Sema(ASTContext &context) - : Context(context), expr(*this), decl(*this) { + : Context(context), decl(*this) { } diff --git a/lib/Parse/Sema.h b/lib/Parse/Sema.h index 992dad78604..58aaa15a449 100644 --- a/lib/Parse/Sema.h +++ b/lib/Parse/Sema.h @@ -18,7 +18,6 @@ #ifndef SWIFT_SEMA_SEMA_H #define SWIFT_SEMA_SEMA_H -#include "SemaExpr.h" #include "SemaDecl.h" namespace swift { @@ -37,7 +36,6 @@ public: // Sema subobjects for handling different subsystems. These are public for // direct access by clients. They are lower case so they don't shadow the // type names they correspond to. - SemaExpr expr; SemaDecl decl; explicit Sema(ASTContext &Context); diff --git a/lib/Parse/SemaExpr.cpp b/lib/Parse/SemaExpr.cpp deleted file mode 100644 index d0eaa2c6404..00000000000 --- a/lib/Parse/SemaExpr.cpp +++ /dev/null @@ -1,202 +0,0 @@ -//===--- SemaExpr.cpp - Swift Expression Semantic Analysis ----------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for Swift expressions. -// -//===----------------------------------------------------------------------===// - -#include "SemaExpr.h" -#include "Sema.h" -#include "swift/AST/ASTContext.h" -#include "swift/AST/Decl.h" -#include "swift/AST/Expr.h" -#include "swift/AST/Stmt.h" -#include "swift/AST/Types.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/SMLoc.h" -using namespace swift; - -//===----------------------------------------------------------------------===// -// Action Implementations -//===----------------------------------------------------------------------===// - -NullablePtr SemaExpr::ActOnNumericConstant(StringRef Text, - SMLoc Loc) { - // The integer literal must fit in 64-bits. - unsigned long long Val; - if (Text.getAsInteger(0, Val)) { - error(Loc, "invalid immediate for integer literal, value too large"); - Text = "1"; - } - - // The type of an integer literal is always "integer_literal_type", which - // should be defined by the library. - Identifier TyName = S.Context.getIdentifier("integer_literal_type"); - Type Ty = S.decl.LookupTypeName(TyName, Loc)->getAliasType(S.Context); - return new (S.Context) IntegerLiteralExpr(Text, Loc, Ty); -} - - -NullablePtr -SemaExpr::ActOnIdentifierExpr(Identifier Text, SMLoc Loc) { - ValueDecl *D = S.decl.LookupValueName(Text); - - if (D == 0) - return new (S.Context) UnresolvedDeclRefExpr(Text, Loc); - - return new (S.Context) DeclRefExpr(D, Loc); -} - -NullablePtr SemaExpr:: -ActOnScopedIdentifierExpr(Identifier ScopeName, SMLoc ScopeLoc, - SMLoc ColonColonLoc, - Identifier Name, SMLoc NameLoc) { - // Note: this is very simplistic support for scoped name lookup, extend when - // needed. - TypeAliasDecl *TypeScopeDecl = S.decl.LookupTypeName(ScopeName, ScopeLoc); - - return new (S.Context) UnresolvedScopedIdentifierExpr(TypeScopeDecl, ScopeLoc, - ColonColonLoc, NameLoc, - Name); -} - -NullablePtr -SemaExpr::ActOnTupleExpr(SMLoc LPLoc, Expr *const *SubExprs, - const Identifier *SubExprNames, - unsigned NumSubExprs, SMLoc RPLoc) { - - Expr **NewSubExprs = - S.Context.AllocateCopy(SubExprs, SubExprs+NumSubExprs); - - Identifier *NewSubExprsNames = 0; - if (SubExprNames) - NewSubExprsNames = - S.Context.AllocateCopy(SubExprNames,SubExprNames+NumSubExprs); - - bool IsGrouping = false; - if (NumSubExprs == 1 && - (SubExprNames == 0 || SubExprNames[0].empty())) - IsGrouping = true; - - return new (S.Context) TupleExpr(LPLoc, NewSubExprs, NewSubExprsNames, - NumSubExprs, RPLoc, IsGrouping); -} - -/// ActOnCondition - Handle a condition to an if/while statement, inserting -/// the call that will convert to a 1-bit type. -Expr *SemaExpr::ActOnCondition(Expr *Cond) { - assert(Cond); // Else may be null. - - // The condition needs to be convertible to a logic value. Build a call to - // "convertToLogicValue" passing in the condition as an argument. - Identifier C2LVFuncId = S.Context.getIdentifier("convertToLogicValue"); - Expr *C2LVFunc = ActOnIdentifierExpr(C2LVFuncId, Cond->getLocStart()).get(); - - return new (S.Context) CallExpr(C2LVFunc, Cond, Type()); -} - - -/// FuncTypePiece - This little enum is used by AddFuncArgumentsToScope to keep -/// track of where in a function type it is currently looking. This affects how -/// the decls are processed and created. -enum class FuncTypePiece { - Function, // Looking at the initial functiontype itself. - Input, // Looking at the input to the function type - Output // Looking at the output to the function type. -}; - -/// AddFuncArgumentsToScope - Walk the type specified for a Func object (which -/// is known to be a FunctionType on the outer level) creating and adding named -/// arguments to the current scope. This causes redefinition errors to be -/// emitted. -static void AddFuncArgumentsToScope(Type Ty, - SmallVectorImpl &AccessPath, - FuncTypePiece Mode, - SMLoc FuncLoc, - SmallVectorImpl &ArgDecls, - SemaExpr &SE) { - // Handle the function case first. - if (Mode == FuncTypePiece::Function) { - FunctionType *FT = cast(Ty.getPointer()); - AccessPath.push_back(0); - AddFuncArgumentsToScope(FT->Input, AccessPath, FuncTypePiece::Input, - FuncLoc, ArgDecls, SE); - - AccessPath.back() = 1; - - // If this is a->b->c then we treat b as an input, not (b->c) as an output. - if (isa(FT->Result.getPointer())) - AddFuncArgumentsToScope(FT->Result, AccessPath, - FuncTypePiece::Function, FuncLoc, ArgDecls, SE); - else - AddFuncArgumentsToScope(FT->Result, AccessPath, - FuncTypePiece::Output, FuncLoc, ArgDecls, SE); - AccessPath.pop_back(); - return; - } - - // Otherwise, we're looking at an input or output to the func. The only type - // we currently dive into is the humble tuple, which can be recursive. This - // should dive in syntactically. - /// - /// Note that we really *do* want dyn_cast here, not getAs, because we do not - /// want to look through type aliases or other sugar, we want to see what the - /// user wrote in the func declaration. - TupleType *TT = dyn_cast(Ty.getPointer()); - if (TT == 0) return; - - - AccessPath.push_back(0); - - // For tuples, recursively processes their elements (to handle cases like: - // (x : (a : int, b : int), y : int) -> ... - // and create decls for any named elements. - for (unsigned i = 0, e = TT->Fields.size(); i != e; ++i) { - AccessPath.back() = 1; - AddFuncArgumentsToScope(TT->Fields[i].Ty, AccessPath, Mode, FuncLoc, - ArgDecls, SE); - - // If this field is named, create the argument decl for it. - Identifier Name = TT->Fields[i].Name; - // Ignore unnamed fields. - if (Name.get() == 0) continue; - - - // Create the argument decl for this named argument. - ArgDecl *AD = new (SE.S.Context) ArgDecl(FuncLoc, Name, TT->Fields[i].Ty); - ArgDecls.push_back(AD); - - // Eventually we should mark the input/outputs as readonly vs writeonly. - //bool isInput = Mode == FuncTypePiece::Input; - - SE.S.decl.AddToScope(AD); - } - - AccessPath.pop_back(); -} - - -FuncExpr *SemaExpr::ActOnFuncExprStart(SMLoc FuncLoc, Type FuncTy) { - SmallVector AccessPath; - SmallVector ArgDecls; - AddFuncArgumentsToScope(FuncTy, AccessPath, FuncTypePiece::Function, - FuncLoc, ArgDecls, *this); - - ArrayRef Args = ArgDecls; - - return new (S.Context) FuncExpr(FuncLoc, FuncTy, - S.Context.AllocateCopy(Args)); -} - - diff --git a/lib/Parse/SemaExpr.h b/lib/Parse/SemaExpr.h deleted file mode 100644 index a63352b32e1..00000000000 --- a/lib/Parse/SemaExpr.h +++ /dev/null @@ -1,70 +0,0 @@ -//===--- SemaExpr.h - Swift Expression Semantic Analysis --------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See http://swift.org/LICENSE.txt for license information -// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file defines the Sema interface which implement hooks invoked by the -// parser to build the AST for expressions. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_SEMA_EXPR_H -#define SWIFT_SEMA_EXPR_H - -#include "SemaBase.h" - -namespace llvm { - template class PointerUnion; - template class NullablePtr; - template class ArrayRef; -} -namespace swift { - class Decl; - class Expr; - class FuncExpr; - class Sema; - class Stmt; - class Type; - class ValueDecl; - class Identifier; - -/// SemaExpr - Semantic analysis support for Swift expressions. -class SemaExpr : public SemaBase { -public: - explicit SemaExpr(Sema &S) : SemaBase(S) {} - - typedef llvm::PointerUnion ExprOrDecl; - - // Action Implementations. These return null on semantic errors. - NullablePtr - ActOnNumericConstant(StringRef Text, SMLoc Loc); - NullablePtr - ActOnIdentifierExpr(Identifier Text, SMLoc Loc); - NullablePtr - ActOnScopedIdentifierExpr(Identifier ScopeName, SMLoc ScopeLoc, - SMLoc ColonColonLoc, - Identifier Name, SMLoc NameLoc); - - NullablePtr - ActOnTupleExpr(SMLoc LPLoc, Expr *const *SubExprs, - const Identifier *SubExprNames, - unsigned NumSubExprs, SMLoc RPLoc); - - /// ActOnCondition - Handle a condition to an if/while statement, inserting - /// the call that will convert to a 1-bit type. - Expr *ActOnCondition(Expr *Cond); - - FuncExpr *ActOnFuncExprStart(SMLoc FuncLoc, Type FuncTy); - -}; - -} // end namespace swift - -#endif