diff --git a/Makefile b/Makefile index d1043ee..6f831de 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ reset: %.cpp : %.rl ragel -o $@ $< -build: ansi_parser.cpp +build: ansi_parser.cpp lel.cpp meson compile -j 10 -C builddir release_build: diff --git a/ansi_parser.cpp b/ansi_parser.cpp index 5a1224a..893486d 100644 --- a/ansi_parser.cpp +++ b/ansi_parser.cpp @@ -114,7 +114,7 @@ ANSIParser::ANSIParser(sf::Color default_fg, sf::Color default_bg) : } bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb) { - const wchar_t *start = NULL; + const wchar_t *start = nullptr; int cs = 0; unsigned int value = 0; const wchar_t *p = codes.data(); diff --git a/ansi_parser.rl b/ansi_parser.rl index dac3e03..0c000eb 100644 --- a/ansi_parser.rl +++ b/ansi_parser.rl @@ -132,7 +132,7 @@ ANSIParser::ANSIParser(sf::Color default_fg, sf::Color default_bg) : } bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_cb) { - const wchar_t *start = NULL; + const wchar_t *start = nullptr; int cs = 0; unsigned int value = 0; const wchar_t *p = codes.data(); diff --git a/lel.cpp b/lel.cpp new file mode 100644 index 0000000..ac59ef0 --- /dev/null +++ b/lel.cpp @@ -0,0 +1,294 @@ + +#line 1 "lel.rl" +#include "lel.hpp" +#include + + +#line 33 "lel.rl" + + + +#line 7 "lel.cpp" +static const char _LELParser_actions[] = { + 0, 1, 1, 1, 2, 1, 3, 1, + 4, 1, 5, 1, 6, 1, 9, 1, + 10, 1, 11, 2, 0, 7, 2, 0, + 8, 2, 4, 1, 2, 4, 5 +}; + +static const char _LELParser_key_offsets[] = { + 0, 0, 4, 18, 20, 24, 35, 47, + 52, 66, 68, 72, 83, 95, 99, 101, + 104, 106, 109 +}; + +static const char _LELParser_trans_keys[] = { + 32, 91, 9, 13, 32, 40, 42, 46, + 60, 62, 94, 95, 9, 13, 65, 90, + 97, 122, 48, 57, 41, 44, 48, 57, + 40, 42, 46, 60, 62, 94, 95, 65, + 90, 97, 122, 32, 93, 95, 124, 9, + 13, 48, 57, 65, 90, 97, 122, 32, + 93, 124, 9, 13, 32, 40, 42, 46, + 60, 62, 94, 95, 9, 13, 65, 90, + 97, 122, 48, 57, 41, 44, 48, 57, + 40, 42, 46, 60, 62, 94, 95, 65, + 90, 97, 122, 32, 93, 95, 124, 9, + 13, 48, 57, 65, 90, 97, 122, 32, + 93, 9, 13, 48, 57, 41, 48, 57, + 48, 57, 41, 48, 57, 32, 91, 9, + 13, 0 +}; + +static const char _LELParser_single_lengths[] = { + 0, 2, 8, 0, 2, 7, 4, 3, + 8, 0, 2, 7, 4, 2, 0, 1, + 0, 1, 2 +}; + +static const char _LELParser_range_lengths[] = { + 0, 1, 3, 1, 1, 2, 4, 1, + 3, 1, 1, 2, 4, 1, 1, 1, + 1, 1, 1 +}; + +static const char _LELParser_index_offsets[] = { + 0, 0, 4, 16, 18, 22, 32, 41, + 46, 58, 60, 64, 74, 83, 87, 89, + 92, 94, 97 +}; + +static const char _LELParser_indicies[] = { + 0, 2, 0, 1, 3, 4, 5, 6, + 7, 7, 6, 8, 3, 8, 8, 1, + 9, 1, 10, 11, 12, 1, 4, 5, + 6, 7, 7, 6, 8, 8, 8, 1, + 13, 15, 14, 16, 13, 14, 14, 14, + 1, 17, 18, 19, 17, 1, 20, 21, + 22, 23, 24, 24, 23, 25, 20, 25, + 25, 1, 26, 1, 27, 28, 29, 1, + 21, 22, 23, 24, 24, 23, 25, 25, + 25, 1, 30, 15, 31, 16, 30, 31, + 31, 31, 1, 32, 18, 32, 1, 33, + 1, 34, 35, 1, 36, 1, 37, 38, + 1, 39, 2, 39, 1, 0 +}; + +static const char _LELParser_trans_targs[] = { + 1, 0, 2, 2, 3, 5, 5, 5, + 6, 4, 5, 16, 4, 7, 6, 18, + 8, 7, 18, 8, 8, 9, 11, 11, + 11, 12, 10, 11, 14, 10, 13, 12, + 13, 15, 11, 15, 17, 5, 17, 18 +}; + +static const char _LELParser_trans_actions[] = { + 0, 0, 3, 0, 0, 13, 5, 11, + 17, 15, 19, 19, 0, 7, 0, 28, + 25, 0, 9, 1, 0, 0, 13, 5, + 11, 17, 15, 19, 19, 0, 7, 0, + 0, 15, 22, 0, 15, 22, 0, 0 +}; + +static const int LELParser_start = 1; +static const int LELParser_first_final = 18; +static const int LELParser_error = 0; + +static const int LELParser_en_main = 1; + + +#line 36 "lel.rl" + +bool LELParser::parse(std::string input) { + int cs = 0; + const char *start = nullptr; + const char *begin = input.data(); + const char *p = input.data(); + const char *pe = p + input.size(); + std::string tk; + + +#line 103 "lel.cpp" + { + cs = LELParser_start; + } + +#line 46 "lel.rl" + +#line 106 "lel.cpp" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _LELParser_trans_keys + _LELParser_key_offsets[cs]; + _trans = _LELParser_index_offsets[cs]; + + _klen = _LELParser_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (unsigned int)(_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _LELParser_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += (unsigned int)((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + _trans = _LELParser_indicies[_trans]; + cs = _LELParser_trans_targs[_trans]; + + if ( _LELParser_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _LELParser_actions + _LELParser_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 8 "lel.rl" + {tk = input.substr(start - begin, p - start); } + break; + case 1: +#line 10 "lel.rl" + { col(); } + break; + case 2: +#line 11 "lel.rl" + { ltab(); } + break; + case 3: +#line 12 "lel.rl" + { valign((*p)); } + break; + case 4: +#line 13 "lel.rl" + { id(input.substr(start - begin, p - start)); } + break; + case 5: +#line 14 "lel.rl" + { row(); } + break; + case 6: +#line 15 "lel.rl" + { align((*p)); } + break; + case 7: +#line 16 "lel.rl" + { setwidth(std::stoi(tk)); } + break; + case 8: +#line 17 "lel.rl" + { setheight(std::stoi(tk)); } + break; + case 9: +#line 18 "lel.rl" + { expand(); } + break; + case 10: +#line 26 "lel.rl" + { start = p; } + break; + case 11: +#line 29 "lel.rl" + {start = p;} + break; +#line 215 "lel.cpp" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 47 "lel.rl" + + bool good = pe - p == 0; + + return good; +} + +void LELParser::col() { + fmt::println("col"); +} + +void LELParser::ltab() { + fmt::println("ltab"); +} + +void LELParser::valign(char dir) { + fmt::println("valign: {}", dir); +} + +void LELParser::align(char dir) { + fmt::println("align {}", dir); +} + +void LELParser::id(std::string name) { + fmt::println("id: {}", name); +} + +void LELParser::row() { + fmt::println("row"); +} + +void LELParser::setwidth(int width) { + fmt::println("setwidth: {}", width); +} + +void LELParser::setheight(int height) { + fmt::println("setheight: {}", height); +} + +void LELParser::expand() { + fmt::println("expand"); +} diff --git a/lel.rl b/lel.rl new file mode 100644 index 0000000..555e7b7 --- /dev/null +++ b/lel.rl @@ -0,0 +1,87 @@ +#include "lel.hpp" +#include + +%%{ + machine LELParser; + alphtype char; + + action token {tk = input.substr(start - begin, fpc - start); } + + action col { col(); } + action ltab { ltab(); } + action valign { valign(fc); } + action id { id(input.substr(start - begin, fpc - start)); } + action row { row(); } + action align { align(fc); } + action setwidth { setwidth(std::stoi(tk)); } + action setheight { setheight(std::stoi(tk)); } + action expand { expand(); } + + col = "|" $col; + ltab = "[" $ltab; + rtab = "]" $row; + valign = ("^" | ".") $valign; + expand = "*" $expand; + halign = ("<" | ">") $align; + number = digit+ >{ start = fpc; } %token; + setw = ("(" number %setwidth ("," number %setheight)? ")") ; + modifiers = (expand | valign | halign | setw); + id = modifiers* ((alpha | '_')+ :>> (alnum | '_')*) >{start = fpc;} %id; + row = space* ltab space* id space* (col space* id)* space* rtab space*; + + main := row+; +}%% + +%% write data; + +bool LELParser::parse(std::string input) { + int cs = 0; + const char *start = nullptr; + const char *begin = input.data(); + const char *p = input.data(); + const char *pe = p + input.size(); + std::string tk; + + %% write init; + %% write exec; + + bool good = pe - p == 0; + + return good; +} + +void LELParser::col() { + fmt::println("col"); +} + +void LELParser::ltab() { + fmt::println("ltab"); +} + +void LELParser::valign(char dir) { + fmt::println("valign: {}", dir); +} + +void LELParser::align(char dir) { + fmt::println("align {}", dir); +} + +void LELParser::id(std::string name) { + fmt::println("id: {}", name); +} + +void LELParser::row() { + fmt::println("row"); +} + +void LELParser::setwidth(int width) { + fmt::println("setwidth: {}", width); +} + +void LELParser::setheight(int height) { + fmt::println("setheight: {}", height); +} + +void LELParser::expand() { + fmt::println("expand"); +} diff --git a/meson.build b/meson.build index 0c3bc69..fd2a3bd 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,7 @@ sources = [ 'devices.cpp', 'gui.cpp', 'inventory.cpp', + 'lel.cpp', 'levelmanager.cpp', 'lights.cpp', 'map.cpp', @@ -77,11 +78,13 @@ sources = [ ] executable('runtests', sources + [ + 'tests/ansi_parser.cpp', 'tests/base.cpp', 'tests/dbc.cpp', 'tests/dinkyecs.cpp', 'tests/fsm.cpp', 'tests/inventory.cpp', + 'tests/lel.cpp', 'tests/levelmanager.cpp', 'tests/lighting.cpp', 'tests/map.cpp', diff --git a/tests/ansi_parser.cpp b/tests/ansi_parser.cpp new file mode 100644 index 0000000..1c7a1b9 --- /dev/null +++ b/tests/ansi_parser.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include "ansi_parser.hpp" +#include +#include + +#include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, Fit, border +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight, Color::Palette256, ftxui +#include // for ColorInfo +#include // for Full, Screen +#include // for Full, Screen +#include // for ColorSupport, Color, Palette16, Palette256, TrueColor +#include "render.hpp" + +using namespace fmt; +using namespace ftxui; + +std::string generate_colors() { + SFMLRender::init_terminal(); + + REQUIRE(ftxui::Terminal::ColorSupport() == ftxui::Terminal::Color::TrueColor); + + const int max_value = 255; + const int value_increment = 8; + const int hue_increment = 6; + int saturation = max_value; + Elements array; + int count = 0; + + for (int value = 0; value < max_value; value += 2 * value_increment) { + Elements line; + for (int hue = 0; hue < max_value; hue += hue_increment) { + line.push_back( + text("#") // + | ftxui::color(Color::HSV(hue, saturation, value)) // + | ftxui::bgcolor(Color::HSV(hue, saturation, value + value_increment))); + count++; + } + array.push_back(hbox(std::move(line))); + } + + auto true_color_display = vbox({ + vbox(std::move(array)), + }); + + auto document = vbox({hbox({ + true_color_display, + })}); + + auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); + Render(screen, document); + return screen.ToString(); +} + +TEST_CASE("test out ragel parser", "[gui]") { + SFMLRender::init_terminal(); + sf::Color default_fg(0,0,0); + sf::Color default_bg(100,100,100); + + // this sets the Truecolor so need to do it first + ANSIParser ansi(default_fg, default_bg); + std::wstring_convert> $converter; + std::string colors = generate_colors(); + std::wstring colors_utf = $converter.from_bytes(colors); + + bool good = ansi.parse(colors_utf, + [&](sf::Color color[[maybe_unused]], sf::Color bgcolor[[maybe_unused]]){ + }, + [&](wchar_t ch) { + bool correct_char = ch == '#' || ch == ' ' || ch == '\n' || ch == '\r'; + REQUIRE(correct_char); + }); + + REQUIRE(good); +} diff --git a/tests/lel.cpp b/tests/lel.cpp new file mode 100644 index 0000000..b142433 --- /dev/null +++ b/tests/lel.cpp @@ -0,0 +1,21 @@ +#include "lel.hpp" +#include +#include +#include +#include "ansi_parser.hpp" +#include +#include + + + +TEST_CASE("test basic ops", "[lel]") { + LELParser parser; + + bool good = parser.parse( + "[ label_1 | label3 ]" + "[ (300,300)*text1 | (150)people ]" + "[