main.cpp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517
  1. #include <gmock/gmock.h>
  2. #include "../../common/Lzs.h"
  3. #include "../ControlFlow.h"
  4. #include "../Graph.h"
  5. #include "../ScriptFormatter.h"
  6. #include "decompiler/ff7_field/ff7_field_disassembler.h"
  7. #include "decompiler/ff7_field/ff7_field_engine.h"
  8. #include "decompiler/ff7_field/ff7_field_codegen.h"
  9. #include "decompiler/ff7_world/ff7_world_disassembler.h"
  10. #include "decompiler/ff7_world/ff7_world_engine.h"
  11. #include "util.h"
  12. #include "ff7_field_dummy_formatter.h"
  13. #define GET(vertex) (boost::get(boost::vertex_name, g, vertex))
  14. class TestReadParameterDisassembler : public SimpleDisassembler
  15. {
  16. public:
  17. TestReadParameterDisassembler(std::vector<unsigned char>&& data, InstVec& insts)
  18. : SimpleDisassembler(insts)
  19. {
  20. mStream = std::make_unique<BinaryReader>(std::move(data));
  21. }
  22. void readParams(InstPtr inst, const char *typeString)
  23. {
  24. return SimpleDisassembler::readParams(inst, typeString);
  25. }
  26. virtual void doDisassemble() override final
  27. {
  28. // NOP
  29. }
  30. };
  31. static InstPtr DoReadParameterTest(std::string str, std::vector<unsigned char> data)
  32. {
  33. InstVec insts;
  34. TestReadParameterDisassembler d(std::move(data), insts);
  35. InstPtr inst = new FieldNoOperationInstruction();
  36. d.readParams(inst, str.c_str());
  37. return inst;
  38. }
  39. TEST(SimpleDisassembler, readParameter_U)
  40. {
  41. std::vector<unsigned char> data = { 0xAA };
  42. InstPtr inst = DoReadParameterTest("U", data);
  43. ASSERT_EQ(inst->_params.size(), 2);
  44. ASSERT_EQ(inst->_params[0]->getSigned(), 0x5);
  45. ASSERT_EQ(inst->_params[1]->getSigned(), 0xA);
  46. }
  47. TEST(SimpleDisassembler, readParameter_N)
  48. {
  49. std::vector<unsigned char> data = { 0xAB };
  50. InstPtr inst = DoReadParameterTest("N", data);
  51. ASSERT_EQ(inst->_params.size(), 2);
  52. ASSERT_EQ(inst->_params[0]->getSigned(), 0xA);
  53. ASSERT_EQ(inst->_params[1]->getSigned(), 0xB);
  54. }
  55. TEST(SimpleDisassembler, readParameter_b)
  56. {
  57. std::vector<unsigned char> data = { (unsigned char)-100 };
  58. InstPtr inst = DoReadParameterTest("b", data);
  59. ASSERT_EQ(inst->_params.size(), 1);
  60. ASSERT_EQ(inst->_params[0]->getSigned(), -100);
  61. }
  62. TEST(SimpleDisassembler, readParameter_B)
  63. {
  64. std::vector<unsigned char> data = { 100 };
  65. InstPtr inst = DoReadParameterTest("B", data);
  66. ASSERT_EQ(inst->_params.size(), 1);
  67. ASSERT_EQ(inst->_params[0]->getSigned(), 100);
  68. }
  69. TEST(SimpleDisassembler, readParameter_s)
  70. {
  71. std::vector<unsigned char> data = { (unsigned char)-40, 0x0 };
  72. InstPtr inst = DoReadParameterTest("s", data);
  73. ASSERT_EQ(inst->_params.size(), 1);
  74. ASSERT_EQ(inst->_params[0]->getSigned(), 216); // TODO: Casting removes the sign
  75. }
  76. TEST(SimpleDisassembler, readParameter_w)
  77. {
  78. std::vector<unsigned char> data = { 0xFE, 0xAA };
  79. InstPtr inst = DoReadParameterTest("w", data);
  80. ASSERT_EQ(inst->_params.size(), 1);
  81. ASSERT_EQ(inst->_params[0]->getSigned(), 0xAAFE);
  82. }
  83. TEST(SimpleDisassembler, readParameter_i)
  84. {
  85. std::vector<unsigned char> data = { (unsigned char)-0x30, 0x0, 0x0, 0x0 };
  86. InstPtr inst = DoReadParameterTest("i", data);
  87. ASSERT_EQ(inst->_params.size(), 1);
  88. ASSERT_EQ(inst->_params[0]->getSigned(), 208); // TODO: Casting removes the sign
  89. }
  90. TEST(SimpleDisassembler, readParameter_d)
  91. {
  92. std::vector<unsigned char> data = { 0xde, 0xad, 0xbe, 0xef };
  93. InstPtr inst = DoReadParameterTest("d", data);
  94. ASSERT_EQ(inst->_params.size(), 1);
  95. ASSERT_EQ(inst->_params[0]->getUnsigned(), 0xEFBEADDE);
  96. }
  97. TEST(FF7Field, FunctionMetaData_Parse_Empty)
  98. {
  99. FunctionMetaData meta("");
  100. ASSERT_EQ("", meta.EntityName());
  101. ASSERT_EQ(false, meta.IsEnd());
  102. ASSERT_EQ(false, meta.IsStart());
  103. }
  104. TEST(FF7Field, FunctionMetaData_Parse_Empties)
  105. {
  106. FunctionMetaData meta("__________________");
  107. ASSERT_EQ("", meta.EntityName());
  108. ASSERT_EQ(false, meta.IsEnd());
  109. ASSERT_EQ(false, meta.IsStart());
  110. }
  111. TEST(FF7Field, FunctionMetaData_Parse_Start)
  112. {
  113. FunctionMetaData meta("start_-1_entity");
  114. ASSERT_EQ("entity", meta.EntityName());
  115. ASSERT_EQ(false, meta.IsEnd());
  116. ASSERT_EQ(true, meta.IsStart());
  117. }
  118. TEST(FF7Field, FunctionMetaData_Parse_End)
  119. {
  120. FunctionMetaData meta("end_-1_entity");
  121. ASSERT_EQ("entity", meta.EntityName());
  122. ASSERT_EQ(true, meta.IsEnd());
  123. ASSERT_EQ(false, meta.IsStart());
  124. }
  125. TEST(FF7Field, FunctionMetaData_Parse_EntityName)
  126. {
  127. FunctionMetaData meta("end_-1_TheName");
  128. ASSERT_EQ("TheName", meta.EntityName());
  129. ASSERT_EQ(true, meta.IsEnd());
  130. ASSERT_EQ(false, meta.IsStart());
  131. ASSERT_EQ(-1, meta.CharacterId());
  132. }
  133. TEST(FF7Field, FunctionMetaData_Parse_EntityNameAndId)
  134. {
  135. FunctionMetaData meta("end_99_The_Name");
  136. ASSERT_EQ("The_Name", meta.EntityName());
  137. ASSERT_EQ(99, meta.CharacterId());
  138. ASSERT_EQ(true, meta.IsEnd());
  139. ASSERT_EQ(false, meta.IsStart());
  140. }
  141. TEST(FF7Field, FunctionMetaData_Parse_StartEnd)
  142. {
  143. FunctionMetaData meta("start_end_-1_entity");
  144. ASSERT_EQ("entity", meta.EntityName());
  145. ASSERT_EQ(true, meta.IsEnd());
  146. ASSERT_EQ(true, meta.IsStart());
  147. }
  148. /*
  149. TEST(FF7World, DisAsm)
  150. {
  151. for (int i = 0; i < 256; i++)
  152. {
  153. WorldEngine engine(i);
  154. InstVec insts;
  155. std::cout << std::endl;
  156. std::cout << std::endl;
  157. std::cout << "SCRIPT(" << i << ")" << std::endl;
  158. auto d = engine.GetDisassembler(insts);
  159. d->open("decompiler/ff7_world/wm0.ev");
  160. d->disassemble();
  161. d->dumpDisassembly(std::cout);
  162. std::cout << std::endl;
  163. auto c = std::make_unique<ControlFlow>(insts, engine);
  164. c->createGroups();
  165. Graph g = c->analyze();
  166. engine.PostCFG(insts, g);
  167. onullstream ns;
  168. auto cg = engine.GetCodeGenerator(insts, std::cout);
  169. std::ofstream out;
  170. out.open("graph.dot");
  171. if (out.is_open())
  172. {
  173. auto& g = c->getGraph();
  174. boost::write_graphviz(
  175. out, g, boost::make_label_writer(get(boost::vertex_name, g)),
  176. boost::MakeArrowheadWriter(get(boost::edge_attribute, g)), GraphProperties(&engine, g));
  177. }
  178. out.close();
  179. cg->generate(insts, g);
  180. VertexIterator v = boost::vertices(g).first;
  181. GroupPtr gr = GET(*v);
  182. // Find first node
  183. while (gr->_prev != NULL)
  184. {
  185. gr = gr->_prev;
  186. }
  187. // Copy out all lines of code
  188. std::vector<std::string> output;
  189. while (gr != NULL)
  190. {
  191. for (std::vector<CodeLine>::iterator it = gr->_code.begin(); it != gr->_code.end(); ++it)
  192. {
  193. output.push_back(it->_line);
  194. }
  195. gr = gr->_next;
  196. }
  197. ASSERT_TRUE(output.empty() == false);
  198. }
  199. }
  200. */
  201. int main(int argc, char** argv)
  202. {
  203. ::testing::InitGoogleMock(&argc, argv);
  204. return RUN_ALL_TESTS();
  205. }
  206. class Tokenzier
  207. {
  208. public:
  209. Tokenzier(const std::string& input)
  210. : mData(input)
  211. {
  212. }
  213. enum class eTokenType
  214. {
  215. eWhiteSpace,
  216. eText,
  217. eNumber,
  218. eInvalid,
  219. eArgumentDelmiter,
  220. eOpenBracket,
  221. eCloseBracket,
  222. eOpenCurlyBracket,
  223. eCloseCurlyBracket,
  224. eQuote,
  225. eEof
  226. };
  227. class Token
  228. {
  229. public:
  230. Token() = default;
  231. Token(eTokenType type, std::string text, int line, int column)
  232. : mType(type), mText(text), mColumn(column), mLine(line)
  233. {
  234. }
  235. Token(eTokenType type, int number, int line, int column)
  236. : mType(type), mNumber(number), mColumn(column), mLine(line)
  237. {
  238. }
  239. Token(eTokenType type, int line, int column)
  240. : mType(type), mColumn(column), mLine(line)
  241. {
  242. }
  243. std::string AsString() const
  244. {
  245. return mText;
  246. }
  247. int AsNumber() const
  248. {
  249. return mNumber;
  250. }
  251. eTokenType Type() const { return mType; }
  252. int Line() const { return mLine; }
  253. int Column() const { return mColumn; }
  254. private:
  255. std::string mText;
  256. int mNumber = 0;
  257. eTokenType mType = eTokenType::eInvalid;
  258. int mLine = -1;
  259. int mColumn = -1;
  260. };
  261. bool IsLineBreak(char item)
  262. {
  263. return item == '\r' || item == '\n';
  264. }
  265. bool IsSpace(char item, std::locale& loc)
  266. {
  267. return std::isspace(item, loc) && !IsLineBreak(item);
  268. }
  269. bool IsAlpha(char item)
  270. {
  271. return
  272. (item >= 'A' && item <= 'Z') ||
  273. (item >= 'a' && item <= 'z') ||
  274. item == '_';
  275. }
  276. bool IsDigit(char item, std::locale& loc)
  277. {
  278. return std::isdigit(item, loc);
  279. }
  280. Token Next()
  281. {
  282. char item = ' ';
  283. if (!mData)
  284. {
  285. return Token(eTokenType::eEof, mCurLine, mCurCol);
  286. }
  287. ReadChar(item);
  288. bool eof = false;
  289. item = ConsumeWhiteSpace(item, eof);
  290. if (eof)
  291. {
  292. return Token(eTokenType::eEof, mCurLine, mCurCol-1);
  293. }
  294. // Begin comment, consume until eLineBreak
  295. const bool startComment = item == ';';
  296. if (startComment)
  297. {
  298. bool isLineBreak = false;
  299. do
  300. {
  301. if (!ReadChar(item))
  302. {
  303. return Token(eTokenType::eEof, mCurLine, mCurCol - 1);
  304. }
  305. isLineBreak = IsLineBreak(item);
  306. } while (!isLineBreak);
  307. item = ConsumeWhiteSpace(item, eof);
  308. if (eof)
  309. {
  310. return Token(eTokenType::eEof, mCurLine, mCurCol - 1);
  311. }
  312. }
  313. if (item == ',')
  314. {
  315. return Token(eTokenType::eArgumentDelmiter, ",", mCurLine, mCurCol - 1);
  316. }
  317. else if (item == '(')
  318. {
  319. return Token(eTokenType::eOpenBracket, "(", mCurLine, mCurCol - 1);
  320. }
  321. else if (item == ')')
  322. {
  323. return Token(eTokenType::eCloseBracket, ")", mCurLine, mCurCol - 1);
  324. }
  325. else if (item == '{')
  326. {
  327. return Token(eTokenType::eOpenCurlyBracket, "{", mCurLine, mCurCol - 1);
  328. }
  329. else if (item == '}')
  330. {
  331. return Token(eTokenType::eCloseCurlyBracket, "}", mCurLine, mCurCol - 1);
  332. }
  333. else if (item == '"')
  334. {
  335. return Token(eTokenType::eQuote, "\"", mCurLine, mCurCol-1);
  336. }
  337. const bool alpha = IsAlpha(item) || item == ';';
  338. if (alpha)
  339. {
  340. const int startCol = mCurCol - 1;
  341. std::string text(1, item);
  342. // eText, consume until eLineBreak or whitespace
  343. bool stillAlphaOrDigit = false;
  344. do
  345. {
  346. if (!ReadChar(item))
  347. {
  348. return Token(eTokenType::eText, text, mCurLine, startCol);
  349. }
  350. // Strings can end with a :
  351. stillAlphaOrDigit = IsAlpha(item) || IsDigit(item, mLoc) || item == ':';
  352. if (stillAlphaOrDigit)
  353. {
  354. text.push_back(item);
  355. if (item == ':')
  356. {
  357. break;
  358. }
  359. }
  360. else
  361. {
  362. // Put the char back
  363. mData.seekg(-1, std::ios::cur);
  364. }
  365. } while (stillAlphaOrDigit);
  366. return Token(eTokenType::eText, text, mCurLine, startCol);
  367. }
  368. else if (IsDigit(item, mLoc) || item == '-') // Start of negative number
  369. {
  370. // eNumber, consume until eLineBreak or whitespace, each item before that must be a digit
  371. const int startCol = mCurCol - 1;
  372. std::string text(1, item);
  373. bool isANumber = true;
  374. do
  375. {
  376. ReadChar(item);
  377. if (!mData && item == '-')
  378. {
  379. // We ONLY have a -, this is invalid
  380. return Token(eTokenType::eInvalid, mCurLine, startCol);
  381. }
  382. else if (!mData)
  383. {
  384. return Token(eTokenType::eNumber, std::stoi(text), mCurLine, startCol);
  385. }
  386. isANumber = IsDigit(item, mLoc);
  387. if (isANumber)
  388. {
  389. text.push_back(item);
  390. }
  391. else
  392. {
  393. // Put the char back
  394. mData.seekg(-1, std::ios::cur);
  395. }
  396. } while (isANumber);
  397. return Token(eTokenType::eNumber, std::stoi(text), mCurLine, startCol);
  398. }
  399. else
  400. {
  401. // eInvalid
  402. return Token(eTokenType::eInvalid, mCurLine, mCurCol-1);
  403. }
  404. }
  405. private:
  406. char ConsumeWhiteSpace(char item, bool& eof)
  407. {
  408. // Eat all whitespace
  409. bool space = IsSpace(item, mLoc) || IsLineBreak(item);
  410. if (space)
  411. {
  412. do
  413. {
  414. if (!ReadChar(item))
  415. {
  416. eof = true;
  417. return item;
  418. }
  419. space = IsSpace(item, mLoc) || IsLineBreak(item);
  420. } while (space);
  421. }
  422. return item;
  423. }
  424. bool ReadChar(char& output)
  425. {
  426. mData.read(&output, 1);
  427. if (mData)
  428. {
  429. if (IsLineBreak(output))
  430. {
  431. mCurLine++;
  432. mCurCol = 1;
  433. }
  434. else
  435. {
  436. mCurCol++;
  437. }
  438. return true;
  439. }
  440. return false;
  441. }
  442. std::locale mLoc;
  443. std::stringstream mData;
  444. int mCurLine = 1;
  445. int mCurCol = 1;
  446. };
  447. TEST(Tokenzier, Empty)
  448. {
  449. Tokenzier t("");
  450. ASSERT_EQ(Tokenzier::eTokenType::eEof, t.Next().Type());
  451. }
  452. TEST(Tokenzier, ReadText)
  453. {
  454. Tokenzier t("Hello");
  455. Tokenzier::Token token = t.Next();
  456. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  457. ASSERT_EQ("Hello", token.AsString());
  458. }
  459. TEST(Tokenzier, ReadText2)
  460. {
  461. Tokenzier t("Hello world");
  462. Tokenzier::Token token = t.Next();
  463. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  464. ASSERT_EQ("Hello", token.AsString());
  465. token = t.Next();
  466. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  467. ASSERT_EQ("world", token.AsString());
  468. }
  469. // Check !"£$%^&*-+<>?;'[]#\/`¬ are marked as invalid and () is not part of text
  470. TEST(Tokenzier, ReadInvalidText)
  471. {
  472. const char kInvalidChars[] = R"(;!£$%^&*-+<>?'[]#\/`¬)";
  473. const int kNumChars = sizeof(kInvalidChars) / sizeof(char);
  474. for (int i = 0; i < kNumChars; i++)
  475. {
  476. Tokenzier t(std::string(1,kInvalidChars[i]));
  477. Tokenzier::Token token = t.Next();
  478. if (i == 0)
  479. {
  480. // ; without a line break becomes EOF
  481. ASSERT_EQ(Tokenzier::eTokenType::eEof, token.Type());
  482. }
  483. else
  484. {
  485. ASSERT_EQ(Tokenzier::eTokenType::eInvalid, token.Type());
  486. }
  487. ASSERT_EQ("", token.AsString());
  488. }
  489. }
  490. TEST(Tokenzier, ReadInvalidText2)
  491. {
  492. Tokenzier t("H!£$%^");
  493. Tokenzier::Token token = t.Next();
  494. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  495. ASSERT_EQ("H", token.AsString());
  496. token = t.Next();
  497. ASSERT_EQ(Tokenzier::eTokenType::eInvalid, token.Type());
  498. ASSERT_EQ("", token.AsString());
  499. }
  500. TEST(Tokenzier, ReadBrackets)
  501. {
  502. {
  503. Tokenzier t("(");
  504. Tokenzier::Token token = t.Next();
  505. ASSERT_EQ(Tokenzier::eTokenType::eOpenBracket, token.Type());
  506. ASSERT_EQ("(", token.AsString());
  507. }
  508. {
  509. Tokenzier t(")");
  510. Tokenzier::Token token = t.Next();
  511. ASSERT_EQ(Tokenzier::eTokenType::eCloseBracket, token.Type());
  512. ASSERT_EQ(")", token.AsString());
  513. }
  514. }
  515. TEST(Tokenzier, ReadLabel)
  516. {
  517. Tokenzier t("Hello:");
  518. Tokenzier::Token token = t.Next();
  519. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  520. ASSERT_EQ("Hello:", token.AsString());
  521. }
  522. TEST(Tokenzier, ReadLabel2)
  523. {
  524. Tokenzier t("Hello:a");
  525. Tokenzier::Token token = t.Next();
  526. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  527. ASSERT_EQ("Hello:", token.AsString());
  528. }
  529. TEST(Tokenzier, ReadWhiteSpace)
  530. {
  531. Tokenzier t("\t ");
  532. Tokenzier::Token token = t.Next();
  533. ASSERT_EQ(Tokenzier::eTokenType::eEof, token.Type());
  534. ASSERT_EQ("", token.AsString());
  535. }
  536. TEST(Tokenzier, ReadArgumentDelimiter)
  537. {
  538. Tokenzier t(",");
  539. Tokenzier::Token token = t.Next();
  540. ASSERT_EQ(Tokenzier::eTokenType::eArgumentDelmiter, token.Type());
  541. ASSERT_EQ(",", token.AsString());
  542. }
  543. TEST(Tokenzier, ReadNewLine)
  544. {
  545. Tokenzier t("\r\n\r\r\n\n");
  546. Tokenzier::Token token = t.Next();
  547. ASSERT_EQ(Tokenzier::eTokenType::eEof, token.Type());
  548. ASSERT_EQ("", token.AsString());
  549. }
  550. TEST(Tokenzier, ReadNegativeNumber)
  551. {
  552. Tokenzier t("-12345");
  553. Tokenzier::Token token = t.Next();
  554. ASSERT_EQ(Tokenzier::eTokenType::eNumber, token.Type());
  555. ASSERT_EQ(-12345, token.AsNumber());
  556. }
  557. TEST(Tokenzier, ReadNumber)
  558. {
  559. Tokenzier t("12345");
  560. Tokenzier::Token token = t.Next();
  561. ASSERT_EQ(Tokenzier::eTokenType::eNumber, token.Type());
  562. ASSERT_EQ(12345, token.AsNumber());
  563. }
  564. TEST(Tokenzier, ReadQuote)
  565. {
  566. Tokenzier t("\"");
  567. Tokenzier::Token token = t.Next();
  568. ASSERT_EQ(Tokenzier::eTokenType::eQuote, token.Type());
  569. ASSERT_EQ("\"", token.AsString());
  570. }
  571. TEST(Tokenzier, ReadCurlyBrackets)
  572. {
  573. Tokenzier t("{}");
  574. Tokenzier::Token token = t.Next();
  575. ASSERT_EQ(Tokenzier::eTokenType::eOpenCurlyBracket, token.Type());
  576. ASSERT_EQ("{", token.AsString());
  577. token = t.Next();
  578. ASSERT_EQ(Tokenzier::eTokenType::eCloseCurlyBracket, token.Type());
  579. ASSERT_EQ("}", token.AsString());
  580. }
  581. // Combos, whitespace, new line, text, number, argument delimiter eof
  582. TEST(Tokenzier, Combos)
  583. {
  584. Tokenzier t(" \nText1234:1234,;Fool1\nFool2");
  585. Tokenzier::Token token = t.Next();
  586. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  587. ASSERT_EQ("Text1234:", token.AsString());
  588. ASSERT_EQ(2, token.Line());
  589. ASSERT_EQ(1, token.Column());
  590. token = t.Next();
  591. ASSERT_EQ(Tokenzier::eTokenType::eNumber, token.Type());
  592. ASSERT_EQ(1234, token.AsNumber());
  593. ASSERT_EQ(2, token.Line());
  594. ASSERT_EQ(10, token.Column());
  595. token = t.Next();
  596. ASSERT_EQ(Tokenzier::eTokenType::eArgumentDelmiter, token.Type());
  597. ASSERT_EQ(",", token.AsString());
  598. ASSERT_EQ(2, token.Line());
  599. ASSERT_EQ(15, token.Column());
  600. token = t.Next();
  601. ASSERT_EQ(Tokenzier::eTokenType::eText, token.Type());
  602. ASSERT_EQ("Fool2", token.AsString());
  603. ASSERT_EQ(3, token.Line());
  604. ASSERT_EQ(1, token.Column());
  605. token = t.Next();
  606. ASSERT_EQ(Tokenzier::eTokenType::eEof, token.Type());
  607. ASSERT_EQ("", token.AsString());
  608. }
  609. typedef std::vector<std::pair<std::string, Tokenzier::Token>> JumpToken;
  610. class Assembler
  611. {
  612. public:
  613. class Method
  614. {
  615. public:
  616. Method(const std::string& name)
  617. : mName(name)
  618. {
  619. }
  620. bool AddLabel(std::string name, const Tokenzier::Token& token)
  621. {
  622. // Labels end with ":" so chop that char off
  623. name = name.substr(0, name.length() - 1);
  624. auto it = mLabels.find(name);
  625. if (it != std::end(mLabels))
  626. {
  627. return false;
  628. }
  629. mLabels.insert(std::make_pair(name, token));
  630. return true;
  631. }
  632. void AddJump(const std::string& label, const Tokenzier::Token& token)
  633. {
  634. auto it = mJumps.find(label);
  635. if (it != std::end(mJumps))
  636. {
  637. it->second.push_back(token);
  638. }
  639. else
  640. {
  641. std::vector<Tokenzier::Token> t;
  642. t.push_back(token);
  643. mJumps.insert(std::make_pair(label, t));
  644. }
  645. }
  646. void VerifyAndResolveLabels(JumpToken& unreferencedLabels, JumpToken& undefinedLabels)
  647. {
  648. for (const auto& jumpTarget : mJumps)
  649. {
  650. auto it = mLabels.find(jumpTarget.first);
  651. if (it == std::end(mLabels))
  652. {
  653. undefinedLabels.push_back(std::make_pair(jumpTarget.first, jumpTarget.second[0]));
  654. }
  655. }
  656. for (const auto& label : mLabels)
  657. {
  658. auto it = mJumps.find(label.first);
  659. if (it == std::end(mJumps))
  660. {
  661. unreferencedLabels.push_back(std::make_pair(label.first, label.second));
  662. }
  663. }
  664. }
  665. private:
  666. std::string mName;
  667. std::map<std::string, Tokenzier::Token> mLabels;
  668. std::map<std::string, std::vector<Tokenzier::Token>> mJumps;
  669. };
  670. class Object
  671. {
  672. public:
  673. Object(const std::string& name)
  674. : mName(name)
  675. {
  676. }
  677. const std::string& Name() const { return mName; }
  678. Method* AddMethod(const std::string& name)
  679. {
  680. auto method = FindMethod(name);
  681. if (!method)
  682. {
  683. mMethods[name] = std::make_unique<Method>(name);
  684. return FindMethod(name);
  685. }
  686. return nullptr;
  687. }
  688. size_t MethodCount() const { return mMethods.size(); }
  689. bool HasMethod(const std::string& name) const
  690. {
  691. return FindMethod(name) != nullptr;
  692. }
  693. private:
  694. Method* FindMethod(const std::string& name) const
  695. {
  696. auto it = mMethods.find(name);
  697. if (it == std::end(mMethods))
  698. {
  699. return nullptr;
  700. }
  701. return it->second.get();
  702. }
  703. std::string mName;
  704. std::map<std::string, std::unique_ptr<Method>> mMethods;
  705. };
  706. Assembler()
  707. {
  708. }
  709. // Something which wraps "methods"
  710. Object* AddObject(const std::string& objectName)
  711. {
  712. auto obj = FindObject(objectName);
  713. if (!obj)
  714. {
  715. mObjects[objectName] = std::make_unique<Object>(objectName);
  716. return FindObject(objectName);
  717. }
  718. return nullptr;
  719. }
  720. size_t ObjectCount() const { return mObjects.size(); }
  721. private:
  722. Object* FindObject(const std::string& objectName) const
  723. {
  724. auto it = mObjects.find(objectName);
  725. if (it == std::end(mObjects))
  726. {
  727. return nullptr;
  728. }
  729. return it->second.get();
  730. }
  731. std::map<std::string, std::unique_ptr<Object>> mObjects;
  732. };
  733. class Parser
  734. {
  735. public:
  736. class Exception : public std::exception
  737. {
  738. public:
  739. Exception(const std::string& msg)
  740. : mMsg(msg)
  741. {
  742. }
  743. Exception(const std::string& msg, const Tokenzier::Token& token)
  744. : mMsg(msg)
  745. {
  746. mMsg += " on line: " + std::to_string(token.Line()) + ", col: " + std::to_string(token.Column());
  747. if (token.Type() == Tokenzier::eTokenType::eNumber)
  748. {
  749. mMsg += ", with value: '" + std::to_string(token.AsNumber()) + "'";
  750. }
  751. else if (token.AsString().empty() == false)
  752. {
  753. mMsg += ", with value: '" + token.AsString() + "'";
  754. }
  755. }
  756. virtual const char* what() const throw() override
  757. {
  758. return mMsg.c_str();
  759. }
  760. private:
  761. std::string mMsg;
  762. };
  763. class DuplicateObjectNameException : public Exception
  764. {
  765. public:
  766. DuplicateObjectNameException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  767. };
  768. class DuplicateMethodNameException : public Exception
  769. {
  770. public:
  771. DuplicateMethodNameException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  772. };
  773. class TooManyObjectsException : public Exception
  774. {
  775. public:
  776. TooManyObjectsException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  777. };
  778. class TooManyMethodsException : public Exception
  779. {
  780. public:
  781. TooManyMethodsException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  782. };
  783. class TooManyArgumentsException : public Exception
  784. {
  785. public:
  786. TooManyArgumentsException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  787. };
  788. class ArgumentOutOfRangeException : public Exception
  789. {
  790. public:
  791. ArgumentOutOfRangeException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  792. };
  793. class DuplicateLabelException : public Exception
  794. {
  795. public:
  796. DuplicateLabelException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  797. };
  798. class UndefinedLabelException : public Exception
  799. {
  800. public:
  801. UndefinedLabelException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  802. };
  803. class UnknownOpCodeException : public Exception
  804. {
  805. public:
  806. UnknownOpCodeException(const std::string& msg, const Tokenzier::Token& token) : Exception(msg, token) { }
  807. };
  808. Parser(const std::string& src)
  809. : mTokenzier(src)
  810. {
  811. }
  812. void Parse()
  813. {
  814. std::deque<Tokenzier::Token> tokenStack;
  815. for (;;)
  816. {
  817. Tokenzier::Token token = mTokenzier.Next();
  818. if (token.Type() == Tokenzier::eTokenType::eInvalid)
  819. {
  820. throw Exception("Invalid syntax", token);
  821. }
  822. if (token.Type() == Tokenzier::eTokenType::eEof)
  823. {
  824. break;
  825. }
  826. tokenStack.push_back(token);
  827. }
  828. Parse(tokenStack);
  829. }
  830. private:
  831. void Parse(std::deque<Tokenzier::Token>& tokens)
  832. {
  833. while (tokens.empty() == false)
  834. {
  835. // Everything at the top level should be an entity
  836. ParseEntity(tokens);
  837. }
  838. }
  839. void ParseEntity(std::deque<Tokenzier::Token>& tokens)
  840. {
  841. // Starts with entity keyword
  842. ExpectText("Entity", NextToken(tokens));
  843. // Entity name is quoted string within brackets
  844. ExpectToken(Tokenzier::eTokenType::eOpenBracket, tokens);
  845. Tokenzier::Token entityNameToken = ExpectQuotedString(tokens);
  846. ExpectToken(Tokenzier::eTokenType::eCloseBracket, tokens);
  847. std::cout << "ParseEntity: " << entityNameToken.AsString().c_str() << std::endl;
  848. auto pObj = mAssembler.AddObject(entityNameToken.AsString());
  849. if (!pObj)
  850. {
  851. throw DuplicateObjectNameException("Duplicated entity name", entityNameToken);
  852. }
  853. if (mAssembler.ObjectCount() >= 32)
  854. {
  855. throw TooManyObjectsException("There can only be 32 entities", entityNameToken);
  856. }
  857. // Entity body within { }'s
  858. ExpectToken(Tokenzier::eTokenType::eOpenCurlyBracket, tokens);
  859. // Handle empty {}'s case
  860. if (PeekTokenType(tokens) != Tokenzier::eTokenType::eCloseCurlyBracket)
  861. {
  862. ParseEntityMethods(tokens, *pObj);
  863. }
  864. ExpectToken(Tokenzier::eTokenType::eCloseCurlyBracket, tokens);
  865. }
  866. void ParseEntityMethods(std::deque<Tokenzier::Token>& tokens, Assembler::Object& obj)
  867. {
  868. while (tokens.empty() == false)
  869. {
  870. // Marks the end of functions
  871. if (PeekTokenType(tokens) == Tokenzier::eTokenType::eCloseCurlyBracket)
  872. {
  873. break;
  874. }
  875. // Otherwise must be fn name() { } decl
  876. ParseEntityMethod(tokens, obj);
  877. }
  878. }
  879. void ParseEntityMethod(std::deque<Tokenzier::Token>& tokens, Assembler::Object& obj)
  880. {
  881. // Starts with fn keyword
  882. ExpectText("fn", NextToken(tokens));
  883. // Function name
  884. Tokenzier::Token text = NextToken(tokens);
  885. ExpectTokenType(Tokenzier::eTokenType::eText, text);
  886. std::cout << "Entity function: " << text.AsString().c_str() << std::endl;
  887. auto pMethod = obj.AddMethod(text.AsString());
  888. if (!pMethod)
  889. {
  890. throw DuplicateMethodNameException("Duplicated function name", text);
  891. }
  892. size_t methodCount = obj.MethodCount();
  893. if (obj.HasMethod("init") && obj.HasMethod("main"))
  894. {
  895. // init and main count as 1 script
  896. methodCount--;
  897. }
  898. if (methodCount >= 32)
  899. {
  900. throw TooManyMethodsException("There can only be 31 scripts excluding init and main", text);
  901. }
  902. // Brackets end function name
  903. ExpectToken(Tokenzier::eTokenType::eOpenBracket, tokens);
  904. ExpectToken(Tokenzier::eTokenType::eCloseBracket, tokens);
  905. // Body within { } 's,
  906. ExpectToken(Tokenzier::eTokenType::eOpenCurlyBracket, tokens);
  907. // handle empty {}'s case
  908. if (PeekTokenType(tokens) != Tokenzier::eTokenType::eCloseCurlyBracket)
  909. {
  910. ParseEntityMethodBody(tokens, *pMethod);
  911. }
  912. ExpectToken(Tokenzier::eTokenType::eCloseCurlyBracket, tokens);
  913. JumpToken unreferencedLabels;
  914. JumpToken undefinedLabels;
  915. pMethod->VerifyAndResolveLabels(unreferencedLabels, undefinedLabels);
  916. if (!undefinedLabels.empty())
  917. {
  918. throw UndefinedLabelException("Undefined label", undefinedLabels[0].second);
  919. }
  920. if (!unreferencedLabels.empty())
  921. {
  922. // Warn about unused labels
  923. for (const auto& label : unreferencedLabels)
  924. {
  925. std::cout << "WARNING: label " + label.first + " is not used on line : " + std::to_string(label.second.Line()) + ", col : " + std::to_string(label.second.Column()) << std::endl;
  926. }
  927. }
  928. }
  929. void ParseEntityMethodBody(std::deque<Tokenzier::Token>& tokens, Assembler::Method& method)
  930. {
  931. while (tokens.empty() == false)
  932. {
  933. // } is the end of the function
  934. if (PeekTokenType(tokens) == Tokenzier::eTokenType::eCloseCurlyBracket)
  935. {
  936. // TODO: Validate semantics of instructions parsed
  937. break;
  938. }
  939. Tokenzier::Token text = NextToken(tokens);
  940. // Probably someone has a passed a number argument to an opcode that takes no arguments
  941. if (text.Type() == Tokenzier::eTokenType::eNumber)
  942. {
  943. throw UnknownOpCodeException("Expected opcode text", text);
  944. }
  945. ExpectTokenType(Tokenzier::eTokenType::eText, text);
  946. // Label
  947. std::string str = text.AsString();
  948. if (str.back() == ':')
  949. {
  950. std::cout << "LABEL:" << str.c_str() << std::endl;
  951. if (!method.AddLabel(str.c_str(), text))
  952. {
  953. throw DuplicateLabelException("Duplicated label", text);
  954. }
  955. }
  956. // instruction/mnemonic
  957. else
  958. {
  959. std::cout << "INSTRUCTION:" << str.c_str() << std::endl;
  960. ParseInstruction(text, tokens, method);
  961. }
  962. }
  963. }
  964. void ParseInstruction(const Tokenzier::Token& inst, std::deque<Tokenzier::Token>& tokens, Assembler::Method& method)
  965. {
  966. const auto insts = FieldInstructions();
  967. auto it = insts.find(inst.AsString());
  968. if (it == std::end(insts))
  969. {
  970. throw UnknownOpCodeException(inst.AsString() + " is not a known instruction", inst);
  971. }
  972. // TODO: Handle arguments correctly, validate labels
  973. const TInstructRecord* rec = it->second;
  974. const char* fmt = rec->mArgumentFormat;
  975. // method.AddInstruction(rec->mOpCode, rec->mOpCodeSize);
  976. // TODO: Flow control needs special handling
  977. while (*fmt)
  978. {
  979. bool handled = false;
  980. switch (*fmt)
  981. {
  982. // TODO: Handle nibbles correctly
  983. /*
  984. case 'N':
  985. {
  986. // TODO
  987. ExpectTokenType(Tokenzier::eTokenType::eNumber, PeekToken(tokens));
  988. NextToken(tokens);
  989. secondNib = !secondNib;
  990. }
  991. break;*/
  992. case 'N':
  993. case 'B':
  994. {
  995. ExpectTokenType(Tokenzier::eTokenType::eNumber, PeekToken(tokens));
  996. const auto token = NextToken(tokens);
  997. if (token.AsNumber() < 0 || token.AsNumber() > 255)
  998. {
  999. throw ArgumentOutOfRangeException("Byte argument must be between 0 and 255", token);
  1000. }
  1001. //method.AddInstructionArgument<unsigned char>(token.AsNumber());
  1002. handled = true;
  1003. }
  1004. break;
  1005. case 'U':
  1006. {
  1007. ExpectTokenType(Tokenzier::eTokenType::eNumber, PeekToken(tokens));
  1008. const auto token = NextToken(tokens);
  1009. if (token.AsNumber() < 0 || token.AsNumber() > 65535)
  1010. {
  1011. throw ArgumentOutOfRangeException("Unsigned short argument must be between 0 and 65535", token);
  1012. }
  1013. //method.AddInstructionArgument<unsigned short int>(token.AsNumber());
  1014. handled = true;
  1015. }
  1016. break;
  1017. // Single byte label
  1018. case 'L':
  1019. {
  1020. ExpectTokenType(Tokenzier::eTokenType::eText, PeekToken(tokens));
  1021. const auto token = NextToken(tokens);
  1022. std::cout << "ADD JUMP: " << token.AsString() << std::endl;
  1023. method.AddJump(token.AsString(), token);
  1024. handled = true;
  1025. }
  1026. break;
  1027. default:
  1028. // TODO: Throw
  1029. break;
  1030. }
  1031. fmt++;
  1032. // If we parsed and argument and there is another argument, then they
  1033. // should be separated by an argument delimiter
  1034. if (handled && *fmt)
  1035. {
  1036. ExpectTokenType(Tokenzier::eTokenType::eArgumentDelmiter, NextToken(tokens));
  1037. }
  1038. }
  1039. if (PeekTokenType(tokens) == Tokenzier::eTokenType::eArgumentDelmiter)
  1040. {
  1041. throw TooManyArgumentsException("Too many arguments for opcode", NextToken(tokens));
  1042. }
  1043. }
  1044. Tokenzier::Token ExpectQuotedString(std::deque<Tokenzier::Token>& tokens)
  1045. {
  1046. ExpectToken(Tokenzier::eTokenType::eQuote, tokens);
  1047. Tokenzier::Token text = NextToken(tokens);
  1048. ExpectTokenType(Tokenzier::eTokenType::eText, text);
  1049. ExpectToken(Tokenzier::eTokenType::eQuote, tokens);
  1050. return text;
  1051. }
  1052. Tokenzier::eTokenType PeekTokenType(const std::deque<Tokenzier::Token>& tokens)
  1053. {
  1054. return PeekToken(tokens).Type();
  1055. }
  1056. void ExpectTokenType(Tokenzier::eTokenType type, const Tokenzier::Token& token)
  1057. {
  1058. if (token.Type() != type)
  1059. {
  1060. throw Exception("Expected token of type: " + ToString(type) + " but got: " + ToString(token.Type()), token);
  1061. }
  1062. }
  1063. void ExpectToken(Tokenzier::eTokenType type, std::deque<Tokenzier::Token>& tokens)
  1064. {
  1065. ExpectTokenType(type, NextToken(tokens));
  1066. }
  1067. void ExpectText(const std::string& expectedText, const Tokenzier::Token& token)
  1068. {
  1069. if (token.Type() != Tokenzier::eTokenType::eText)
  1070. {
  1071. throw Exception("Expected token of type: " + ToString(Tokenzier::eTokenType::eText) + " but got: " + ToString(token.Type()), token);
  1072. }
  1073. if (token.AsString() != expectedText)
  1074. {
  1075. throw Exception("Expected keyword: " + expectedText + " but got: " + token.AsString(), token);
  1076. }
  1077. }
  1078. Tokenzier::Token NextToken(std::deque<Tokenzier::Token>& tokens)
  1079. {
  1080. if (tokens.empty())
  1081. {
  1082. throw Exception("Expected more tokens before end of input");
  1083. }
  1084. Tokenzier::Token ret = tokens.front();
  1085. tokens.pop_front();
  1086. return ret;
  1087. }
  1088. Tokenzier::Token PeekToken(const std::deque<Tokenzier::Token>& tokens)
  1089. {
  1090. if (tokens.empty())
  1091. {
  1092. throw Exception("Expected more tokens before end of input");
  1093. }
  1094. return tokens.front();
  1095. }
  1096. std::string ToString(Tokenzier::eTokenType type)
  1097. {
  1098. std::string ret;
  1099. switch (type)
  1100. {
  1101. case Tokenzier::eTokenType::eArgumentDelmiter:
  1102. ret = "argument delimiter";
  1103. break;
  1104. case Tokenzier::eTokenType::eWhiteSpace:
  1105. ret = "white space";
  1106. break;
  1107. case Tokenzier::eTokenType::eText:
  1108. ret = "text";
  1109. break;
  1110. case Tokenzier::eTokenType::eNumber:
  1111. ret = "number";
  1112. break;
  1113. case Tokenzier::eTokenType::eInvalid:
  1114. ret = "invalid";
  1115. break;
  1116. case Tokenzier::eTokenType::eOpenBracket:
  1117. ret = "open bracket";
  1118. break;
  1119. case Tokenzier::eTokenType::eCloseBracket:
  1120. ret = "close bracket";
  1121. break;
  1122. case Tokenzier::eTokenType::eOpenCurlyBracket:
  1123. ret = "open curly brace";
  1124. break;
  1125. case Tokenzier::eTokenType::eCloseCurlyBracket:
  1126. ret = "close curly brace";
  1127. break;
  1128. case Tokenzier::eTokenType::eQuote:
  1129. ret = "quote";
  1130. break;
  1131. case Tokenzier::eTokenType::eEof:
  1132. ret = "end of file";
  1133. break;
  1134. default:
  1135. // Shouldn't actually be possible
  1136. throw Exception("Unknown token type: " + std::to_string(static_cast<int>(type)));
  1137. }
  1138. return ret;
  1139. }
  1140. Tokenzier mTokenzier;
  1141. Assembler mAssembler;
  1142. };
  1143. TEST(Parser, SimpleScript)
  1144. {
  1145. Parser p("Entity(\"Testing\") { fn init() { start: NOP REQ 1,2 ;JMPB start\r\n } fn main() { } fn script1() { ;IFUB 0, 0, 1, 2, 0, lfalse NOP lfalse:\n } } ; Example\n Entity(\"Second\")\n {\n fn\n init()\n {\n }\n }");
  1146. ASSERT_NO_THROW(p.Parse());
  1147. }
  1148. // Parse unknown opcode
  1149. TEST(Parser, UnknownOpcode)
  1150. {
  1151. Parser p("Entity(\"Testing\") { fn init() { FLUB } } ");
  1152. ASSERT_THROW(p.Parse(), Parser::UnknownOpCodeException);
  1153. }
  1154. // Parse duplicate entity name
  1155. TEST(Parser, DuplicateObjectName)
  1156. {
  1157. Parser p("Entity(\"Testing\") { fn init() { } } Entity(\"Testing\") { fn init() { } } ");
  1158. ASSERT_THROW(p.Parse(), Parser::DuplicateObjectNameException);
  1159. }
  1160. // Parse duplicate function name
  1161. TEST(Parser, DuplicateMethodName)
  1162. {
  1163. Parser p("Entity(\"Testing\") { fn init() { } fn init() { } }");
  1164. ASSERT_THROW(p.Parse(), Parser::DuplicateMethodNameException);
  1165. }
  1166. // Parse too many entities
  1167. TEST(Parser, TooManyEntities)
  1168. {
  1169. std::string strScript;
  1170. for (int i = 0; i < 32; i++) // TODO: Find out what the actual limit is
  1171. {
  1172. const std::string entityName = "Test" + std::to_string(i);
  1173. const std::string entity = "Entity(\"" + entityName + "\") { fn init() { } }";
  1174. strScript += entity;
  1175. }
  1176. Parser p(strScript);
  1177. ASSERT_THROW(p.Parse(), Parser::TooManyObjectsException);
  1178. }
  1179. // Parse too many functions
  1180. TEST(Parser, TooManyFunctions)
  1181. {
  1182. std::string strFunctions;
  1183. for (int i = 0; i < 31; i++)
  1184. {
  1185. strFunctions += "fn test" + std::to_string(i) +"() { NOP NOP } ";
  1186. }
  1187. Parser p("Entity(\"Testing\") { fn init() { } fn main() { }" + strFunctions +"}");
  1188. ASSERT_THROW(p.Parse(), Parser::TooManyMethodsException);
  1189. }
  1190. // Parse too many arguments
  1191. TEST(Parser, TooManyArguments)
  1192. {
  1193. {
  1194. Parser p("Entity(\"Testing\") { fn init() { NOP 1 } }");
  1195. ASSERT_THROW(p.Parse(), Parser::UnknownOpCodeException);
  1196. }
  1197. {
  1198. Parser p("Entity(\"Testing\") { fn init() { REQSW 1,2,3 } }");
  1199. ASSERT_THROW(p.Parse(), Parser::TooManyArgumentsException);
  1200. }
  1201. }
  1202. // Parse not enough arguments
  1203. TEST(Parser, NotEnoughArguments)
  1204. {
  1205. Parser p("Entity(\"Testing\") { fn init() { REQSW 1 } }");
  1206. ASSERT_THROW(p.Parse(), Parser::Exception); // Expects , after 1
  1207. }
  1208. // Parse argument value out of range
  1209. TEST(Parser, ArgumentOutOfRange)
  1210. {
  1211. Parser p("Entity(\"Testing\") { fn init() { REQSW 256, 9999999 } }");
  1212. ASSERT_THROW(p.Parse(), Parser::ArgumentOutOfRangeException);
  1213. }
  1214. // Parse duplicated labels
  1215. TEST(Parser, DuplicatedLabels)
  1216. {
  1217. Parser p("Entity(\"Testing\") { fn init() { label: label: } }");
  1218. ASSERT_THROW(p.Parse(), Parser::DuplicateLabelException);
  1219. }
  1220. // Parse IF
  1221. TEST(Parser, ParseIf)
  1222. {
  1223. // TODO: Could allow cleaner syntax:
  1224. //Parser p("Entity(\"Testing\") { fn init() { IFUB Var(1,2) > Var(0,4) foo NOP foo: } }");
  1225. Parser p("Entity(\"Testing\") { fn init() { IFUB 1, 0, 20, 30, 1, foo NOP foo: } }");
  1226. p.Parse();
  1227. }
  1228. // Parse IF's with missing labels
  1229. TEST(Parser, ParseIfMissingLabel)
  1230. {
  1231. Parser p("Entity(\"Testing\") { fn init() { IFUB 1, 0, 20, 30, 1, foo NOP } }");
  1232. ASSERT_THROW(p.Parse(), Parser::UndefinedLabelException);
  1233. }
  1234. // Parse generates warning on unused label
  1235. TEST(Parser, WarnsOnUnusedLabels)
  1236. {
  1237. // TODO: Not auto checked as writes to std out, it should probably call back to us so we can check
  1238. Parser p("Entity(\"Testing\") { fn init() { IFUB 1, 0, 20, 30, 1, foo NOP foo: asdf: \nasdsds: \nhello: } }");
  1239. p.Parse();
  1240. }
  1241. // Simple assemble / disassemble
  1242. TEST(Parser, AssembleDisassemble)
  1243. {
  1244. Parser p("Entity(\"Testing\") { fn main() { NOP } fn init() { NOP } }");
  1245. }
  1246. // Parse IF's that jump after the if with no "gap"
  1247. /*
  1248. TEST(Parser, ZeroGapIf)
  1249. {
  1250. Parser p("Entity(\"Testing\") { fn init() { IFUB 1, 0, 20, 30, 1, foo foo: } }");
  1251. ASSERT_THROW(p.Parse(), Parser::JumpHasNoGap);
  1252. }
  1253. */
  1254. // Parse var length arguments
  1255. // Parse double meaning arguments
  1256. // Parse all op codes
  1257. // Assemble all op codes
  1258. // Disassemble all assembled op codes + compare
  1259. // Check function ends with RET or JUMPB/JMPBL - is this actually required?
  1260. TEST(FF7Field, Asm)
  1261. {
  1262. DummyFormatter dummy;
  1263. FieldEngine eng(dummy, "test");
  1264. InstVec insts;
  1265. FieldDisassembler d(dummy, &eng, insts);
  1266. }