aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
-rw-r--r--lib/CodeGen/CodeGen.cc76
1 files changed, 61 insertions, 15 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 31a0274..ffe10b1 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -45,6 +45,10 @@ const BuiltinInfo *findBuiltin(const std::string &Name) {
CodeGen::~CodeGen() = default;
+bool CodeGen::isBuiltinName(const std::string &Name) {
+ return findBuiltin(Name) != nullptr;
+}
+
void CodeGen::reportError(const char *Fmt, ...) {
va_list Args;
va_start(Args, Fmt);
@@ -500,6 +504,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
Value *R = emitExpr(Bin->getRHS());
if (!L || !R) return nullptr;
if (Bin->getOp() == '&') {
+ L = coerceValueToType(L, resolveType("STRING"));
+ R = coerceValueToType(R, resolveType("STRING"));
+ if (!L || !R) return nullptr;
return StrHandler->emitConcat(L, R);
}
return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine());
@@ -536,13 +543,18 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return StrHandler->emitLeft(Str, Len);
}
if (Name == "LCASE") {
- return StrHandler->emitLCase(emitExpr(Call->getArgs()[0].get()));
+ Value *Str = emitExpr(Call->getArgs()[0].get());
+ if (!Str) return nullptr;
+ return StrHandler->emitLCase(Str);
}
if (Name == "UCASE") {
- return StrHandler->emitUCase(emitExpr(Call->getArgs()[0].get()));
+ Value *Str = emitExpr(Call->getArgs()[0].get());
+ if (!Str) return nullptr;
+ return StrHandler->emitUCase(Str);
}
if (Name == "ASC") {
Value *ArgVal = emitExpr(Call->getArgs()[0].get());
+ if (!ArgVal) return nullptr;
const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get());
Value *CharVal = nullptr;
if (ArgType && ArgType->isChar()) {
@@ -555,14 +567,18 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
if (Name == "CHR") {
Value *IntVal = coerceValueToType(emitExpr(Call->getArgs()[0].get()), resolveType("INTEGER"));
+ if (!IntVal) return nullptr;
Value *CharVal = Builder->CreateTrunc(IntVal, Type::getInt8Ty(*TheContext), "chr_val");
return coerceValueToType(CharVal, resolveType("STRING"));
}
if (Name == "IS_NUM") {
- return StrConvHandler->emitIsNum(emitExpr(Call->getArgs()[0].get()));
+ Value *Str = emitExpr(Call->getArgs()[0].get());
+ if (!Str) return nullptr;
+ return StrConvHandler->emitIsNum(Str);
}
if (Name == "NUM_TO_STR") {
Value *NumV = emitExpr(Call->getArgs()[0].get());
+ if (!NumV) return nullptr;
bool IsReal = NumV->getType()->isDoubleTy();
if (NumV->getType()->isIntegerTy(8)) {
NumV = coerceValueToType(NumV, resolveType("INTEGER"));
@@ -570,7 +586,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return StrConvHandler->emitNumToStr(NumV, IsReal);
}
if (Name == "STR_TO_NUM") {
- return StrConvHandler->emitStrToNum(emitExpr(Call->getArgs()[0].get()), true);
+ Value *Str = emitExpr(Call->getArgs()[0].get());
+ if (!Str) return nullptr;
+ return StrConvHandler->emitStrToNum(Str, true);
}
std::vector<Value*> Args;
@@ -602,18 +620,36 @@ bool CodeGen::marshalCallArgs(const std::string &Callee,
bool IsByRef = Sig->Params[i].second;
ExprAST *ArgExpr = ArgExprs[i].get();
+ // Parameters can never be arrays, so a whole-array argument is always
+ // a user error (and would smash the data pointer if let through).
+ if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ if (Info && Info->IsArray) {
+ reportError("Cannot pass whole array %s to %s; pass an element like %s[i]",
+ Var->getName().c_str(), Callee.c_str(), Var->getName().c_str());
+ return false;
+ }
+ }
+
if (IsByRef) {
auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr);
if (!Var) {
reportError("BYREF argument to %s must be a variable", Callee.c_str());
return false;
}
- Value *Ptr = getNamedValue(Var->getName());
- if (!Ptr) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ if (!Info) {
reportError("Unknown variable %s in BYREF call", Var->getName().c_str());
return false;
}
- Out.push_back(Ptr);
+ // BYREF aliases the storage, so the types must match exactly.
+ if (Info->TypeName != TypeName) {
+ reportError("BYREF argument %s to %s must be of type %s (got %s)",
+ Var->getName().c_str(), Callee.c_str(),
+ TypeName.c_str(), Info->TypeName.c_str());
+ return false;
+ }
+ Out.push_back(Info->Storage);
} else {
Value *V = coerceValueToType(emitExpr(ArgExpr), resolveType(TypeName));
if (!V) return false;
@@ -716,6 +752,15 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Value *Alloca = Symbol->Storage;
Builder->CreateStore(StartVal, Alloca);
+ // STEP is evaluated exactly once, before the loop.
+ Value *StepVal = nullptr;
+ if (Stmt->getStep()) {
+ StepVal = coerceValueToType(emitExpr(Stmt->getStep()), resolveType("INTEGER"));
+ if (!StepVal) return;
+ } else {
+ StepVal = ConstantInt::get(*TheContext, APInt(64, 1));
+ }
+
BasicBlock *CondBB = BasicBlock::Create(*TheContext, "forcond", TheFunction);
BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "forloop", TheFunction);
BasicBlock *IncBB = BasicBlock::Create(*TheContext, "forinc", TheFunction);
@@ -728,14 +773,6 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Value *EndVal = coerceValueToType(emitExpr(Stmt->getEnd()), resolveType("INTEGER"));
if (!EndVal) return;
- Value *StepVal = nullptr;
- if (Stmt->getStep()) {
- StepVal = coerceValueToType(emitExpr(Stmt->getStep()), resolveType("INTEGER"));
- if (!StepVal) return;
- } else {
- StepVal = ConstantInt::get(*TheContext, APInt(64, 1));
- }
-
// The loop direction depends on the STEP value at run time.
Value *StepNonNeg = Builder->CreateICmpSGE(StepVal,
ConstantInt::get(*TheContext, APInt(64, 0)),
@@ -795,6 +832,11 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Value *RetVal = nullptr;
if (Ret->getRetVal()) {
RetVal = emitExpr(Ret->getRetVal());
+ Function *F = Builder->GetInsertBlock()->getParent();
+ if (const FuncSig *Sig = FuncGen->getSignature(F->getName().str())) {
+ RetVal = coerceValueToType(RetVal, resolveType(Sig->ReturnTypeName));
+ if (!RetVal) return;
+ }
}
FuncGen->emitReturn(Ret, RetVal);
return;
@@ -885,6 +927,10 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Cannot infer the type of the OUTPUT expression");
return;
}
+ if (TypeInfo->isVoid()) {
+ reportError("Cannot OUTPUT the result of a PROCEDURE call");
+ return;
+ }
emitOutputValue(Val, TypeInfo, true);
return;
}