diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 12 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 22 | ||||
| -rw-r--r-- | lib/CodeGen/OperatorGen.cc | 71 | ||||
| -rw-r--r-- | lib/CodeGen/ValueTypeGen.cc | 6 | ||||
| -rw-r--r-- | lib/Parser/Parser.cc | 15 | ||||
| -rw-r--r-- | lib/Parser/ParserExpression.cc | 25 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 17 |
7 files changed, 147 insertions, 21 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 61fd837..f7c4de6 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -369,6 +369,14 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line, std::vector<Value*> &Out) { + std::vector<ExprAST*> Args; + for (const auto &Arg : ArgExprs) Args.push_back(Arg.get()); + return marshalCallArgs(Signature, Args, Line, Out); +} + +bool CodeGen::marshalCallArgs(const FuncSig &Signature, + const std::vector<ExprAST*> &ArgExprs, + int Line, std::vector<Value*> &Out) { SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine); const FuncSig *Sig = &Signature; const std::string &Callee = Sig->Name; @@ -379,7 +387,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, for (size_t i = 0; i < ArgExprs.size(); ++i) { if (i >= Sig->Params.size()) { - Value *V = emitVariadicArgument(ArgExprs[i].get(), Callee, i + 1); + Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1); if (!V) return false; Out.push_back(V); continue; @@ -387,7 +395,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, const ParamSig &P = Sig->Params[i]; const std::string &TypeName = P.TypeName; bool IsByRef = P.IsByRef; - ExprAST *ArgExpr = ArgExprs[i].get(); + ExprAST *ArgExpr = ArgExprs[i]; if (P.IsArray) { if (!Arrays->emitArrayArgument(ArgExpr, P.TypeName, P.Rank, P.DeclaredBounds, diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc index 8fb13c9..a01cab2 100644 --- a/lib/CodeGen/ExpressionGen.cc +++ b/lib/CodeGen/ExpressionGen.cc @@ -73,6 +73,16 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) { + if (isWholeArrayVar(Unary->getOperand())) { + reportError("A whole array cannot be used as an operand; index it"); + return nullptr; + } + auto Overload = resolveOperator(Unary->getOp(), getExprTypeInfo(Unary->getOperand())); + if (Overload.Ambiguous) { + reportError("Ambiguous overload for %s", operatorName(Unary->getOp()).c_str()); + return nullptr; + } + if (Overload.Signature) return emitOperatorCall(*Overload.Signature, Unary->getOperand()); if (Unary->getOp() == tok_not) { const TypeInfo *Info = getExprTypeInfo(Unary->getOperand()); Value *Operand = Info && Info->isC() @@ -123,6 +133,16 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { // '&' path: their admissible operations are decided by name here. const TypeInfo *LT = getExprTypeInfo(Bin->getLHS()); const TypeInfo *RT = getExprTypeInfo(Bin->getRHS()); + if (LT && RT) { + auto Overload = resolveOperator(Bin->getOp(), LT, RT); + if (Overload.Ambiguous) { + reportError("Ambiguous overload for %s(%s, %s)", operatorName(Bin->getOp()).c_str(), + LT->Name.c_str(), RT->Name.c_str()); + return nullptr; + } + if (Overload.Signature) + return emitOperatorCall(*Overload.Signature, Bin->getLHS(), Bin->getRHS()); + } Value *L = emitExpr(Bin->getLHS()); Value *R = emitExpr(Bin->getRHS()); return emitBinaryOp(Bin->getOp(), L, LT, R, RT, Bin->getLine()); @@ -165,7 +185,7 @@ Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT, reportError("Ambiguous overload for %s(%s, %s)", operatorName(Op).c_str(), LT->Name.c_str(), RT->Name.c_str()); return nullptr; } - if (Overload.Signature) return FuncGen->emitCall(*Overload.Signature, {L, R}); + if (Overload.Signature) return emitOperatorValues(*Overload.Signature, L, LT, R); if ((LT && LT->isC()) || (RT && RT->isC())) return emitCBinaryOp(Op, L, LT, R, RT, Line); if ((LT && LT->isUserKind()) || (RT && RT->isUserKind())) diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc index 83c515b..d340ed7 100644 --- a/lib/CodeGen/OperatorGen.cc +++ b/lib/CodeGen/OperatorGen.cc @@ -1,7 +1,9 @@ #include "cps/CodeGen.h" #include "cps/Operator.h" +#include "cps/TypeAST.h" using namespace cps; +using namespace llvm; // Probing candidates must not evaluate operands or diagnose absent overloads: // both static typing and emission use this same selection. @@ -9,12 +11,73 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( int Op, const TypeInfo *Left, const TypeInfo *Right) { OperatorResolution Result; if (!Left) return Result; - for (const FuncSig *Sig : FuncGen->getOverloads(operatorName(Op))) { - if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u)) continue; - if (!Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; - if (Right && !Right->sameType(resolveType(Sig->Params[1].TypeName))) continue; + auto Candidates = FuncGen->getOverloads(operatorName(Op)); + if (Left->IsClass) { + auto Members = FuncGen->getOverloads(Left->Name + "." + operatorName(Op)); + Candidates.insert(Candidates.end(), Members.begin(), Members.end()); + } + for (const FuncSig *Sig : Candidates) { + bool Member = !Sig->Prototype->getOwnerClass().empty(); + if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u) - Member) continue; + if (!Member && !Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; + if (Right && !Right->sameType(resolveType(Sig->Params[Member ? 0 : 1].TypeName))) continue; if (Result.Signature) Result.Ambiguous = true; else Result.Signature = Sig; } return Result; } + +bool CodeGen::checkOperatorAccess(const FuncSig &Signature) { + const PrototypeAST *Proto = Signature.Prototype; + if (!Proto->getOwnerClass().empty() && !Proto->isPublic() && + !sameIdentifier(CurrentClass, Proto->getOwnerClass())) { + reportError("Cannot access private method %s of type %s", + Proto->getName().c_str(), Proto->getOwnerClass().c_str()); + return false; + } + return true; +} + +Value *CodeGen::materializeOperatorReceiver(Value *Val, const TypeInfo *Type) { + if (!Val || !Type) return nullptr; + auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "operator_receiver"); + size_t Object = registerStackObject(Storage, Type->Name, DiagnosticLine, false, true); + Builder->CreateStore(Val, Storage); + activateStackObject(Object); + return Storage; +} + +Value *CodeGen::emitOperatorCall(const FuncSig &Signature, ExprAST *Left, ExprAST *Right) { + if (!checkOperatorAccess(Signature)) return nullptr; + std::vector<Value*> Args; + std::vector<ExprAST*> Explicit; + if (Signature.Prototype->getOwnerClass().empty()) { + Explicit.push_back(Left); + } else { + Value *Receiver = nullptr; + if (dynamic_cast<VariableExprAST*>(Left) || dynamic_cast<ArrayAccessExprAST*>(Left) || + dynamic_cast<DesignatorExprAST*>(Left)) { + LValueInfo LV; + if (!emitLValue(Left, LV)) return nullptr; + Receiver = LV.Addr; + } else { + Receiver = materializeOperatorReceiver(emitExpr(Left), getExprTypeInfo(Left)); + } + if (!Receiver) return nullptr; + Args.push_back(Receiver); + } + if (Right) Explicit.push_back(Right); + if (!marshalCallArgs(Signature, Explicit, DiagnosticLine, Args)) return nullptr; + return FuncGen->emitCall(Signature, Args); +} + +// CASE has already evaluated and captured its selector and label values. +Value *CodeGen::emitOperatorValues(const FuncSig &Signature, Value *Left, + const TypeInfo *LeftType, Value *Right) { + if (!checkOperatorAccess(Signature)) return nullptr; + if (!Signature.Prototype->getOwnerClass().empty()) + Left = materializeOperatorReceiver(Left, LeftType); + if (!Left) return nullptr; + return FuncGen->emitCall(Signature, {Left, Right}); +} diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc index b09a5d9..e7a3f77 100644 --- a/lib/CodeGen/ValueTypeGen.cc +++ b/lib/CodeGen/ValueTypeGen.cc @@ -70,10 +70,14 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) { if (dynamic_cast<AddrOfExprAST*>(Expr)) return nullptr; if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) { + if (isWholeArrayVar(Unary->getOperand())) return nullptr; + const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand()); + auto Overload = resolveOperator(Unary->getOp(), Operand); + if (Overload.Ambiguous) return nullptr; + if (Overload.Signature) return resolveType(Overload.Signature->ReturnTypeName); if (Unary->getOp() == tok_not) { return resolveType("BOOLEAN"); } - const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand()); if (Operand && Operand->isC()) return Types->promoteCScalar(Operand); if (Operand && !Operand->isC() && !Operand->isUserKind()) return Operand->isReal() ? resolveType("REAL") : resolveType("INTEGER"); diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index f22e3c6..afe0e80 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -48,7 +48,7 @@ void Parser::syncToStatementStart() { switch (CurTok) { case tok_include: case tok_global: case tok_endglobal: case tok_include_obj: case tok_extern: - case tok_delete: case tok_constant: case tok_declare: case tok_identifier: case tok_input: case tok_output: + case tok_delete: case tok_constant: case tok_declare: case tok_identifier: case tok_operator: case tok_input: case tok_output: case tok_case: case tok_endcase: case tok_otherwise: case tok_if: case tok_while: case tok_repeat: case tok_for: case tok_overload: case tok_function: case tok_procedure: case tok_call: case tok_return: @@ -163,7 +163,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { if (CurTok == tok_declare) { return ParseDeclare(); } - else if (CurTok == tok_identifier) { + else if (CurTok == tok_identifier || CurTok == tok_operator) { return ParseAssignStmt(); } else if (CurTok == tok_input) { @@ -284,9 +284,16 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { // Bare-name and single-index targets degrade to their legacy nodes so the // existing assignment code paths stay untouched. std::unique_ptr<StmtAST> Parser::ParseAssignStmt() { - std::string Name = Lex.IdentifierStr; int Line = Lex.getLine(); - getNextToken(); + std::string Name; + if (CurTok == tok_operator) { + int Op; + Name = ParseOperatorName(Op); + if (Name.empty()) return nullptr; + } else { + Name = Lex.IdentifierStr; + getNextToken(); + } if (CurTok == '(') { getNextToken(); diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index a4f4fcc..6cde5bf 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -41,9 +41,16 @@ std::unique_ptr<ExprAST> Parser::ParseNumberExpr() { } std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { - std::string IdName = Lex.IdentifierStr; int Line = Lex.getLine(); - getNextToken(); + std::string IdName; + if (CurTok == tok_operator) { + int Op; + IdName = ParseOperatorName(Op); + if (IdName.empty()) return nullptr; + } else { + IdName = Lex.IdentifierStr; + getNextToken(); + } if (CurTok == '(' && !atCaseBoundary()) { getNextToken(); @@ -110,15 +117,21 @@ bool Parser::ParseDesignatorSuffix(std::vector<DesignatorAccess> &Out) { Out.push_back(std::move(A)); } else if (CurTok == '.') { getNextToken(); - if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete) { + if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete && CurTok != tok_operator) { cps::sourceDiagnostic(Lex.getLine(), "error: Expected field name after '.' at line %d\n", Lex.getLine()); return false; } DesignatorAccess A; A.Kind = AccessKind::Field; - A.FieldName = CurTok == tok_new ? "NEW" : CurTok == tok_delete ? "DELETE" : Lex.IdentifierStr; + if (CurTok == tok_operator) { + int Op; + A.FieldName = ParseOperatorName(Op); + if (A.FieldName.empty()) return false; + } else { + A.FieldName = CurTok == tok_new ? "NEW" : CurTok == tok_delete ? "DELETE" : Lex.IdentifierStr; + getNextToken(); + } Out.push_back(std::move(A)); - getNextToken(); } else if (CurTok == '^') { getNextToken(); DesignatorAccess A; @@ -172,7 +185,7 @@ std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { case tok_new: cps::sourceDiagnostic(Lex.getLine(), "error: NEW is only allowed on the right of an assignment at line %d\n", Lex.getLine()); return nullptr; - case tok_identifier: return ParseIdentifierExpr(); + case tok_identifier: case tok_operator: return ParseIdentifierExpr(); case tok_number_int: return ParseNumberExpr(); case tok_number_real: return ParseNumberExpr(); case tok_string_literal: { diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index 3ff54da..dfb689a 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -140,6 +140,10 @@ std::string Parser::ParseOperatorName(int &Op) { return {}; } getNextToken(); + if (CurTok != '(') { + sourceDiagnostic(Lex.getLine(), "error: Expected '(' after operator name at line %d\n", Lex.getLine()); + return {}; + } return operatorName(Op); } @@ -339,13 +343,20 @@ std::unique_ptr<StmtAST> Parser::ParseExternDecl() { std::unique_ptr<StmtAST> Parser::ParseCallStmt() { int Line = Lex.getLine(); getNextToken(); - if (CurTok != tok_identifier) { + if (CurTok != tok_identifier && CurTok != tok_operator) { cps::sourceDiagnostic(Lex.getLine(), "error: Expected callee name after CALL\n"); return nullptr; } - std::string Callee = Lex.IdentifierStr; - getNextToken(); + std::string Callee; + if (CurTok == tok_operator) { + int Op; + Callee = ParseOperatorName(Op); + if (Callee.empty()) return nullptr; + } else { + Callee = Lex.IdentifierStr; + getNextToken(); + } std::vector<DesignatorAccess> Accesses; if (!ParseDesignatorSuffix(Accesses)) return nullptr; |
