void EditorInterface::makeIni() { FNTRACE("", "EditorInterface", "makeIni", ""); assert(!fileName.isEmpty()); QFile iniFile(fileName+".ini"); if (!iniFile.open(QIODevice::WriteOnly | QIODevice::Text)) ETHROW(Exception(QString("Could not open %1 for writing.").arg(iniFile.fileName()))); QTextStream iniOut(&iniFile); for (MapList::iterator mapIter = mapList.begin(); mapIter != mapList.end(); ++mapIter) { iniOut << mapIter->typeId << ' ' << mapIter->prestDef << ' ' << mapIter->file << '\n'; } }
void IRGenerator::accept(Handler& handler) { FNTRACE(); setHandler(getHandler(handler.name())); setInsertPoint(createBlock("EntryPoint")); this->handler()->setEntryPoint(getInsertPoint()); for (Symbol* symbol: *handler.scope()) { codegen(symbol); } codegen(handler.body()); createRet(get(false)); }
std::unique_ptr<Stmt> FlowParser::postscriptStmt(std::unique_ptr<Stmt> baseStmt) { FNTRACE(); if (token() == FlowToken::Semicolon) { nextToken(); return baseStmt; } if (baseStmt->location().end.line != lexer_->line()) return baseStmt; FlowToken op = token(); switch (op) { case FlowToken::If: case FlowToken::Unless: break; default: return baseStmt; } // STMT ['if' EXPR] ';' // STMT ['unless' EXPR] ';' FlowLocation sloc = location(); nextToken(); // 'if' | 'unless' std::unique_ptr<Expr> condExpr = expr(); if (!condExpr) return nullptr; consumeIf(FlowToken::Semicolon); if (op == FlowToken::Unless) { auto opc = makeOperator(FlowToken::Not, condExpr.get()); if (opc == Opcode::EXIT) { reportError("Type cast error. No cast implementation found for requested cast from %s to %s.", tos(condExpr->getType()).c_str(), "bool"); return nullptr; } condExpr = std::make_unique<UnaryExpr>(opc, std::move(condExpr), sloc); } return std::make_unique<CondStmt>(std::move(condExpr), std::move(baseStmt), nullptr, sloc.update(end())); }
void IRGenerator::accept(Handler& handlerSym) { FNTRACE(); assert(handlerStack_.empty()); setHandler(getHandler(handlerSym.name())); setInsertPoint(createBlock("EntryPoint")); codegenInline(handlerSym); createRet(get(false)); handler()->verify(); assert(handlerStack_.empty()); }
void InitialConfigDialog::saveData() { FNTRACE("", "InitialConfigDialog", "saveData", ""); ini::AttributeMap data; lineedit("ds1editpath", editorPath, "", false, data); lineedit("ds1editname", editorName, "", false, data); // make sure file exists QFile iniFile("ds1edit_loader.ini"); if (!iniFile.exists()) { iniFile.open(QIODevice::ReadWrite | QIODevice::Text); iniFile.close(); } ini::loader::writeData(data, ini::full); }
void IRGenerator::accept(MatchStmt& stmt) { FNTRACE(); // TODO BasicBlock* contBlock = createBlock("match.cont"); MatchInstr* matchInstr = new MatchInstr(stmt.op()); Value* cond = codegen(stmt.condition()); matchInstr->setCondition(cond); for (const MatchCase& one: stmt.cases()) { Value* label; if (auto e = dynamic_cast<StringExpr*>(one.first.get())) label = get(e->value()); else if (auto e = dynamic_cast<RegExpExpr*>(one.first.get())) label = get(e->value()); else { reportError("FIXME: Invalid (unsupported) literal type <%s> in match case.", tos(one.first->getType()).c_str()); result_ = nullptr; return; } BasicBlock* bb = createBlock("match.case"); setInsertPoint(bb); codegen(one.second.get()); createBr(contBlock); matchInstr->addCase(label, bb); } if (stmt.elseStmt()) { BasicBlock* elseBlock = createBlock("match.else"); setInsertPoint(elseBlock); codegen(stmt.elseStmt()); createBr(contBlock); matchInstr->setElseBlock(elseBlock); } setInsertPoint(contBlock); }
void IRGenerator::accept(ArrayExpr& arrayExpr) { FNTRACE(); // loads a new array of given elements from regs[1] to regs[N], where regs[0] equals N; Value* array = createAlloca(arrayExpr.getType(), get(1 + arrayExpr.values().size())); // store array size at array[0] createArraySet(array, get(0), get(arrayExpr.values().size())); // store array values at array[1] to array[N] for (size_t i = 1, e = 1 + arrayExpr.values().size(); i != e; ++i) { Value* element = codegen(arrayExpr.values()[i].get()); createArraySet(array, get(i), element); } result_ = array; }
void EditorInterface::run() { FNTRACE("", "EditorInterface", "run", ""); assert(!editorProcess || editorProcess->state() == QProcess::NotRunning); if (!(QFileInfo(editorDir.filePath(editorName))).exists()) ETHROW(Exception("The Loader can't find the Ds1 Editor. " "You must setup the Loader's ini to select where the Ds1 Editor .exe is. " "Use the menu \"Settings->Configure Loader\".")); QDir temp = QDir::temp(); int i = 0; // find first tempX.ini that doesn't exist in temporary directory while (QFileInfo(temp.filePath(QString("temp%1.ini").arg(i))).exists()) ++i; if (!editorProcess) editorProcess = new QProcess(this); fileName = temp.filePath(QString("temp%1").arg(i)); makeRelativePaths(); QStringList args = makeArgs(); output->clear(); output->insertPlainText("ds1edit Loader: starting editor using program\n"); output->insertPlainText(editorDir.filePath(editorName)); output->insertPlainText("\nand arguments\n\""); output->insertPlainText(args.join("\" \"")); connect(editorProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(terminated(int, QProcess::ExitStatus))); connect(editorProcess, SIGNAL(readyReadStandardOutput()), SLOT(editorOutputReady())); editorProcess->setWorkingDirectory(editorDir.absolutePath()); output->insertPlainText("\"\nStarting from directory: "); output->insertPlainText(editorProcess->workingDirectory()); output->insertPlainText("\n\n"); editorProcess->start(editorDir.filePath(editorName), args, QIODevice::ReadOnly | QIODevice::Text); //if (!editorProcess->waitForStarted()) // ETHROW(Exception("Editor process failed to start")); }
void EditorInterface::makeRelativePaths() { FNTRACE("", "EditorInterface", "makeRelativePaths", ""); QString editorPath = editorDir.absolutePath(); for (MapList::iterator mapIter = mapList.begin(); mapIter != mapList.end(); ++mapIter) { if (mapIter->file.startsWith(editorPath)) mapIter->file = mapIter->file.mid(editorPath.length()+1); // +1 for / } for (QStringList::iterator dt1Iter = dt1List.begin(); dt1Iter != dt1List.end(); ++dt1Iter) { if (dt1Iter->startsWith(editorPath)) (*dt1Iter) = dt1Iter->mid(editorPath.length()+1); } if (fileName.startsWith(editorPath)) fileName = fileName.mid(editorPath.length()+1); }
// }}} // {{{ stmt std::unique_ptr<Stmt> FlowParser::stmt() { FNTRACE(); switch (token()) { case FlowToken::If: return ifStmt(); case FlowToken::Begin: return compoundStmt(); case FlowToken::Ident: return callStmt(); case FlowToken::Semicolon: { FlowLocation sloc(location()); nextToken(); return std::make_unique<CompoundStmt>(sloc.update(end())); } default: reportError("Unexpected token '%s'. Expected a statement instead.", token().c_str()); return nullptr; } }
void InitialConfigDialog::browseEditor() { FNTRACE("", "InitialConfigDialog", "browseEditor", ""); QString executablePath = QFileDialog::getOpenFileName(this, "Select ds1edit executable", editorPath->text(), "Executable Files (*.exe);;All Files (*.*)"); if (executablePath.length()) { QFileInfo executable(executablePath); assert(executable.exists()); editorPath->setText(executable.absolutePath()); editorName->setText(executable.fileName()); } if (!editorPath->text().isEmpty() && !editorName->text().isEmpty()) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } }
void IRGenerator::accept(CondStmt& stmt) { FNTRACE(); BasicBlock* trueBlock = createBlock("trueBlock"); BasicBlock* falseBlock = createBlock("falseBlock"); BasicBlock* contBlock = createBlock("contBlock"); Value* cond = codegen(stmt.condition()); createCondBr(cond, trueBlock, falseBlock); setInsertPoint(trueBlock); codegen(stmt.thenStmt()); createBr(contBlock); setInsertPoint(falseBlock); codegen(stmt.elseStmt()); createBr(contBlock); setInsertPoint(contBlock); }
EditorInterface::EditorInterface(LoaderDialog* dialog, const QString& path, const QString& name) : editorDir(path), editorName(name), editorProcess(0) { FNTRACE("", "EditorInterface", "EditorInterface", "LoaderDialog* dialog"); assert(dialog->mapList->topLevelItemCount() > 0); #define SYNCCHECKED(name) name = dialog-> name ->isChecked() SYNCCHECKED(resize); SYNCCHECKED(forceDt1); SYNCCHECKED(forcePalette); SYNCCHECKED(noCheckAct); SYNCCHECKED(autoPrestDef); #undef SYNCCHECKED #define GETNUMVAL(name) dialog-> name ->text().toInt() act = GETNUMVAL(forcePalAct); x = GETNUMVAL(resizeX); y = GETNUMVAL(resizeY); #undef GETNUMVAL dt1List = dialog->dt1List; Ds1Info map; QTreeWidgetItem* item; for (int i = 0, itemCount = dialog->mapList->topLevelItemCount(); i < itemCount; ++i) { map.clear(); item = dialog->mapList->topLevelItem(i); map.file = item->text(0); map.name = item->text(1); map.path = item->text(2); map.typeId = item->text(3).toInt(); if (autoPrestDef) map.prestDef = -1; else map.prestDef = item->text(4).toInt(); map.comment = item->text(5).toInt(); mapList.append(map); } output = dialog->editorOutput; }
void readData(const QString& filename, AttributeMap& data) throw(ParseError, Exception) { FNTRACE("ini", "", "readData", QString("%1, %2 rows of data").arg(filename).arg(data.size())); QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) ETHROW(Exception(QString("Unable to open %1 for reading.").arg(filename))); QByteArray line; size_t lineNumber = 0; while (!file.atEnd()) { line = file.readLine(); ++lineNumber; // trim comments and whitespace if (line.isEmpty()) continue; if (line.contains(COMMENT_BEGIN)) line.truncate(line.indexOf(COMMENT_BEGIN)); if (line.isEmpty()) continue; line = line.trimmed(); if (line.isEmpty()) continue; // name=value pair? else if (line.contains(ASSIGNER)) { QString name = line.left(line.indexOf(ASSIGNER)); name = name.trimmed(); if (name.isEmpty()) ETHROW(ParseError(filename, lineNumber, "Empty name left of assigner.")); QString value = line.right(line.length() - line.indexOf(ASSIGNER) - 1); value = value.trimmed(); data[name] = value; } else ETHROW(ParseError(filename, lineNumber, "Unknown non-empty line.")); } }
void EditorInterface::makeBatch(QString& batchFileName) { FNTRACE("", "EditorInterface", "batchFileName", batchFileName); if (batchFileName.endsWith(".bat", Qt::CaseInsensitive)) fileName = batchFileName.left(batchFileName.length()-4); else fileName = batchFileName; makeRelativePaths(); batchFileName = fileName+".bat"; QString debugFileName = fileName + "_debug.txt"; QStringList args = makeArgs(); QFile batchFile(batchFileName); if (!batchFile.open(QIODevice::WriteOnly | QIODevice::Text)) ETHROW(Exception(QString("Failed to open %1 for writing").arg(batchFileName))); QTextStream batch(&batchFile); batch << "@echo off\n"; if (QDir::drives().size()>1) batch << editorDir.absolutePath().left(2) << "\n"; batch << "cd \"" << editorDir.absolutePath() << "\"\n" << editorName; for (QStringList::iterator arg = args.begin(); arg != args.end(); ++arg) { batch << ' '; if (arg->contains(' ')) batch << '"'+(*arg)+'"'; else batch << (*arg); } batch << " > \"" << debugFileName << "\"\n" "If ERRORLEVEL 0 goto DONE\n" "pause\n" ":DONE\n"; }
void IRGenerator::accept(ArrayExpr& arrayExpr) { FNTRACE(); std::vector<Value*> values; for (size_t i = 0, e = arrayExpr.values().size(); i != e; ++i) { Value* element = codegen(arrayExpr.values()[i].get()); values.push_back(element); } if (isConstant(values)) { std::vector<Constant*> constants; for (Value* value: values) constants.push_back(static_cast<Constant*>(value)); result_ = get(constants); } else { // TODO: print line:col hint where this exact message occured. // via: reportError(arrayExpr, "Variable array elements not allowed."); reportError("Variable array elements not allowed."); result_ = nullptr; } }
// handlerDecl ::= 'handler' IDENT (';' | [do] stmt) std::unique_ptr<Handler> FlowParser::handlerDecl() { FNTRACE(); FlowLocation loc(location()); nextToken(); // 'handler' consume(FlowToken::Ident); std::string name = stringValue(); if (consumeIf(FlowToken::Semicolon)) { // forward-declaration loc.update(end()); return std::make_unique<Handler>(name, loc); } std::unique_ptr<SymbolTable> st = enterScope("handler-" + name); std::unique_ptr<Stmt> body = stmt(); leaveScope(); if (!body) return nullptr; loc.update(body->location().end); // forward-declared / previousely -declared? if (Handler* handler = scope()->lookup<Handler>(name, Lookup::Self)) { if (handler->body() != nullptr) { // TODO say where we found the other hand, compared to this one. reportError("Redeclaring handler '%s'", handler->name().c_str()); return nullptr; } handler->implement(std::move(st), std::move(body)); handler->owner()->removeSymbol(handler); return std::unique_ptr<Handler>(handler); } return std::make_unique<Handler>(name, std::move(st), std::move(body), loc); }
void writeSparse(QFile& file, const AttributeMap& data) { FNTRACE("ini", "", "writeSparse", QString("file %1, %2 rows of data").arg(file.fileName()).arg(data.size())); if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) ETHROW(Exception(QString("Unable to open %1 for writing.").arg(file.fileName()))); file.resize(0); QTextStream fout(&file); int max_key_length = 0; for (AttributeMap::const_iterator iter = data.begin(); iter != data.end(); ++iter) { if (iter.key().length() > max_key_length) max_key_length = iter.key().length(); } for (AttributeMap::const_iterator iter = data.begin(); iter != data.end(); ++iter) { fout << iter.key(); for (int i = iter.key().length(); i < max_key_length; ++i) fout << ' '; fout << " = " << iter.value() << "\n"; } }
// primaryExpr ::= NUMBER // | STRING // | variable // | function '(' exprList ')' // | '(' expr ')' std::unique_ptr<Expr> FlowParser::primaryExpr() { FNTRACE(); static struct { const char* ident; long long nominator; long long denominator; } units[] = { { "byte", 1, 1 }, { "kbyte", 1024llu, 1 }, { "mbyte", 1024llu * 1024, 1 }, { "gbyte", 1024llu * 1024 * 1024, 1 }, { "tbyte", 1024llu * 1024 * 1024 * 1024, 1 }, { "bit", 1, 8 }, { "kbit", 1024llu, 8 }, { "mbit", 1024llu * 1024, 8 }, { "gbit", 1024llu * 1024 * 1024, 8 }, { "tbit", 1024llu * 1024 * 1024 * 1024, 8 }, { "sec", 1, 1 }, { "min", 60llu, 1 }, { "hour", 60llu * 60, 1 }, { "day", 60llu * 60 * 24, 1 }, { "week", 60llu * 60 * 24 * 7, 1 }, { "month", 60llu * 60 * 24 * 30, 1 }, { "year", 60llu * 60 * 24 * 365, 1 }, { nullptr, 1, 1 } }; FlowLocation loc(location()); switch (token()) { case FlowToken::Ident: { std::string name = stringValue(); nextToken(); Symbol* symbol = scope()->lookup(name, Lookup::All); if (!symbol) { // XXX assume that given symbol is a auto forward-declared handler. Handler* href = (Handler*) globalScope()->appendSymbol(std::make_unique<Handler>(name, loc)); return std::make_unique<HandlerRefExpr>(href, loc); } if (auto variable = dynamic_cast<Variable*>(symbol)) return std::make_unique<VariableExpr>(variable, loc); if (auto handler = dynamic_cast<Handler*>(symbol)) return std::make_unique<HandlerRefExpr>(handler, loc); if (symbol->type() == Symbol::BuiltinFunction) { if (token() != FlowToken::RndOpen) return std::make_unique<FunctionCallExpr>((BuiltinFunction*) symbol, ExprList()/*args*/, loc); nextToken(); ExprList args; bool rv = listExpr(args); consume(FlowToken::RndClose); if (!rv) return nullptr; return std::make_unique<FunctionCallExpr>((BuiltinFunction*) symbol, std::move(args), loc); } reportError("Unsupported symbol type of '%s' in expression.", name.c_str()); return nullptr; } case FlowToken::Boolean: { std::unique_ptr<BoolExpr> e = std::make_unique<BoolExpr>(booleanValue(), loc); nextToken(); return std::move(e); } case FlowToken::RegExp: { std::unique_ptr<RegExpExpr> e = std::make_unique<RegExpExpr>(RegExp(stringValue()), loc); nextToken(); return std::move(e); } case FlowToken::InterpolatedStringFragment: return interpolatedStr(); case FlowToken::String: case FlowToken::RawString: { std::unique_ptr<StringExpr> e = std::make_unique<StringExpr>(stringValue(), loc); nextToken(); return std::move(e); } case FlowToken::Number: { // NUMBER [UNIT] auto number = numberValue(); nextToken(); if (token() == FlowToken::Ident) { std::string sv(stringValue()); for (size_t i = 0; units[i].ident; ++i) { if (sv == units[i].ident || (sv[sv.size() - 1] == 's' && sv.substr(0, sv.size() - 1) == units[i].ident)) { nextToken(); // UNIT number = number * units[i].nominator / units[i].denominator; loc.update(end()); break; } } } return std::make_unique<NumberExpr>(number, loc); } case FlowToken::IP: { std::unique_ptr<IPAddressExpr> e = std::make_unique<IPAddressExpr>(lexer_->ipValue(), loc); nextToken(); return std::move(e); } case FlowToken::Cidr: { std::unique_ptr<CidrExpr> e = std::make_unique<CidrExpr>(lexer_->cidr(), loc); nextToken(); return std::move(e); } case FlowToken::StringType: case FlowToken::NumberType: case FlowToken::BoolType: return castExpr(); case FlowToken::Begin: { // lambda-like inline function ref char name[64]; static unsigned long i = 0; ++i; snprintf(name, sizeof(name), "__lambda_%lu", i); FlowLocation loc = location(); auto st = std::make_unique<SymbolTable>(scope(), name); enter(st.get()); std::unique_ptr<Stmt> body = compoundStmt(); leave(); if (!body) return nullptr; loc.update(body->location().end); Handler* handler = new Handler(name, std::move(st), std::move(body), loc); // TODO (memory leak): add handler to unit's global scope, i.e. via: // - scope()->rootScope()->insert(handler); // - unit_->scope()->insert(handler); // to get free'd return std::make_unique<HandlerRefExpr>(handler, loc); } case FlowToken::RndOpen: { nextToken(); std::unique_ptr<Expr> e = expr(); consume(FlowToken::RndClose); e->setLocation(loc.update(end())); return e; } default: TRACE(1, "Expected primary expression. Got something... else."); reportUnexpectedToken(); return nullptr; } }
void writePreserving(QFile& inFile, QTextStream& out, const AttributeMap& data) { FNTRACE("ini", "", "writePreserving", QString("in, out, %1 rows of data").arg(data.size())); int i, j; QChar c; QString name; size_t lineNumber = 0; QString line; typedef QSet<AttributeMap::key_type> KeySet; KeySet unwrittenKeys = KeySet::fromList(data.keys()); if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) ETHROW(Exception(QString("Unable to open %1 for reading.").arg(inFile.fileName()))); QTextStream in(&inFile); while (!(line = in.readLine()).isNull()) { ++lineNumber; //std::cout << lineNumber << ": " << line.toStdString() << ":\n"; for (i = 0; line[i].isSpace(); ++i) { out << line[i]; } if (line[i].isNull()) { out << '\n'; continue; } else if (line[i] == COMMENT_BEGIN) { out << line.mid(i) << '\n'; continue; } for (j = i; !(c = line[i]).isNull() && c!=COMMENT_BEGIN && c!=ASSIGNER; ++i) ; //std::cout << "non-empty, "; if (c != ASSIGNER) // non-empty line that isn't assignment -> invalid ETHROW(ParseError(inFile.fileName(), lineNumber, "Unknown non-empty line.")); for (--i; line[i].isSpace(); --i) ; // last character of name name = line.mid(j, i - j + 1); //std::cout << "name: " << name.toStdString() << ' '; for ( ; line[j]!=ASSIGNER; ++j) out << line[j]; out << ASSIGNER; i = j + 1; for ( ; line[i].isSpace(); ++i) out << line[i]; if (data.contains(name)) { //std::cout << "known "; out << data.value(name); unwrittenKeys.remove(name); for (j = i; !line[i].isNull() && line[i]!=COMMENT_BEGIN; ++i) ; // EOL || comment for (--i; line[i].isSpace(); --i) ; // last character of value ++i; // first character after value } out << line.mid(i) << '\n'; //std::cout << '\n'; } if (unwrittenKeys.size()) { out << '\n' << COMMENT_BEGIN << "Following lines were generated by Ds1edit Loader:\n"; for (KeySet::iterator key = unwrittenKeys.begin(); key != unwrittenKeys.end(); ++key) out << (*key) << ' ' << ASSIGNER << ' ' << data.value(*key) << '\n'; } //in.resize(in.pos()+1); inFile.close(); }
void IRGenerator::accept(ExprStmt& stmt) { FNTRACE(); codegen(stmt.expression()); }
void IRGenerator::accept(BinaryExpr& expr) { FNTRACE(); static const std::unordered_map< int /*FlowVM::Opcode*/, Value* (IRGenerator::*)(Value*, Value*, const std::string&) > ops = { // numerical { FlowVM::Opcode::NADD, &IRGenerator::createAdd }, { FlowVM::Opcode::NSUB, &IRGenerator::createSub }, { FlowVM::Opcode::NMUL, &IRGenerator::createMul }, { FlowVM::Opcode::NDIV, &IRGenerator::createDiv }, { FlowVM::Opcode::NREM, &IRGenerator::createRem }, { FlowVM::Opcode::NSHL, &IRGenerator::createShl }, { FlowVM::Opcode::NSHR, &IRGenerator::createShr }, { FlowVM::Opcode::NPOW, &IRGenerator::createPow }, { FlowVM::Opcode::NAND, &IRGenerator::createAnd }, { FlowVM::Opcode::NOR, &IRGenerator::createOr }, { FlowVM::Opcode::NXOR, &IRGenerator::createXor }, { FlowVM::Opcode::NCMPEQ, &IRGenerator::createNCmpEQ }, { FlowVM::Opcode::NCMPNE, &IRGenerator::createNCmpNE }, { FlowVM::Opcode::NCMPLE, &IRGenerator::createNCmpLE }, { FlowVM::Opcode::NCMPGE, &IRGenerator::createNCmpGE }, { FlowVM::Opcode::NCMPLT, &IRGenerator::createNCmpLT }, { FlowVM::Opcode::NCMPGT, &IRGenerator::createNCmpGT }, // string { FlowVM::Opcode::SADD, &IRGenerator::createSAdd }, { FlowVM::Opcode::SCMPEQ, &IRGenerator::createSCmpEQ }, { FlowVM::Opcode::SCMPNE, &IRGenerator::createSCmpNE }, { FlowVM::Opcode::SCMPLE, &IRGenerator::createSCmpLE }, { FlowVM::Opcode::SCMPGE, &IRGenerator::createSCmpGE }, { FlowVM::Opcode::SCMPLT, &IRGenerator::createSCmpLT }, { FlowVM::Opcode::SCMPGT, &IRGenerator::createSCmpGT }, { FlowVM::Opcode::SCMPBEG, &IRGenerator::createSCmpEB }, { FlowVM::Opcode::SCMPEND, &IRGenerator::createSCmpEE }, { FlowVM::Opcode::SCONTAINS, &IRGenerator::createSIn }, // regex { FlowVM::Opcode::SREGMATCH, &IRGenerator::createSCmpRE }, // ip { FlowVM::Opcode::PCMPEQ, &IRGenerator::createPCmpEQ }, { FlowVM::Opcode::PCMPNE, &IRGenerator::createPCmpNE }, { FlowVM::Opcode::PINCIDR, &IRGenerator::createPInCidr }, }; if (expr.op() == FlowVM::Opcode::BOR) { // (lhs || rhs) // // L = lhs(); // if (L) goto end; // R = rhs(); // L = R; // end: // result = L; BasicBlock* borLeft = createBlock("bor.left"); BasicBlock* borRight = createBlock("bor.right"); BasicBlock* borCont = createBlock("bor.cont"); AllocaInstr* result = createAlloca(FlowType::Boolean, get(1), "bor"); Value* lhs = codegen(expr.leftExpr()); createCondBr(lhs, borLeft, borRight); setInsertPoint(borLeft); createStore(result, lhs, "bor.left"); createBr(borCont); setInsertPoint(borRight); Value* rhs = codegen(expr.rightExpr()); createStore(result, rhs, "bor.right"); createBr(borCont); setInsertPoint(borCont); result_ = result; return; } Value* lhs = codegen(expr.leftExpr()); Value* rhs = codegen(expr.rightExpr()); auto i = ops.find(expr.op()); if (i != ops.end()) { result_ = (this->*i->second)(lhs, rhs, ""); } else { fprintf(stderr, "BUG: Binary operation `%s` not implemented.\n", mnemonic(expr.op())); assert(!"Unimplemented"); result_ = nullptr; } }
void IRGenerator::accept(BuiltinHandler& builtin) { FNTRACE(); result_ = getBuiltinHandler(builtin.signature()); }
void IRGenerator::accept(BuiltinFunction& builtin) { FNTRACE(); result_ = getBuiltinFunction(builtin.signature()); }
std::unique_ptr<Stmt> FlowParser::callStmt() { // callStmt ::= NAME ['(' exprList ')' | exprList] (';' | LF) // | NAME '=' expr [';' | LF] // NAME may be a builtin-function, builtin-handler, handler-name, or variable. FNTRACE(); FlowLocation loc(location()); std::string name = stringValue(); nextToken(); // IDENT std::unique_ptr<Stmt> stmt; Symbol* callee = scope()->lookup(name, Lookup::All); if (!callee) { // XXX assume that given symbol is a auto forward-declared handler. callee = (Handler*) globalScope()->appendSymbol(std::make_unique<Handler>(name, loc)); } bool callArgs = false; switch (callee->type()) { case Symbol::Variable: { // var '=' expr (';' | LF) if (!consume(FlowToken::Assign)) return nullptr; std::unique_ptr<Expr> value = expr(); if (!value) return nullptr; stmt = std::make_unique<AssignStmt>(static_cast<Variable*>(callee), std::move(value), loc.update(end())); break; } case Symbol::BuiltinHandler: case Symbol::BuiltinFunction: stmt = std::make_unique<CallStmt>(loc, (Callable*) callee); callArgs = true; break; case Symbol::Handler: stmt = std::make_unique<CallStmt>(loc, (Callable*) callee); break; default: break; } if (callArgs) { CallStmt* callStmt = static_cast<CallStmt*>(stmt.get()); if (token() == FlowToken::RndOpen) { nextToken(); ExprList args; bool rv = listExpr(args); consume(FlowToken::RndClose); if (!rv) return nullptr; callStmt->setArgs(std::move(args)); } else if (lexer_->line() == loc.begin.line) { ExprList args; if (!listExpr(args)) return nullptr; callStmt->setArgs(std::move(args)); } // match call parameters FlowVM::Signature sig; sig.setName(name); sig.setReturnType(callStmt->callee()->signature().returnType()); // XXX cheetah std::vector<FlowType> argTypes; for (const auto& arg: callStmt->args()) { argTypes.push_back(arg->getType()); } sig.setArgs(argTypes); if (sig != callStmt->callee()->signature()) { reportError("Callee parameter type signature mismatch: %s passed, but %s expected.\n", sig.to_s().c_str(), callStmt->callee()->signature().to_s().c_str()); return nullptr; } } switch (token()) { case FlowToken::If: case FlowToken::Unless: return postscriptStmt(std::move(stmt)); case FlowToken::Semicolon: // stmt ';' nextToken(); stmt->location().update(end()); return stmt; default: if (stmt->location().end.line != lexer_->line()) return stmt; reportUnexpectedToken(); return nullptr; } }