aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/CodeGen.cc24
-rw-r--r--lib/CodeGen/ConstructorGen.cc68
-rw-r--r--lib/CodeGen/ControlFlowGen.cc7
-rw-r--r--lib/CodeGen/Designator.cc12
-rw-r--r--lib/CodeGen/ExceptionHandler.cc7
-rw-r--r--lib/CodeGen/FunctionGen.cc11
-rw-r--r--lib/CodeGen/OperatorGen.cc26
-rw-r--r--lib/CodeGen/StatementGen.cc21
-rw-r--r--lib/Parser/Parser.cc6
-rw-r--r--lib/Parser/ParserExpression.cc38
-rw-r--r--lib/Parser/ParserFunction.cc6
11 files changed, 206 insertions, 20 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index c9d8c1a..49fc7b1 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -390,6 +390,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
return false;
}
+ std::vector<size_t> Transfers;
for (size_t i = 0; i < ArgExprs.size(); ++i) {
if (i >= Sig->Params.size()) {
Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1);
@@ -423,6 +424,26 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
if (IsByRef) {
auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr);
+ bool InternalBinding = Signature.Prototype &&
+ (sameIdentifier(Signature.Prototype->getName(), "NEW") ||
+ Signature.Prototype->getOperator() == tok_assign);
+ if (!Var && InternalBinding) {
+ const TypeInfo *Actual = getExprTypeInfo(ArgExpr);
+ if (!Actual || !Actual->sameType(resolveType(TypeName))) {
+ reportError("BYREF argument to %s has an incompatible type", Callee.c_str());
+ return false;
+ }
+ if (isObjectLValue(ArgExpr)) {
+ LValueInfo LV;
+ if (!emitLValue(ArgExpr, LV)) return false;
+ Out.push_back(LV.Addr);
+ } else {
+ Value *Storage = materializeOperatorReceiver(emitExpr(ArgExpr), Actual);
+ if (!Storage) return false;
+ Out.push_back(Storage);
+ }
+ continue;
+ }
if (!Var) {
reportError("BYREF argument to %s must be a variable", Callee.c_str());
return false;
@@ -442,11 +463,12 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
}
Out.push_back(symbolAddress(*Info));
} else {
- Value *V = emitCoercedExpr(ArgExpr, resolveType(TypeName));
+ Value *V = emitOwnedValue(ArgExpr, resolveType(TypeName), Transfers);
if (!V) return false;
Out.push_back(V);
}
}
+ transferObjects(Transfers);
return true;
}
diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc
index e1033c3..4bf5568 100644
--- a/lib/CodeGen/ConstructorGen.cc
+++ b/lib/CodeGen/ConstructorGen.cc
@@ -8,6 +8,70 @@
using namespace llvm;
using namespace cps;
+bool CodeGen::isObjectLValue(ExprAST *Expr) const {
+ return dynamic_cast<VariableExprAST *>(Expr) || dynamic_cast<ArrayAccessExprAST *>(Expr) ||
+ dynamic_cast<DesignatorExprAST *>(Expr);
+}
+
+void CodeGen::transferObjects(const std::vector<size_t> &Objects) {
+ for (size_t Index : Objects)
+ if (Index != size_t(-1)) Builder->CreateStore(Builder->getFalse(), StackObjects[Index].Alive);
+}
+
+Value *CodeGen::emitOwnedValue(ExprAST *Expr, const TypeInfo *Type,
+ std::vector<size_t> &Transfers) {
+ if (!Type || !Type->IsClass) return emitCoercedExpr(Expr, Type);
+ const TypeInfo *Source = getExprTypeInfo(Expr);
+ if (!Source || !Source->sameType(Type)) return emitCoercedExpr(Expr, Type);
+ Value *Value = nullptr;
+ if (isObjectLValue(Expr)) {
+ LValueInfo LV;
+ if (!emitLValue(Expr, LV)) return nullptr;
+ return copyClassValue(Type, LV.Addr, Transfers);
+ }
+ Value = emitCoercedExpr(Expr, Type);
+ if (!Value) return nullptr;
+ // A pending argument owns its result until all remaining arguments succeed.
+ auto *Storage = materializeOperatorReceiver(Value, Type);
+ if (typeNeedsDestruction(Type->Name)) Transfers.push_back(StackObjects.size() - 1);
+ return Builder->CreateLoad(Type->LLVMType, Storage);
+}
+
+Value *CodeGen::copyClassValue(const TypeInfo *Type, Value *Address,
+ std::vector<size_t> &Transfers) {
+ const FuncSig *Copy = nullptr;
+ for (const FuncSig *Sig : FuncGen->getOverloads(Type->Name + ".NEW"))
+ if (Sig->IsOverload && Sig->Params.size() == 1 && Sig->Params[0].IsByRef &&
+ !Sig->Params[0].IsArray && Type->sameType(resolveType(Sig->Params[0].TypeName)))
+ Copy = Sig;
+ if (!Copy) return Builder->CreateLoad(Type->LLVMType, Address);
+ if (!checkOperatorAccess(*Copy)) return nullptr;
+ auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(),
+ Type->LLVMType, "copy_object");
+ size_t Lifetime = registerStackObject(Storage, Type->Name, DiagnosticLine, false, true);
+ if (Lifetime != size_t(-1)) StackObjects[Lifetime].Temporary = true;
+ Builder->CreateStore(Types->getZeroValue(Type->Name), Storage);
+ for (const auto &[Name, Field] : Type->Record.Fields) {
+ if (typeNeedsConstruction(Field.TypeName) &&
+ !emitDefaultConstruct(Field.TypeName,
+ Builder->CreateStructGEP(Type->LLVMType, Storage, Field.Index), DiagnosticLine))
+ return nullptr;
+ }
+ if (!FuncGen->emitCall(*Copy, {Storage, Address})) return nullptr;
+ activateStackObject(Lifetime);
+ Transfers.push_back(Lifetime);
+ return Builder->CreateLoad(Type->LLVMType, Storage, "copied_value");
+}
+
+void CodeGen::cleanupTemporaries(size_t Start) {
+ if (!Builder->GetInsertBlock() || Builder->GetInsertBlock()->hasTerminator()) return;
+ // Destructor emission can itself register temporaries. Copy each record before emitting.
+ for (size_t I = StackObjects.size(); I > Start; --I) {
+ auto Object = StackObjects[I - 1];
+ if (Object.Temporary) emitStackObjectCleanup(Object);
+ }
+}
+
bool CodeGen::typeNeedsConstruction(const std::string &TypeName) const {
if (findMethod(TypeName, "NEW")) return true;
const TypeInfo *Info = resolveType(TypeName);
@@ -169,8 +233,8 @@ void CodeGen::emitStackObjectCleanup(const StackObject &Object) {
}
void CodeGen::finishStackObjects(Function *F) {
- Exceptions->fillCleanups(F, [this] {
+ Exceptions->fillCleanups(F, [this](bool TemporariesOnly) {
for (auto It = StackObjects.rbegin(); It != StackObjects.rend(); ++It)
- emitStackObjectCleanup(*It);
+ if (!TemporariesOnly || It->Temporary) emitStackObjectCleanup(*It);
});
}
diff --git a/lib/CodeGen/ControlFlowGen.cc b/lib/CodeGen/ControlFlowGen.cc
index 0cf0c34..414fe19 100644
--- a/lib/CodeGen/ControlFlowGen.cc
+++ b/lib/CodeGen/ControlFlowGen.cc
@@ -29,6 +29,7 @@ void CodeGen::emitTryStmt(TryStmtAST *Stmt) {
void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
if (!CondV) return;
+ cleanupTemporaries();
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction);
@@ -65,6 +66,7 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
if (!CondV) return;
+ cleanupTemporaries();
Builder->CreateCondBr(CondV, LoopBB, AfterBB);
@@ -100,6 +102,7 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
if (!CondV) return;
+ cleanupTemporaries();
Builder->CreateCondBr(CondV, AfterBB, LoopBB);
@@ -127,6 +130,8 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Value *Alloca = Symbol->Storage;
Builder->CreateStore(StartVal, Alloca);
+ cleanupTemporaries();
+
// STEP is evaluated exactly once, before the loop.
Value *StepVal = nullptr;
if (Stmt->getStep()) {
@@ -136,6 +141,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
StepVal = ConstantInt::get(*TheContext, APInt(64, 1));
}
+ cleanupTemporaries();
BasicBlock *CondBB = BasicBlock::Create(*TheContext, "forcond", TheFunction);
BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "forloop", TheFunction);
BasicBlock *IncBB = BasicBlock::Create(*TheContext, "forinc", TheFunction);
@@ -147,6 +153,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
Value *EndVal = emitCoercedExpr(Stmt->getEnd(), resolveType("INTEGER"));
if (!EndVal) return;
+ cleanupTemporaries();
// The loop direction depends on the STEP value at run time.
Value *StepNonNeg = Builder->CreateICmpSGE(StepVal,
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
index 5fb0ed3..b9c9a1a 100644
--- a/lib/CodeGen/Designator.cc
+++ b/lib/CodeGen/Designator.cc
@@ -98,7 +98,17 @@ const FuncSig *CodeGen::resolveMethod(const std::string &Class, const std::strin
Value *CodeGen::emitMemberCall(MemberCallExprAST *Call) {
SaveAndRestore<int> Location(DiagnosticLine, Call->getLine());
LValueInfo Receiver;
- if (!emitLValue(Call->getReceiver(), Receiver)) return nullptr;
+ if (isObjectLValue(Call->getReceiver())) {
+ if (!emitLValue(Call->getReceiver(), Receiver)) return nullptr;
+ } else {
+ const TypeInfo *Type = getExprTypeInfo(Call->getReceiver());
+ if (!Type || !Type->IsClass) {
+ reportError("A temporary method receiver must be a class");
+ return nullptr;
+ }
+ Receiver = {materializeOperatorReceiver(emitExpr(Call->getReceiver()), Type), Type->Name};
+ if (!Receiver.Addr) return nullptr;
+ }
return emitMethodCall(Receiver.TypeName, Receiver.Addr, Call->getMethod(),
Call->getArgs(), Call->getLine());
}
diff --git a/lib/CodeGen/ExceptionHandler.cc b/lib/CodeGen/ExceptionHandler.cc
index 3f69417..c879a87 100644
--- a/lib/CodeGen/ExceptionHandler.cc
+++ b/lib/CodeGen/ExceptionHandler.cc
@@ -94,7 +94,7 @@ void ExceptionHandler::recordExit(Instruction *Before, bool Unwinding) {
CleanupPoints[F].push_back({Before, States[F], Unwinding});
}
-void ExceptionHandler::fillCleanups(Function *F, const std::function<void()> &Destroy) {
+void ExceptionHandler::fillCleanups(Function *F, const std::function<void(bool)> &Destroy) {
IRBuilderBase::InsertPointGuard Guard(Builder);
SaveAndRestore<FunctionState> StateGuard(States[F]);
auto &Points = CleanupPoints[F];
@@ -107,7 +107,7 @@ void ExceptionHandler::fillCleanups(Function *F, const std::function<void()> &De
auto *Continuation = BB->splitBasicBlock(Point.Before->getIterator(), "after_destruction");
BB->getTerminator()->eraseFromParent();
Builder.SetInsertPoint(BB);
- Destroy();
+ Destroy(Point.TemporariesOnly);
Builder.CreateBr(Continuation);
}
Points.clear();
@@ -133,7 +133,8 @@ BasicBlock *ExceptionHandler::emitUnwindDestination() {
for (unsigned I = TargetDepth; I < State.CatchDepth; ++I) Builder.CreateCall(EndCatch);
if (Handler) {
Builder.CreateStore(Builder.CreateExtractValue(LP, 0), Handler->Exception);
- Builder.CreateBr(Handler->Target);
+ auto *Branch = Builder.CreateBr(Handler->Target);
+ CleanupPoints[F].push_back({Branch, States[F], true, true});
} else {
recordExit(Builder.CreateResume(LP), true);
}
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index a0d0e32..37df8ff 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -91,7 +91,7 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vector<ParamDecl
IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin());
AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, P.Name);
- // Shallow BYVAL copy. The common lifetime hook is the future copy-constructor point.
+ // The caller constructs class arguments; this slot takes ownership of the value.
Builder.CreateStore(ArgVal, Alloca);
const TypeInfo *Info = Types.resolve(P.TypeName);
if (Info && Info->IsClass) {
@@ -123,6 +123,15 @@ const FuncSig *FunctionGen::getSignatureByLink(const std::string &Name) const {
Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
auto Registered = PrototypeLinks.find(Proto);
if (Registered != PrototypeLinks.end()) return Module.getFunction(Registered->second);
+ if (!Proto->getOwnerClass().empty() && sameIdentifier(Proto->getName(), "NEW") &&
+ Proto->getParams().size() == 1) {
+ const auto &P = Proto->getParams()[0];
+ if (!P.IsArray && sameIdentifier(P.TypeName, Proto->getOwnerClass()) &&
+ P.Mode != PassMode::ByRef) {
+ reportError("A copy constructor must take BYREF to its own class");
+ return nullptr;
+ }
+ }
if (int Op = Proto->getOperator()) {
size_t Count = Proto->getParams().size() + !Proto->getOwnerClass().empty();
bool ValidCount = Op == '-' ? Count == 1 || Count == 2
diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc
index d340ed7..b449ba1 100644
--- a/lib/CodeGen/OperatorGen.cc
+++ b/lib/CodeGen/OperatorGen.cc
@@ -45,6 +45,7 @@ Value *CodeGen::materializeOperatorReceiver(Value *Val, const TypeInfo *Type) {
size_t Object = registerStackObject(Storage, Type->Name, DiagnosticLine, false, true);
Builder->CreateStore(Val, Storage);
activateStackObject(Object);
+ if (Object != size_t(-1)) StackObjects[Object].Temporary = true;
return Storage;
}
@@ -76,8 +77,25 @@ Value *CodeGen::emitOperatorCall(const FuncSig &Signature, ExprAST *Left, ExprAS
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});
+ bool Member = !Signature.Prototype->getOwnerClass().empty();
+ std::vector<Value *> Args;
+ std::vector<size_t> Transfers;
+ auto Capture = [&](Value *Val, const TypeInfo *Type) -> Value * {
+ auto *Slot = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(),
+ Type->LLVMType, "case_operand");
+ Builder->CreateStore(Val, Slot);
+ return Slot;
+ };
+ if (Member) Args.push_back(Capture(Left, LeftType));
+ else {
+ if (LeftType->IsClass) Left = copyClassValue(LeftType, Capture(Left, LeftType), Transfers);
+ if (!Left) return nullptr;
+ Args.push_back(Left);
+ }
+ const TypeInfo *RightType = resolveType(Signature.Params[Member ? 0 : 1].TypeName);
+ if (RightType->IsClass) Right = copyClassValue(RightType, Capture(Right, RightType), Transfers);
+ if (!Right) return nullptr;
+ Args.push_back(Right);
+ transferObjects(Transfers);
+ return FuncGen->emitCall(Signature, Args);
}
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index 99a269d..c0bc223 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -10,6 +10,12 @@ using namespace llvm;
using namespace cps;
void CodeGen::emitStmt(StmtAST *Stmt) {
+ size_t Start = StackObjects.size();
+ emitStmtImpl(Stmt);
+ cleanupTemporaries(Start);
+}
+
+void CodeGen::emitStmtImpl(StmtAST *Stmt) {
SaveAndRestore<int> Location(DiagnosticLine, Stmt && Stmt->getLine() ? Stmt->getLine() : DiagnosticLine);
if (!Stmt) return;
@@ -89,12 +95,18 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
if (auto *Call = dynamic_cast<MemberCallStmtAST*>(Stmt)) {
- emitMemberCall(Call->getCall());
+ Value *Result = emitMemberCall(Call->getCall());
+ const TypeInfo *Type = getExprTypeInfo(Call->getCall());
+ if (Result && Type && Type->IsClass) materializeOperatorReceiver(Result, Type);
return;
}
if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
- emitCall(Call->getCallee(), Call->getArgs(), Call->getLine());
+ Value *Result = emitCall(Call->getCallee(), Call->getArgs(), Call->getLine());
+ const FuncSig *Sig = FuncGen->hasFunction(Call->getCallee())
+ ? resolveCall(Call->getCallee(), Call->getArgs()) : nullptr;
+ const TypeInfo *Type = Sig ? resolveType(Sig->ReturnTypeName) : nullptr;
+ if (Result && Type && Type->IsClass) materializeOperatorReceiver(Result, Type);
return;
}
@@ -117,9 +129,12 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
Value *RetVal = nullptr;
if (Ret->getRetVal()) {
- RetVal = emitCoercedExpr(Ret->getRetVal(), resolveType(Sig->ReturnTypeName));
+ std::vector<size_t> Transfers;
+ RetVal = emitOwnedValue(Ret->getRetVal(), resolveType(Sig->ReturnTypeName), Transfers);
+ transferObjects(Transfers);
if (!RetVal) return;
}
+ cleanupTemporaries();
FuncGen->emitReturn(Ret, RetVal);
return;
}
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index afe0e80..48f4df4 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -299,6 +299,12 @@ std::unique_ptr<StmtAST> Parser::ParseAssignStmt() {
getNextToken();
auto Args = ParseExprList(')', true);
if (!Args) return nullptr;
+ if (CurTok == '.') {
+ auto Result = ParseResultMethods(std::make_unique<CallExprAST>(Name, std::move(*Args), Line), Line);
+ if (!Result) return nullptr;
+ return std::make_unique<MemberCallStmtAST>(
+ std::unique_ptr<MemberCallExprAST>(static_cast<MemberCallExprAST *>(Result.release())));
+ }
return std::make_unique<CallStmtAST>(Name, std::move(*Args), Line);
}
diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc
index 6cde5bf..7558c86 100644
--- a/lib/Parser/ParserExpression.cc
+++ b/lib/Parser/ParserExpression.cc
@@ -56,12 +56,12 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() {
getNextToken();
auto Args = ParseExprList(')', true);
if (!Args) return nullptr;
- if (CurTok == '[' || CurTok == '.' || CurTok == '^') {
+ if (CurTok == '[' || CurTok == '^') {
cps::sourceDiagnostic(Lex.getLine(), "error: record/array/pointer access on a function result is not supported at line %d\n",
Lex.getLine());
return nullptr;
}
- return std::make_unique<CallExprAST>(IdName, std::move(*Args), Line);
+ return ParseResultMethods(std::make_unique<CallExprAST>(IdName, std::move(*Args), Line), Line);
}
std::vector<DesignatorAccess> Accesses;
@@ -95,12 +95,13 @@ std::unique_ptr<MemberCallExprAST> Parser::ParseMemberCall(
if (!Parsed) return nullptr;
Args = std::move(*Parsed);
}
- if (CurTok == '[' || CurTok == '.' || CurTok == '^') {
+ if (CurTok == '[' || CurTok == '^') {
cps::sourceDiagnostic(Lex.getLine(), "error: record/array/pointer access on a function result is not supported at line %d\n",
Lex.getLine());
return nullptr;
}
- return std::make_unique<MemberCallExprAST>(std::move(Receiver), Method, std::move(Args), Line);
+ auto Result = ParseResultMethods(std::make_unique<MemberCallExprAST>(std::move(Receiver), Method, std::move(Args), Line), Line);
+ return std::unique_ptr<MemberCallExprAST>(static_cast<MemberCallExprAST *>(Result.release()));
}
// Postfix accessor chain after an identifier: '[' exprs ']' | '.' IDENT | '^'
@@ -173,11 +174,38 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() {
return V;
}
+std::unique_ptr<ExprAST> Parser::ParseResultMethods(std::unique_ptr<ExprAST> Expr, int Line) {
+ while (CurTok == '.' && !atCaseBoundary()) {
+ getNextToken();
+ std::string Name;
+ if (CurTok == tok_operator) {
+ int Op;
+ Name = ParseOperatorName(Op);
+ if (Name.empty()) return nullptr;
+ } else if (CurTok == tok_identifier || CurTok == tok_delete) {
+ Name = CurTok == tok_delete ? "DELETE" : Lex.IdentifierStr;
+ getNextToken();
+ } else {
+ sourceDiagnostic(Lex.getLine(), "error: Expected method name at line %d\n", Lex.getLine());
+ return nullptr;
+ }
+ if (CurTok != '(') {
+ sourceDiagnostic(Lex.getLine(), "error: Expected '(' after method name at line %d\n", Lex.getLine());
+ return nullptr;
+ }
+ getNextToken();
+ auto Args = ParseExprList(')', true);
+ if (!Args) return nullptr;
+ Expr = std::make_unique<MemberCallExprAST>(std::move(Expr), Name, std::move(*Args), Line);
+ }
+ return Expr;
+}
+
std::unique_ptr<ExprAST> Parser::ParsePrimary() {
int Line = Lex.getLine();
auto Expr = ParsePrimaryImpl();
if (Expr && !Expr->getLine()) Expr->setLine(Line);
- return Expr;
+ return Expr ? ParseResultMethods(std::move(Expr), Line) : nullptr;
}
std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() {
diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc
index dfb689a..65e0b85 100644
--- a/lib/Parser/ParserFunction.cc
+++ b/lib/Parser/ParserFunction.cc
@@ -374,6 +374,12 @@ std::unique_ptr<StmtAST> Parser::ParseCallStmt() {
Args = std::move(*Parsed);
}
+ if (CurTok == '.') {
+ auto Result = ParseResultMethods(std::make_unique<CallExprAST>(Callee, std::move(Args), Line), Line);
+ if (!Result) return nullptr;
+ return std::make_unique<MemberCallStmtAST>(
+ std::unique_ptr<MemberCallExprAST>(static_cast<MemberCallExprAST *>(Result.release())));
+ }
return std::make_unique<CallStmtAST>(Callee, std::move(Args), Line);
}