diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000..2b11e35 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,49 @@ +name: CMake + +on: [push, pull_request] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#configuring-a-build-matrix + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v2 + + - name: Create Build Environment + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + shell: bash + working-directory: ${{runner.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config $BUILD_TYPE + + - name: Test + working-directory: ${{runner.workspace}}/build + shell: bash + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C $BUILD_TYPE diff --git a/.travis.yml b/.travis.yml index 0b5fbad..2529dc6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,39 +1,20 @@ language: cpp -sudo: false matrix: include: - - compiler: gcc + - os: linux addons: apt: sources: - ubuntu-toolchain-r-test - - george-edison55-precise-backports packages: - - cmake - - cmake-data - - gcc-4.9 - - g++-4.9 - env: COMPILER=g++-4.9 -# - compiler: clang -# addons: -# apt: -# sources: -# - kubuntu-backports -# - ubuntu-toolchain-r-test -# - llvm-toolchain-precise-3.7 -# packages: -# - cmake -# - clang-3.7 -# env: COMPILER=clang++-3.7 + - g++-8 + env: + - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" -branches: - only: - - master - -before_script: - - export CXX=$COMPILER +before_install: + - eval "${MATRIX_EVAL}" script: - mkdir build && cd build - - cmake .. && make && ctest -V + - cmake .. && make && ./test/test-main diff --git a/CMakeLists.txt b/CMakeLists.txt index c83c5e0..3d5f99a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,33 +1,11 @@ cmake_minimum_required(VERSION 3.1.0) project("cpp-peglib") -# Check if a supported compiler is used to setup the C++ standard to use: -get_property(known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) -list(FIND known_features "cxx_std_17" found) -if(NOT ${found} EQUAL -1) - # C++17 standard is supported - set(CMAKE_CXX_STANDARD 17) -else() - # Check for C++11 standard support - list(FIND known_features "cxx_std_11" found) - if(NOT ${found} EQUAL -1) - # C++11 standard is supported - set(CMAKE_CXX_STANDARD 11) - endif() -endif() - -if(${found} EQUAL -1) - message(FATAL_ERROR "Your compiler is not supported.") -endif() - +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_EXTENSIONS OFF) -if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat -Wno-padded -Wno-weak-vtables -Wno-exit-time-destructors -Wno-c++2a-compat -Wno-switch-enum -Wno-c++98-compat-pedantic") -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wpedantic -Wextra -Woverloaded-virtual") -elseif(MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /wd4503 /wd4512 /utf-8") +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus /utf-8") endif() set(THREADS_PREFER_PTHREAD_FLAG ON) @@ -37,10 +15,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(add_link_deps Threads::Threads) endif() -enable_testing() - -add_subdirectory(test) add_subdirectory(example) add_subdirectory(lint) +add_subdirectory(test) +enable_testing() + install(FILES peglib.h DESTINATION include) diff --git a/README.md b/README.md index d16a325..9b9b9e1 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ cpp-peglib ========== +[![](https://github.com/yhirose/cpp-peglib/workflows/CMake/badge.svg)](https://github.com/yhirose/cpp-peglib/actions) [![Build Status](https://travis-ci.org/yhirose/cpp-peglib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-peglib) [![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-peglib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-peglib) -C++11 header-only [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) (Parsing Expression Grammars) library. You can start using it right away just by including `peglib.h` in your project. +C++17 header-only [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) (Parsing Expression Grammars) library. You can start using it right away just by including `peglib.h` in your project. + +Since this library only supports C++17 compilers, please make sure that compiler the option `-std=c++17` is enabled. (`/std:c++17 /Zc:__cplusplus` for MSVC) You can also try the online version, PEG Playground at https://yhirose.github.io/cpp-peglib. @@ -44,8 +47,8 @@ using namespace peg; using namespace std; int main(void) { - // (2) Make a parser - parser parser(R"( + // (2) Make a parser + parser parser(R"( # Grammar for Calculator... Additive <- Multitive '+' Additive / Multitive Multitive <- Primary '*' Multitive / Primary @@ -54,38 +57,38 @@ int main(void) { %whitespace <- [ \t]* )"); - assert((bool)parser == true); + assert(static_cast(parser) == true); - // (3) Setup actions - parser["Additive"] = [](const SemanticValues& sv) { - switch (sv.choice()) { - case 0: // "Multitive '+' Additive" - return any_cast(sv[0]) + any_cast(sv[1]); - default: // "Multitive" - return any_cast(sv[0]); - } - }; - - parser["Multitive"] = [](const SemanticValues& sv) { - switch (sv.choice()) { - case 0: // "Primary '*' Multitive" - return any_cast(sv[0]) * any_cast(sv[1]); - default: // "Primary" - return any_cast(sv[0]); - } - }; + // (3) Setup actions + parser["Additive"] = [](const SemanticValues &vs) { + switch (vs.choice()) { + case 0: // "Multitive '+' Additive" + return any_cast(vs[0]) + any_cast(vs[1]); + default: // "Multitive" + return any_cast(vs[0]); + } + }; + + parser["Multitive"] = [](const SemanticValues &vs) { + switch (vs.choice()) { + case 0: // "Primary '*' Multitive" + return any_cast(vs[0]) * any_cast(vs[1]); + default: // "Primary" + return any_cast(vs[0]); + } + }; - parser["Number"] = [](const SemanticValues& sv) { - return stoi(sv.token(), nullptr, 10); - }; + parser["Number"] = [](const SemanticValues &vs) { + return vs.token_to_number(); + }; - // (4) Parse - parser.enable_packrat_parsing(); // Enable packrat parsing. + // (4) Parse + parser.enable_packrat_parsing(); // Enable packrat parsing. - int val; - parser.parse(" (1 + 2) * 3 ", val); + int val; + parser.parse(" (1 + 2) * 3 ", val); - assert(val == 9); + assert(val == 9); } ``` @@ -104,7 +107,7 @@ auto grammar = R"( parser parser; parser.log = [](size_t line, size_t col, const string& msg) { - cerr << line << ":" << col << ": " << msg << "\n"; + cerr << line << ":" << col << ": " << msg << "\n"; }; auto ok = parser.load_grammar(grammar); @@ -114,10 +117,10 @@ assert(ok); There are four semantic actions available: ```cpp -[](const SemanticValues& sv, any& dt) -[](const SemanticValues& sv) -[](SemanticValues& sv, any& dt) -[](SemanticValues& sv) +[](const SemanticValues& vs, any& dt) +[](const SemanticValues& vs) +[](SemanticValues& vs, any& dt) +[](SemanticValues& vs) ``` `SemanticValues` value contains the following information: @@ -129,48 +132,36 @@ There are four semantic actions available: `any& dt` is a 'read-write' context data which can be used for whatever purposes. The initial context data is set in `peg::parser::parse` method. -`peg::any` is a simpler implementatin of std::any. If the compiler in use supports C++17, by default `peg::any` is defined as an alias to `std::any`. - -To force using the simpler `any` implementation that comes with `cpp-peglib`, define `PEGLIB_USE_STD_ANY` as 0 before including `peglib.h`: -```cpp -#define PEGLIB_USE_STD_ANY 0 -#include -[...] -``` - -A semantic action can return a value of arbitrary data type, which will be wrapped by `peg::any`. If a user returns nothing in a semantic action, the first semantic value in the `const SemanticValues& sv` argument will be returned. (Yacc parser has the same behavior.) +A semantic action can return a value of arbitrary data type, which will be wrapped by `peg::any`. If a user returns nothing in a semantic action, the first semantic value in the `const SemanticValues& vs` argument will be returned. (Yacc parser has the same behavior.) Here shows the `SemanticValues` structure: ```cpp struct SemanticValues : protected std::vector { - // Input text - const char* path; - const char* ss; + // Input text + const char* path; + const char* ss; - // Matched string - std::string str() const; // Matched string - const char* c_str() const; // Matched string start - size_t length() const; // Matched string length + // Matched string + std::string_view sv() const { return sv_; } - // Line number and column at which the matched string is - std::pair line_info() const; + // Line number and column at which the matched string is + std::pair line_info() const; - // Tokens - std::vector< - std::pair< - const char*, // Token start - size_t>> // Token length - tokens; + // Tokens + std::vector tokens; + std::string_view token(size_t id = 0) const; - std::string token(size_t id = 0) const; + // Token conversion + std::string token_to_string(size_t id = 0) const; + template T token_to_number() const; - // Choice number (0 based index) - size_t choice() const; + // Choice number (0 based index) + size_t choice() const; - // Transform the semantic value vector to another vector - template vector transform(size_t beg = 0, size_t end = -1) const; + // Transform the semantic value vector to another vector + template vector transform(size_t beg = 0, size_t end = -1) const; } ``` @@ -178,14 +169,14 @@ The following example uses `<` ... ` >` operator, which is *token boundary* oper ```cpp peg::parser parser(R"( - ROOT <- _ TOKEN (',' _ TOKEN)* - TOKEN <- < [a-z0-9]+ > _ - _ <- [ \t\r\n]* + ROOT <- _ TOKEN (',' _ TOKEN)* + TOKEN <- < [a-z0-9]+ > _ + _ <- [ \t\r\n]* )"); -parser["TOKEN"] = [](const SemanticValues& sv) { - // 'token' doesn't include trailing whitespaces - auto token = sv.token(); +parser["TOKEN"] = [](const SemanticValues& vs) { + // 'token' doesn't include trailing whitespaces + auto token = vs.token(); }; auto ret = parser.parse(" token1, token2 "); @@ -195,13 +186,13 @@ We can ignore unnecessary semantic values from the list by using `~` operator. ```cpp peg::parser parser(R"( - ROOT <- _ ITEM (',' _ ITEM _)* - ITEM <- ([a-z])+ - ~_ <- [ \t]* + ROOT <- _ ITEM (',' _ ITEM _)* + ITEM <- ([a-z])+ + ~_ <- [ \t]* )"); -parser["ROOT"] = [&](const SemanticValues& sv) { - assert(sv.size() == 2); // should be 2 instead of 5. +parser["ROOT"] = [&](const SemanticValues& vs) { + assert(vs.size() == 2); // should be 2 instead of 5. }; auto ret = parser.parse(" item1, item2 "); @@ -211,9 +202,9 @@ The following grammar is same as the above. ```cpp peg::parser parser(R"( - ROOT <- ~_ ITEM (',' ~_ ITEM ~_)* - ITEM <- ([a-z])+ - _ <- [ \t]* + ROOT <- ~_ ITEM (',' ~_ ITEM ~_)* + ITEM <- ([a-z])+ + _ <- [ \t]* )"); ``` @@ -222,12 +213,12 @@ peg::parser parser(R"( ```cpp peg::parser parser("NUMBER <- [0-9]+"); -parser["NUMBER"] = [](const SemanticValues& sv) { - auto val = stol(sv.str(), nullptr, 10); - if (val != 100) { - throw peg::parse_error("value error!!"); - } - return val; +parser["NUMBER"] = [](const SemanticValues& vs) { + auto val = vs.token_to_number(); + if (val != 100) { + throw peg::parse_error("value error!!"); + } + return val; }; long val; @@ -243,15 +234,15 @@ assert(ret == false); ```cpp parser["RULE"].enter = [](const char* s, size_t n, any& dt) { - std::cout << "enter" << std::endl; + std::cout << "enter" << std::endl; }; -parser["RULE"] = [](const SemanticValues& sv, any& dt) { - std::cout << "action!" << std::endl; +parser["RULE"] = [](const SemanticValues& vs, any& dt) { + std::cout << "action!" << std::endl; }; parser["RULE"].leave = [](const char* s, size_t n, size_t matchlen, any& value, any& dt) { - std::cout << "leave" << std::endl; + std::cout << "leave" << std::endl; }; ``` @@ -291,9 +282,9 @@ Word expression ```cpp peg::parser parser(R"( - ROOT <- 'hello' 'world' - %whitespace <- [ \t\r\n]* - %word <- [a-z]+ + ROOT <- 'hello' 'world' + %whitespace <- [ \t\r\n]* + %word <- [a-z]+ )"); parser.parse("hello world"); // OK @@ -305,14 +296,14 @@ Capture/Backreference ```cpp peg::parser parser(R"( - ROOT <- CONTENT - CONTENT <- (ELEMENT / TEXT)* - ELEMENT <- $(STAG CONTENT ETAG) - STAG <- '<' $tag< TAG_NAME > '>' - ETAG <- '' - TAG_NAME <- 'b' / 'u' - TEXT <- TEXT_DATA - TEXT_DATA <- ![<] . + ROOT <- CONTENT + CONTENT <- (ELEMENT / TEXT)* + ELEMENT <- $(STAG CONTENT ETAG) + STAG <- '<' $tag< TAG_NAME > '>' + ETAG <- '' + TAG_NAME <- 'b' / 'u' + TEXT <- TEXT_DATA + TEXT_DATA <- ![<] . )"); parser.parse("This is a test text."); // OK @@ -359,36 +350,36 @@ Regarding the *precedence climbing algorithm*, please see [this article](https:/ ```cpp parser parser(R"( - EXPRESSION <- INFIX_EXPRESSION(ATOM, OPERATOR) - ATOM <- NUMBER / '(' EXPRESSION ')' - OPERATOR <- < [-+/*] > - NUMBER <- < '-'? [0-9]+ > - %whitespace <- [ \t]* - - # Declare order of precedence - INFIX_EXPRESSION(A, O) <- A (O A)* { - precedence - L + - - L * / - } + EXPRESSION <- INFIX_EXPRESSION(ATOM, OPERATOR) + ATOM <- NUMBER / '(' EXPRESSION ')' + OPERATOR <- < [-+/*] > + NUMBER <- < '-'? [0-9]+ > + %whitespace <- [ \t]* + + # Declare order of precedence + INFIX_EXPRESSION(A, O) <- A (O A)* { + precedence + L + - + L * / + } )"); -parser["INFIX_EXPRESSION"] = [](const SemanticValues& sv) -> long { - auto result = any_cast(sv[0]); - if (sv.size() > 1) { - auto ope = any_cast(sv[1]); - auto num = any_cast(sv[2]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } +parser["INFIX_EXPRESSION"] = [](const SemanticValues& vs) -> long { + auto result = any_cast(vs[0]); + if (vs.size() > 1) { + auto ope = any_cast(vs[1]); + auto num = any_cast(vs[2]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; } - return result; + } + return result; }; -parser["OPERATOR"] = [](const SemanticValues& sv) { return *sv.c_str(); }; -parser["NUMBER"] = [](const SemanticValues& sv) { return atol(sv.c_str()); }; +parser["OPERATOR"] = [](const SemanticValues& vs) { return *vs.sv(); }; +parser["NUMBER"] = [](const SemanticValues& vs) { return vs.token_to_number(); }; long val; parser.parse(" -1 + (1 + 2) * 3 - -1", val); @@ -446,8 +437,8 @@ vector tags; Definition ROOT, TAG_NAME, _; ROOT <= seq(_, zom(seq(chr('['), TAG_NAME, chr(']'), _))); -TAG_NAME <= oom(seq(npd(chr(']')), dot())), [&](const SemanticValues& sv) { - tags.push_back(sv.str()); +TAG_NAME <= oom(seq(npd(chr(']')), dot())), [&](const SemanticValues& vs) { + tags.push_back(vs.str()); }; _ <= zom(cls(" \t")); @@ -487,24 +478,24 @@ It's possible to add/override definitions. ```cpp auto syntax = R"( - ROOT <- _ 'Hello' _ NAME '!' _ + ROOT <- _ 'Hello' _ NAME '!' _ )"; Rules additional_rules = { - { - "NAME", usr([](const char* s, size_t n, SemanticValues& sv, any& dt) -> size_t { - static vector names = { "PEG", "BNF" }; - for (const auto& name: names) { - if (name.size() <= n && !name.compare(0, name.size(), s, name.size())) { - return name.size(); // processed length - } - } - return -1; // parse error - }) - }, - { - "~_", zom(cls(" \t\r\n")) - } + { + "NAME", usr([](const char* s, size_t n, SemanticValues& vs, any& dt) -> size_t { + static vector names = { "PEG", "BNF" }; + for (const auto& name: names) { + if (name.size() <= n && !name.compare(0, name.size(), s, name.size())) { + return name.size(); // processed length + } + } + return -1; // parse error + }) + }, + { + "~_", zom(cls(" \t\r\n")) + } }; auto g = parser(syntax, additional_rules); diff --git a/appveyor.yml b/appveyor.yml index 942555e..3b39dc2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,9 +2,6 @@ clone_depth: 5 environment: matrix: - - JOB: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - CMAKE_GENERATOR: "Visual Studio 14 2015" - JOB: Visual Studio 2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_GENERATOR: "Visual Studio 15 2017" diff --git a/docs/build.sh b/docs/build.sh index 91b6cbb..8099d75 100644 --- a/docs/build.sh +++ b/docs/build.sh @@ -1,2 +1,2 @@ source ~/Projects/emsdk/emsdk_env.sh -emcc -std=c++11 -O3 --bind -o native.js native.cpp +emcc -std=c++17 -O3 --bind -o native.js native.cpp diff --git a/docs/native.js b/docs/native.js index 32745cc..fe318f9 100644 --- a/docs/native.js +++ b/docs/native.js @@ -1 +1 @@ -var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":839,"maximum":839+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr,maxBytesToRead){var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0||i==maxBytesToRead/2)return str;++i;str+=String.fromCharCode(codeUnit)}}}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5278160,DYNAMICTOP_PTR=35120;var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}var wasmBinaryFile="native.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_allocate_exception(size){return _malloc(size)}var ___exception_infos={};var ___exception_last=0;function __ZSt18uncaught_exceptionv(){return __ZSt18uncaught_exceptionv.uncaught_exceptions>0}function ___cxa_throw(ptr,type,destructor){___exception_infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};___exception_last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___map_file(pathname,size){setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:function(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(populate,callback){if(typeof populate==="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:function(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=function(from,to){if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);if(typeof Uint8Array!="undefined")xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(chunkNum){var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]==="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]==="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!=="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){return low}};function syscallMunmap(addr,len){if((addr|0)===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);if(info.prot&2){SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset)}FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___sys_munmap(addr,len){try{return syscallMunmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n")(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function new_(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError("new_ called with constructor type "+typeof constructor+" which is not a function")}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0||i==length){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(HEAP[currentBytePtr>>shift]==0||i==length){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value==="string")){throwBindingError("Cannot pass non-string to C++ string type "+name)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function _abort(){abort()}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;abortOnCannotGrowMemory(requestedSize)}var ENV={};function __getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8","_":__getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var asmLibraryArg={"a":___assert_fail,"d":___cxa_allocate_exception,"c":___cxa_throw,"q":___map_file,"p":___sys_munmap,"k":__embind_register_bool,"j":__embind_register_emval,"i":__embind_register_float,"t":__embind_register_function,"e":__embind_register_integer,"b":__embind_register_memory_view,"g":__embind_register_std_string,"f":__embind_register_std_wstring,"l":__embind_register_void,"h":_abort,"m":_emscripten_memcpy_big,"n":_emscripten_resize_heap,"r":_environ_get,"s":_environ_sizes_get,"memory":wasmMemory,"o":_strftime_l,"table":wasmTable};var asm=createWasm();Module["asm"]=asm;var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["u"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["v"]).apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return(___getTypeName=Module["___getTypeName"]=Module["asm"]["w"]).apply(null,arguments)};var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=function(){return(___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=Module["asm"]["x"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["y"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["z"]).apply(null,arguments)};var dynCall_viii=Module["dynCall_viii"]=function(){return(dynCall_viii=Module["dynCall_viii"]=Module["asm"]["A"]).apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return(dynCall_viiii=Module["dynCall_viiii"]=Module["asm"]["B"]).apply(null,arguments)};var dynCall_vii=Module["dynCall_vii"]=function(){return(dynCall_vii=Module["dynCall_vii"]=Module["asm"]["C"]).apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return(dynCall_viiiiii=Module["dynCall_viiiiii"]=Module["asm"]["D"]).apply(null,arguments)};var dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=function(){return(dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=Module["asm"]["E"]).apply(null,arguments)};var dynCall_viiiiiii=Module["dynCall_viiiiiii"]=function(){return(dynCall_viiiiiii=Module["dynCall_viiiiiii"]=Module["asm"]["F"]).apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return(dynCall_vi=Module["dynCall_vi"]=Module["asm"]["G"]).apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return(dynCall_iii=Module["dynCall_iii"]=Module["asm"]["H"]).apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return(dynCall_ii=Module["dynCall_ii"]=Module["asm"]["I"]).apply(null,arguments)};var dynCall_iiiiii=Module["dynCall_iiiiii"]=function(){return(dynCall_iiiiii=Module["dynCall_iiiiii"]=Module["asm"]["J"]).apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return(dynCall_viiiii=Module["dynCall_viiiii"]=Module["asm"]["K"]).apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return(dynCall_iiii=Module["dynCall_iiii"]=Module["asm"]["L"]).apply(null,arguments)};var dynCall_viijii=Module["dynCall_viijii"]=function(){return(dynCall_viijii=Module["dynCall_viijii"]=Module["asm"]["M"]).apply(null,arguments)};var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=function(){return(dynCall_iiiiiii=Module["dynCall_iiiiiii"]=Module["asm"]["N"]).apply(null,arguments)};var dynCall_iidiiii=Module["dynCall_iidiiii"]=function(){return(dynCall_iidiiii=Module["dynCall_iidiiii"]=Module["asm"]["O"]).apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return(dynCall_iiiii=Module["dynCall_iiiii"]=Module["asm"]["P"]).apply(null,arguments)};var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=function(){return(dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=Module["asm"]["Q"]).apply(null,arguments)};var dynCall_iiiiij=Module["dynCall_iiiiij"]=function(){return(dynCall_iiiiij=Module["dynCall_iiiiij"]=Module["asm"]["R"]).apply(null,arguments)};var dynCall_iiiiid=Module["dynCall_iiiiid"]=function(){return(dynCall_iiiiid=Module["dynCall_iiiiid"]=Module["asm"]["S"]).apply(null,arguments)};var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=function(){return(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=Module["asm"]["T"]).apply(null,arguments)};var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=function(){return(dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=Module["asm"]["U"]).apply(null,arguments)};var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=function(){return(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=Module["asm"]["V"]).apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return(dynCall_v=Module["dynCall_v"]=Module["asm"]["W"]).apply(null,arguments)};Module["asm"]=asm;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":776,"maximum":776+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr,maxBytesToRead){var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0||i==maxBytesToRead/2)return str;++i;str+=String.fromCharCode(codeUnit)}}}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5279872,DYNAMICTOP_PTR=36832;var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}var wasmBinaryFile="native.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_allocate_exception(size){return _malloc(size)}var ___exception_infos={};var ___exception_last=0;function __ZSt18uncaught_exceptionv(){return __ZSt18uncaught_exceptionv.uncaught_exceptions>0}function ___cxa_throw(ptr,type,destructor){___exception_infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};___exception_last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___map_file(pathname,size){setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:function(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(populate,callback){if(typeof populate==="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:function(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=function(from,to){if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);if(typeof Uint8Array!="undefined")xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(chunkNum){var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]==="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]==="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!=="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){return low}};function syscallMunmap(addr,len){if((addr|0)===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);if(info.prot&2){SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset)}FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___sys_munmap(addr,len){try{return syscallMunmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+' "use strict";'+" return body.apply(this, arguments);\n"+"};\n")(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function new_(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError("new_ called with constructor type "+typeof constructor+" which is not a function")}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0||i==length){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(HEAP[currentBytePtr>>shift]==0||i==length){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value==="string")){throwBindingError("Cannot pass non-string to C++ string type "+name)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function _abort(){abort()}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;abortOnCannotGrowMemory(requestedSize)}var ENV={};function __getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8","_":__getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var asmLibraryArg={"b":___assert_fail,"e":___cxa_allocate_exception,"d":___cxa_throw,"q":___map_file,"p":___sys_munmap,"k":__embind_register_bool,"j":__embind_register_emval,"i":__embind_register_float,"t":__embind_register_function,"c":__embind_register_integer,"a":__embind_register_memory_view,"g":__embind_register_std_string,"f":__embind_register_std_wstring,"l":__embind_register_void,"h":_abort,"m":_emscripten_memcpy_big,"n":_emscripten_resize_heap,"r":_environ_get,"s":_environ_sizes_get,"memory":wasmMemory,"o":_strftime_l,"table":wasmTable};var asm=createWasm();Module["asm"]=asm;var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["u"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["v"]).apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return(___getTypeName=Module["___getTypeName"]=Module["asm"]["w"]).apply(null,arguments)};var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=function(){return(___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=Module["asm"]["x"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["y"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["z"]).apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return(dynCall_viiii=Module["dynCall_viiii"]=Module["asm"]["A"]).apply(null,arguments)};var dynCall_iiiiii=Module["dynCall_iiiiii"]=function(){return(dynCall_iiiiii=Module["dynCall_iiiiii"]=Module["asm"]["B"]).apply(null,arguments)};var dynCall_vii=Module["dynCall_vii"]=function(){return(dynCall_vii=Module["dynCall_vii"]=Module["asm"]["C"]).apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return(dynCall_viiiiii=Module["dynCall_viiiiii"]=Module["asm"]["D"]).apply(null,arguments)};var dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=function(){return(dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=Module["asm"]["E"]).apply(null,arguments)};var dynCall_viiiiiii=Module["dynCall_viiiiiii"]=function(){return(dynCall_viiiiiii=Module["dynCall_viiiiiii"]=Module["asm"]["F"]).apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return(dynCall_vi=Module["dynCall_vi"]=Module["asm"]["G"]).apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return(dynCall_ii=Module["dynCall_ii"]=Module["asm"]["H"]).apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return(dynCall_viiiii=Module["dynCall_viiiii"]=Module["asm"]["I"]).apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return(dynCall_iiii=Module["dynCall_iiii"]=Module["asm"]["J"]).apply(null,arguments)};var dynCall_viijii=Module["dynCall_viijii"]=function(){return(dynCall_viijii=Module["dynCall_viijii"]=Module["asm"]["K"]).apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return(dynCall_iii=Module["dynCall_iii"]=Module["asm"]["L"]).apply(null,arguments)};var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=function(){return(dynCall_iiiiiii=Module["dynCall_iiiiiii"]=Module["asm"]["M"]).apply(null,arguments)};var dynCall_iidiiii=Module["dynCall_iidiiii"]=function(){return(dynCall_iidiiii=Module["dynCall_iidiiii"]=Module["asm"]["N"]).apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return(dynCall_iiiii=Module["dynCall_iiiii"]=Module["asm"]["O"]).apply(null,arguments)};var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=function(){return(dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=Module["asm"]["P"]).apply(null,arguments)};var dynCall_iiiiij=Module["dynCall_iiiiij"]=function(){return(dynCall_iiiiij=Module["dynCall_iiiiij"]=Module["asm"]["Q"]).apply(null,arguments)};var dynCall_iiiiid=Module["dynCall_iiiiid"]=function(){return(dynCall_iiiiid=Module["dynCall_iiiiid"]=Module["asm"]["R"]).apply(null,arguments)};var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=function(){return(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=Module["asm"]["S"]).apply(null,arguments)};var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=function(){return(dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=Module["asm"]["T"]).apply(null,arguments)};var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=function(){return(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=Module["asm"]["U"]).apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return(dynCall_v=Module["dynCall_v"]=Module["asm"]["V"]).apply(null,arguments)};Module["asm"]=asm;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); diff --git a/docs/native.wasm b/docs/native.wasm index 7af8445..2f0b1c3 100644 Binary files a/docs/native.wasm and b/docs/native.wasm differ diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 7669594..2c6aef2 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,13 +1,9 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.1) project(example) include_directories(..) -if(MSVC) - add_compile_options(${cxx11_options} /W3) -else() - add_compile_options(${cxx11_options}) -endif() +set(CMAKE_CXX_STANDARD 17) add_executable(calc calc.cc) target_link_libraries(calc ${add_link_deps}) diff --git a/example/calc.cc b/example/calc.cc index 6de3dd0..686aee7 100644 --- a/example/calc.cc +++ b/example/calc.cc @@ -1,13 +1,13 @@ -#include #include #include +#include using namespace peg; using namespace std; int main(void) { - // (2) Make a parser - parser parser(R"( + // (2) Make a parser + parser parser(R"( # Grammar for Calculator... Additive <- Multitive '+' Additive / Multitive Multitive <- Primary '*' Multitive / Primary @@ -16,36 +16,36 @@ int main(void) { %whitespace <- [ \t]* )"); - assert(static_cast(parser) == true); - - // (3) Setup actions - parser["Additive"] = [](const SemanticValues& sv) { - switch (sv.choice()) { - case 0: // "Multitive '+' Additive" - return any_cast(sv[0]) + any_cast(sv[1]); - default: // "Multitive" - return any_cast(sv[0]); - } - }; - - parser["Multitive"] = [](const SemanticValues& sv) { - switch (sv.choice()) { - case 0: // "Primary '*' Multitive" - return any_cast(sv[0]) * any_cast(sv[1]); - default: // "Primary" - return any_cast(sv[0]); - } - }; - - parser["Number"] = [](const SemanticValues& sv) { - return stoi(sv.token(), nullptr, 10); - }; - - // (4) Parse - parser.enable_packrat_parsing(); // Enable packrat parsing. - - int val; - parser.parse(" (1 + 2) * 3 ", val); - - assert(val == 9); + assert(static_cast(parser) == true); + + // (3) Setup actions + parser["Additive"] = [](const SemanticValues &vs) { + switch (vs.choice()) { + case 0: // "Multitive '+' Additive" + return any_cast(vs[0]) + any_cast(vs[1]); + default: // "Multitive" + return any_cast(vs[0]); + } + }; + + parser["Multitive"] = [](const SemanticValues &vs) { + switch (vs.choice()) { + case 0: // "Primary '*' Multitive" + return any_cast(vs[0]) * any_cast(vs[1]); + default: // "Primary" + return any_cast(vs[0]); + } + }; + + parser["Number"] = [](const SemanticValues &vs) { + return vs.token_to_number(); + }; + + // (4) Parse + parser.enable_packrat_parsing(); // Enable packrat parsing. + + int val; + parser.parse(" (1 + 2) * 3 ", val); + + assert(val == 9); } diff --git a/example/calc2.cc b/example/calc2.cc index 1ba00fa..c0121ab 100644 --- a/example/calc2.cc +++ b/example/calc2.cc @@ -5,9 +5,9 @@ // MIT License // -#include -#include #include +#include +#include using namespace peg; @@ -21,45 +21,47 @@ using namespace peg; // FACTOR_OPERATOR <- [/*] // NUMBER <- [0-9]+ // -int main(int argc, const char** argv) -{ - if (argc < 2 || std::string("--help") == argv[1]) { - std::cout << "usage: calc [formula]" << std::endl; - return 1; - } +int main(int argc, const char **argv) { + if (argc < 2 || std::string("--help") == argv[1]) { + std::cout << "usage: calc [formula]" << std::endl; + return 1; + } - auto reduce = [](const SemanticValues& sv) -> long { - auto result = any_cast(sv[0]); - for (auto i = 1u; i < sv.size(); i += 2) { - auto num = any_cast(sv[i + 1]); - auto ope = any_cast(sv[i]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; - }; + auto reduce = [](const SemanticValues &vs) { + auto result = std::any_cast(vs[0]); + for (auto i = 1u; i < vs.size(); i += 2) { + auto num = std::any_cast(vs[i + 1]); + auto ope = std::any_cast(vs[i]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; + } + } + return result; + }; - Definition EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, NUMBER; + Definition EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, NUMBER; - EXPRESSION <= seq(TERM, zom(seq(TERM_OPERATOR, TERM))), reduce; - TERM <= seq(FACTOR, zom(seq(FACTOR_OPERATOR, FACTOR))), reduce; - FACTOR <= cho(NUMBER, seq(chr('('), EXPRESSION, chr(')'))); - TERM_OPERATOR <= cls("+-"), [](const SemanticValues& sv) { return static_cast(*sv.c_str()); }; - FACTOR_OPERATOR <= cls("*/"), [](const SemanticValues& sv) { return static_cast(*sv.c_str()); }; - NUMBER <= oom(cls("0-9")), [](const SemanticValues& sv) { return atol(sv.c_str()); }; + EXPRESSION <= seq(TERM, zom(seq(TERM_OPERATOR, TERM))), reduce; + TERM <= seq(FACTOR, zom(seq(FACTOR_OPERATOR, FACTOR))), reduce; + FACTOR <= cho(NUMBER, seq(chr('('), EXPRESSION, chr(')'))); + TERM_OPERATOR <= cls("+-"), + [](const SemanticValues &vs) { return static_cast(*vs.sv().data()); }; + FACTOR_OPERATOR <= cls("*/"), + [](const SemanticValues &vs) { return static_cast(*vs.sv().data()); }; + NUMBER <= oom(cls("0-9")), + [](const SemanticValues &vs) { return vs.token_to_number(); }; - auto expr = argv[1]; - long val = 0; - if (EXPRESSION.parse_and_get_value(expr, val).ret) { - std::cout << expr << " = " << val << std::endl; - return 0; - } + auto expr = argv[1]; + long val = 0; + if (EXPRESSION.parse_and_get_value(expr, val).ret) { + std::cout << expr << " = " << val << std::endl; + return 0; + } - return -1; + return -1; } // vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/example/calc3.cc b/example/calc3.cc index f8f85bb..1f5b633 100644 --- a/example/calc3.cc +++ b/example/calc3.cc @@ -5,40 +5,39 @@ // MIT License // -#include -#include #include +#include +#include using namespace peg; -int main(int argc, const char** argv) -{ - if (argc < 2 || std::string("--help") == argv[1]) { - std::cout << "usage: calc3 [formula]" << std::endl; - return 1; - } +int main(int argc, const char **argv) { + if (argc < 2 || std::string("--help") == argv[1]) { + std::cout << "usage: calc3 [formula]" << std::endl; + return 1; + } - std::function eval = [&](const Ast& ast) { - if (ast.name == "NUMBER") { - return stol(ast.token); - } else { - const auto& nodes = ast.nodes; - auto result = eval(*nodes[0]); - for (auto i = 1u; i < nodes.size(); i += 2) { - auto num = eval(*nodes[i + 1]); - auto ope = nodes[i]->token[0]; - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; + std::function eval = [&](const Ast &ast) { + if (ast.name == "NUMBER") { + return ast.token_to_number(); + } else { + const auto &nodes = ast.nodes; + auto result = eval(*nodes[0]); + for (auto i = 1u; i < nodes.size(); i += 2) { + auto num = eval(*nodes[i + 1]); + auto ope = nodes[i]->token[0]; + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; } - }; + } + return result; + } + }; - parser parser(R"( + parser parser(R"( EXPRESSION <- TERM (TERM_OPERATOR TERM)* TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* FACTOR <- NUMBER / '(' EXPRESSION ')' @@ -50,20 +49,20 @@ int main(int argc, const char** argv) %whitespace <- [ \t\r\n]* )"); - parser.enable_ast(); + parser.enable_ast(); - auto expr = argv[1]; - std::shared_ptr ast; - if (parser.parse(expr, ast)) { - ast = AstOptimizer(true).optimize(ast); - std::cout << ast_to_s(ast); - std::cout << expr << " = " << eval(*ast) << std::endl; - return 0; - } + auto expr = argv[1]; + std::shared_ptr ast; + if (parser.parse(expr, ast)) { + ast = AstOptimizer(true).optimize(ast); + std::cout << ast_to_s(ast); + std::cout << expr << " = " << eval(*ast) << std::endl; + return 0; + } - std::cout << "syntax error..." << std::endl; + std::cout << "syntax error..." << std::endl; - return -1; + return -1; } // vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/example/calc4.cc b/example/calc4.cc index 1404dfc..563f994 100644 --- a/example/calc4.cc +++ b/example/calc4.cc @@ -1,12 +1,12 @@ -#include #include #include +#include using namespace peg; using namespace std; int main(void) { - parser parser(R"( + parser parser(R"( EXPRESSION <- ATOM (OPERATOR ATOM)* { precedence L - + @@ -18,25 +18,25 @@ int main(void) { %whitespace <- [ \t\r\n]* )"); - parser["EXPRESSION"] = [](const SemanticValues& sv) -> long { - auto result = any_cast(sv[0]); - if (sv.size() > 1) { - auto ope = any_cast(sv[1]); - auto num = any_cast(sv[2]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; - }; - parser["OPERATOR"] = [](const SemanticValues& sv) { return *sv.c_str(); }; - parser["NUMBER"] = [](const SemanticValues& sv) { return atol(sv.c_str()); }; + parser["EXPRESSION"] = [](const SemanticValues &vs) { + auto result = any_cast(vs[0]); + if (vs.size() > 1) { + auto ope = any_cast(vs[1]); + auto num = any_cast(vs[2]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; + } + } + return result; + }; + parser["OPERATOR"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + parser["NUMBER"] = [](const SemanticValues &vs) { return atol(vs.sv().data()); }; - long val; - parser.parse(" -1 + (1 + 2) * 3 - -1", val); + long val; + parser.parse(" -1 + (1 + 2) * 3 - -1", val); - assert(val == 9); + assert(val == 9); } diff --git a/example/calc5.cc b/example/calc5.cc index 2b9a750..449a7d3 100644 --- a/example/calc5.cc +++ b/example/calc5.cc @@ -5,40 +5,39 @@ // MIT License // -#include -#include #include +#include +#include using namespace peg; -int main(int argc, const char** argv) -{ - if (argc < 2 || std::string("--help") == argv[1]) { - std::cout << "usage: calc5 [formula]" << std::endl; - return 1; - } +int main(int argc, const char **argv) { + if (argc < 2 || std::string("--help") == argv[1]) { + std::cout << "usage: calc5 [formula]" << std::endl; + return 1; + } - std::function eval = [&](const Ast& ast) { - if (ast.name == "NUMBER") { - return stol(ast.token); - } else { - const auto& nodes = ast.nodes; - auto result = eval(*nodes[0]); - if (nodes.size() > 1) { - auto ope = nodes[1]->token[0]; - auto num = eval(*nodes[2]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; + std::function eval = [&](const Ast &ast) { + if (ast.name == "NUMBER") { + return ast.token_to_number(); + } else { + const auto &nodes = ast.nodes; + auto result = eval(*nodes[0]); + if (nodes.size() > 1) { + auto ope = nodes[1]->token[0]; + auto num = eval(*nodes[2]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; } - }; + } + return result; + } + }; - parser parser(R"( + parser parser(R"( EXPRESSION <- ATOM (OPERATOR ATOM)* { precedence L - + @@ -50,20 +49,20 @@ int main(int argc, const char** argv) %whitespace <- [ \t\r\n]* )"); - parser.enable_ast(); + parser.enable_ast(); - auto expr = argv[1]; - std::shared_ptr ast; - if (parser.parse(expr, ast)) { - ast = AstOptimizer(true).optimize(ast); - std::cout << ast_to_s(ast); - std::cout << expr << " = " << eval(*ast) << std::endl; - return 0; - } + auto expr = argv[1]; + std::shared_ptr ast; + if (parser.parse(expr, ast)) { + ast = AstOptimizer(true).optimize(ast); + std::cout << ast_to_s(ast); + std::cout << expr << " = " << eval(*ast) << std::endl; + return 0; + } - std::cout << "syntax error..." << std::endl; + std::cout << "syntax error..." << std::endl; - return -1; + return -1; } // vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/lint/CMakeLists.txt b/lint/CMakeLists.txt index 5561422..1c7e632 100644 --- a/lint/CMakeLists.txt +++ b/lint/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.1) project(peglint) + include_directories(..) -add_definitions("-std=c++11") -add_executable(peglint peglint.cc) -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - target_link_libraries(peglint ${add_link_deps}) -endif() +set(CMAKE_CXX_STANDARD 17) + +add_executable(peglint peglint.cc) +target_link_libraries(peglint ${add_link_deps}) diff --git a/lint/peglint.cc b/lint/peglint.cc index 930fd2e..7aeb2f4 100644 --- a/lint/peglint.cc +++ b/lint/peglint.cc @@ -131,7 +131,7 @@ int main(int argc, const char **argv) { parser.enable_trace( [&](const char *name, const char *s, size_t /*n*/, const peg::SemanticValues & /*sv*/, const peg::Context &c, - const peg::any & /*dt*/) { + const std::any & /*dt*/) { auto pos = static_cast(s - c.s); auto backtrack = (pos < prev_pos ? "*" : ""); string indent; @@ -145,7 +145,7 @@ int main(int argc, const char **argv) { }, [&](const char *name, const char *s, size_t /*n*/, const peg::SemanticValues &sv, const peg::Context &c, - const peg::any & /*dt*/, size_t len) { + const std::any & /*dt*/, size_t len) { auto pos = static_cast(s - c.s); if (len != static_cast(-1)) { pos += len; } string indent; @@ -160,8 +160,9 @@ int main(int argc, const char **argv) { } std::string token; if (!sv.tokens.empty()) { - const auto &tok = sv.tokens[0]; - token += " '" + std::string(tok.first, tok.second) + "'"; + token += " '"; + token += sv.tokens[0]; + token +=+ "'"; } std::cout << "L " << pos << "\t" << indent << ret << name << " #" << c.trace_ids.back() << choice.str() << token << std::endl; diff --git a/peglib.h b/peglib.h index 3cf24cd..e2e85ec 100644 --- a/peglib.h +++ b/peglib.h @@ -5,20 +5,13 @@ // MIT License // -#ifndef CPPPEGLIB_PEGLIB_H -#define CPPPEGLIB_PEGLIB_H - -#ifndef PEGLIB_USE_STD_ANY -#ifdef _MSVC_LANG -#define PEGLIB_USE_STD_ANY _MSVC_LANG >= 201703L -#elif defined(__cplusplus) -#define PEGLIB_USE_STD_ANY __cplusplus >= 201703L -#endif -#endif // PEGLIB_USE_STD_ANY +#pragma once #include +#include #include #include +#include #include #include #include @@ -29,110 +22,16 @@ #include #include #include -#include #include #include #include -#if PEGLIB_USE_STD_ANY -#include -#endif -// guard for older versions of VC++ -#ifdef _MSC_VER -#if defined(_MSC_VER) && _MSC_VER < 1900 // Less than Visual Studio 2015 -#error "Requires complete C+11 support" -#endif +#if !defined(__cplusplus) || __cplusplus < 201703L +#error "Requires complete C++17 support" #endif namespace peg { -/*----------------------------------------------------------------------------- - * any - *---------------------------------------------------------------------------*/ - -#if PEGLIB_USE_STD_ANY -using any = std::any; - -// Define a function alias to std::any_cast using perfect forwarding -template -auto any_cast(Args &&... args) - -> decltype(std::any_cast(std::forward(args)...)) { - return std::any_cast(std::forward(args)...); -} -#else -class any { -public: - any() = default; - - any(const any &rhs) : content_(rhs.clone()) {} - - any(any &&rhs) : content_(rhs.content_) { rhs.content_ = nullptr; } - - template any(const T &value) : content_(new holder(value)) {} - - any &operator=(const any &rhs) { - if (this != &rhs) { - if (content_) { delete content_; } - content_ = rhs.clone(); - } - return *this; - } - - any &operator=(any &&rhs) { - if (this != &rhs) { - if (content_) { delete content_; } - content_ = rhs.content_; - rhs.content_ = nullptr; - } - return *this; - } - - ~any() { delete content_; } - - bool has_value() const { return content_ != nullptr; } - - template friend T &any_cast(any &val); - - template friend const T &any_cast(const any &val); - -private: - struct placeholder { - virtual ~placeholder() {} - virtual placeholder *clone() const = 0; - }; - - template struct holder : placeholder { - holder(const T &value) : value_(value) {} - placeholder *clone() const override { return new holder(value_); } - T value_; - }; - - placeholder *clone() const { return content_ ? content_->clone() : nullptr; } - - placeholder *content_ = nullptr; -}; - -template T &any_cast(any &val) { - if (!val.content_) { throw std::bad_cast(); } - auto p = dynamic_cast *>(val.content_); - assert(p); - if (!p) { throw std::bad_cast(); } - return p->value_; -} - -template <> inline any &any_cast(any &val) { return val; } - -template const T &any_cast(const any &val) { - assert(val.content_); - auto p = dynamic_cast *>(val.content_); - assert(p); - if (!p) { throw std::bad_cast(); } - return p->value_; -} - -template <> inline const any &any_cast(const any &val) { return val; } -#endif - /*----------------------------------------------------------------------------- * scope_exit *---------------------------------------------------------------------------*/ @@ -165,12 +64,6 @@ private: bool execute_on_destruction; }; -template -auto make_scope_exit(EF &&exit_function) -> scope_exit { - return scope_exit::type>( - std::forward(exit_function)); -} - /*----------------------------------------------------------------------------- * UTF8 functions *---------------------------------------------------------------------------*/ @@ -324,7 +217,7 @@ inline std::pair parse_hex_number(const char *s, size_t n, ret = static_cast(ret * 16 + val); i++; } - return std::make_pair(ret, i); + return std::pair(ret, i); } inline std::pair parse_octal_number(const char *s, size_t n, @@ -335,7 +228,7 @@ inline std::pair parse_octal_number(const char *s, size_t n, ret = static_cast(ret * 8 + val); i++; } - return std::make_pair(ret, i); + return std::pair(ret, i); } inline std::string resolve_escape_sequence(const char *s, size_t n) { @@ -416,10 +309,10 @@ public: for (const auto &item : items) { for (size_t len = 1; len <= item.size(); len++) { auto last = len == item.size(); - std::string s(item.c_str(), len); - auto it = dic_.find(s); + std::string_view sv(item.data(), len); + auto it = dic_.find(sv); if (it == dic_.end()) { - dic_.emplace(s, Info{last, last}); + dic_.emplace(sv, Info{last, last}); } else if (last) { it->second.match = true; } else { @@ -431,20 +324,18 @@ public: size_t match(const char *text, size_t text_len) const { size_t match_len = 0; - { - auto done = false; - size_t len = 1; - while (!done && len <= text_len) { - std::string s(text, len); - auto it = dic_.find(s); - if (it == dic_.end()) { - done = true; - } else { - if (it->second.match) { match_len = len; } - if (it->second.done) { done = true; } - } - len += 1; + auto done = false; + size_t len = 1; + while (!done && len <= text_len) { + std::string_view sv(text, len); + auto it = dic_.find(sv); + if (it == dic_.end()) { + done = true; + } else { + if (it->second.match) { match_len = len; } + if (it->second.done) { done = true; } } + len += 1; } return match_len; } @@ -454,7 +345,10 @@ private: bool done; bool match; }; - std::unordered_map dic_; + + // TODO: Use unordered_map when heterogeneous lookup is supported in C++20 + // std::unordered_map dic_; + std::map> dic_; }; /*----------------------------------------------------------------------------- @@ -479,22 +373,27 @@ inline std::pair line_info(const char *start, const char *cur) { auto col = p - col_ptr + 1; - return std::make_pair(no, col); + return std::pair(no, col); } /* * String tag */ -inline constexpr unsigned int str2tag(const char *str, unsigned int h = 0) { - return (*str == '\0') - ? h - : str2tag(str + 1, (h * 33) ^ static_cast(*str)); +inline constexpr unsigned int str2tag_core(const char *s, size_t l, + unsigned int h) { + return (l == 0) ? h + : str2tag_core(s + 1, l - 1, + (h * 33) ^ static_cast(*s)); +} + +inline constexpr unsigned int str2tag(std::string_view sv) { + return str2tag_core(sv.data(), sv.size(), 0); } namespace udl { -inline constexpr unsigned int operator"" _(const char *s, size_t) { - return str2tag(s); +inline constexpr unsigned int operator"" _(const char *s, size_t l) { + return str2tag_core(s, l, 0); } } // namespace udl @@ -502,17 +401,14 @@ inline constexpr unsigned int operator"" _(const char *s, size_t) { /* * Semantic values */ -struct SemanticValues : protected std::vector { +struct SemanticValues : protected std::vector { // Input text const char *path = nullptr; const char *ss = nullptr; const std::vector *source_line_index = nullptr; // Matched string - const char *c_str() const { return s_; } - size_t length() const { return n_; } - - std::string str() const { return std::string(s_, n_); } + std::string_view sv() const { return sv_; } // Definition name const std::string &name() const { return name_; } @@ -523,14 +419,14 @@ struct SemanticValues : protected std::vector { std::pair line_info() const { const auto &idx = *source_line_index; - auto cur = static_cast(std::distance(ss, s_)); + auto cur = static_cast(std::distance(ss, sv_.data())); auto it = std::lower_bound( idx.begin(), idx.end(), cur, [](size_t element, size_t value) { return element < value; }); auto id = static_cast(std::distance(idx.begin(), it)); auto off = cur - (id == 0 ? 0 : idx[id - 1] + 1); - return std::make_pair(id + 1, off + 1); + return std::pair(id + 1, off + 1); } // Choice count @@ -540,15 +436,24 @@ struct SemanticValues : protected std::vector { size_t choice() const { return choice_; } // Tokens - std::vector> tokens; + std::vector tokens; - std::string token(size_t id = 0) const { - if (!tokens.empty()) { - assert(id < tokens.size()); - const auto &tok = tokens[id]; - return std::string(tok.first, tok.second); - } - return std::string(s_, n_); + std::string_view token(size_t id = 0) const { + if (tokens.empty()) { return sv_; } + assert(id < tokens.size()); + return tokens[id]; + } + + // Token conversion + std::string token_to_string(size_t id = 0) const { + return std::string(token(id)); + } + + template T token_to_number() const { + auto sv = token(); + T n = 0; + std::from_chars(sv.data(), sv.data() + sv.size(), n); + return n; } // Transform the semantic value vector to another vector @@ -558,33 +463,33 @@ struct SemanticValues : protected std::vector { std::vector r; end = (std::min)(end, size()); for (size_t i = beg; i < end; i++) { - r.emplace_back(any_cast((*this)[i])); + r.emplace_back(std::any_cast((*this)[i])); } return r; } - using std::vector::iterator; - using std::vector::const_iterator; - using std::vector::size; - using std::vector::empty; - using std::vector::assign; - using std::vector::begin; - using std::vector::end; - using std::vector::rbegin; - using std::vector::rend; - using std::vector::operator[]; - using std::vector::at; - using std::vector::resize; - using std::vector::front; - using std::vector::back; - using std::vector::push_back; - using std::vector::pop_back; - using std::vector::insert; - using std::vector::erase; - using std::vector::clear; - using std::vector::swap; - using std::vector::emplace; - using std::vector::emplace_back; + using std::vector::iterator; + using std::vector::const_iterator; + using std::vector::size; + using std::vector::empty; + using std::vector::assign; + using std::vector::begin; + using std::vector::end; + using std::vector::rbegin; + using std::vector::rend; + using std::vector::operator[]; + using std::vector::at; + using std::vector::resize; + using std::vector::front; + using std::vector::back; + using std::vector::push_back; + using std::vector::pop_back; + using std::vector::insert; + using std::vector::erase; + using std::vector::clear; + using std::vector::swap; + using std::vector::emplace; + using std::vector::emplace_back; private: friend class Context; @@ -593,8 +498,7 @@ private: friend class Holder; friend class PrecedenceClimbing; - const char *s_ = nullptr; - size_t n_ = 0; + std::string_view sv_; size_t choice_count_ = 0; size_t choice_ = 0; std::string name_; @@ -603,170 +507,54 @@ private: /* * Semantic action */ -template ::value, - std::nullptr_t>::type = nullptr, - typename... Args> -any call(F fn, Args &&... args) { - fn(std::forward(args)...); - return any(); -} - -template ::type, any>::value, - std::nullptr_t>::type = nullptr, - typename... Args> -any call(F fn, Args &&... args) { - return fn(std::forward(args)...); -} - -template ::value && - !std::is_same::type, any>::value, - std::nullptr_t>::type = nullptr, - typename... Args> -any call(F fn, Args &&... args) { - return any(fn(std::forward(args)...)); +template std::any call(F fn, Args &&... args) { + using R = decltype(fn(std::forward(args)...)); + if constexpr (std::is_void::value) { + fn(std::forward(args)...); + return std::any(); + } else if constexpr (std::is_same::type, + std::any>::value) { + return fn(std::forward(args)...); + } else { + return std::any(fn(std::forward(args)...)); + } } +template +struct argument_count : argument_count {}; +template +struct argument_count + : std::integral_constant {}; +template +struct argument_count + : std::integral_constant {}; +template +struct argument_count + : std::integral_constant {}; + class Action { public: Action() = default; - Action(const Action &rhs) = default; - - template ::value && - !std::is_same::value, - std::nullptr_t>::type = nullptr> - Action(F fn) : fn_(make_adaptor(fn, &F::operator())) {} - - template ::value, - std::nullptr_t>::type = nullptr> - Action(F fn) : fn_(make_adaptor(fn, fn)) {} - - template ::value, - std::nullptr_t>::type = nullptr> - Action(F /*fn*/) {} - - template ::value && - !std::is_same::value, - std::nullptr_t>::type = nullptr> - void operator=(F fn) { - fn_ = make_adaptor(fn, &F::operator()); - } - - template ::value, - std::nullptr_t>::type = nullptr> - void operator=(F fn) { - fn_ = make_adaptor(fn, fn); - } - - template ::value, - std::nullptr_t>::type = nullptr> - void operator=(F /*fn*/) {} - + Action(Action &&rhs) = default; + template Action(F fn) : fn_(make_adaptor(fn)) {} + template void operator=(F fn) { fn_ = make_adaptor(fn); } Action &operator=(const Action &rhs) = default; operator bool() const { return bool(fn_); } - any operator()(SemanticValues &sv, any &dt) const { return fn_(sv, dt); } + std::any operator()(SemanticValues &vs, std::any &dt) const { + return fn_(vs, dt); + } private: - template struct TypeAdaptor_sv { - TypeAdaptor_sv(std::function fn) : fn_(fn) {} - any operator()(SemanticValues &sv, any & /*dt*/) { - return call(fn_, sv); - } - std::function fn_; - }; + using Fty = std::function; - template struct TypeAdaptor_csv { - TypeAdaptor_csv(std::function fn) : fn_(fn) {} - any operator()(SemanticValues &sv, any & /*dt*/) { - return call(fn_, sv); + template Fty make_adaptor(F fn) { + if constexpr (argument_count::value == 1) { + return [fn](auto &vs, auto & /*dt*/) { return call(fn, vs); }; + } else { + return [fn](auto &vs, auto &dt) { return call(fn, vs, dt); }; } - std::function fn_; - }; - - template struct TypeAdaptor_sv_dt { - TypeAdaptor_sv_dt(std::function fn) - : fn_(fn) {} - any operator()(SemanticValues &sv, any &dt) { return call(fn_, sv, dt); } - std::function fn_; - }; - - template struct TypeAdaptor_csv_dt { - TypeAdaptor_csv_dt(std::function fn) - : fn_(fn) {} - any operator()(SemanticValues &sv, any &dt) { return call(fn_, sv, dt); } - std::function fn_; - }; - - typedef std::function Fty; - - template - Fty make_adaptor(F fn, R (F::*)(SemanticValues &sv) const) { - return TypeAdaptor_sv(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(const SemanticValues &sv) const) { - return TypeAdaptor_csv(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(SemanticValues &sv)) { - return TypeAdaptor_sv(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(const SemanticValues &sv)) { - return TypeAdaptor_csv(fn); - } - - template - Fty make_adaptor(F fn, R (*)(SemanticValues &sv)) { - return TypeAdaptor_sv(fn); - } - - template - Fty make_adaptor(F fn, R (*)(const SemanticValues &sv)) { - return TypeAdaptor_csv(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(SemanticValues &sv, any &dt) const) { - return TypeAdaptor_sv_dt(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(const SemanticValues &sv, any &dt) const) { - return TypeAdaptor_csv_dt(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(SemanticValues &sv, any &dt)) { - return TypeAdaptor_sv_dt(fn); - } - - template - Fty make_adaptor(F fn, R (F::*)(const SemanticValues &sv, any &dt)) { - return TypeAdaptor_csv_dt(fn); - } - - template - Fty make_adaptor(F fn, R (*)(SemanticValues &sv, any &dt)) { - return TypeAdaptor_sv_dt(fn); - } - - template - Fty make_adaptor(F fn, R (*)(const SemanticValues &sv, any &dt)) { - return TypeAdaptor_csv_dt(fn); } Fty fn_; @@ -780,7 +568,7 @@ private: struct parse_error { parse_error() = default; parse_error(const char *s) : s_(s) {} - const char *what() const { return s_.empty() ? nullptr : s_.c_str(); } + const char *what() const { return s_.empty() ? nullptr : s_.data(); } private: std::string s_; @@ -800,15 +588,13 @@ class Context; class Ope; class Definition; -typedef std::function - TracerEnter; +using TracerEnter = std::function; -typedef std::function - TracerLeave; +using TracerLeave = std::function; class Context { public: @@ -834,7 +620,7 @@ public: std::shared_ptr wordOpe; - std::vector> capture_scope_stack; + std::vector> capture_scope_stack; size_t capture_scope_stack_size = 0; const size_t def_count; @@ -842,7 +628,8 @@ public: std::vector cache_registered; std::vector cache_success; - std::map, std::tuple> cache_values; + std::map, std::tuple> + cache_values; TracerEnter tracer_enter; TracerLeave tracer_leave; @@ -875,7 +662,8 @@ public: Context operator=(const Context &) = delete; template - void packrat(const char *a_s, size_t def_id, size_t &len, any &val, T fn) { + void packrat(const char *a_s, size_t def_id, size_t &len, std::any &val, + T fn) { if (!enablePackratParsing) { fn(val); return; @@ -886,7 +674,7 @@ public: if (cache_registered[idx]) { if (cache_success[idx]) { - auto key = std::make_pair(col, def_id); + auto key = std::pair(col, def_id); std::tie(len, val) = cache_values[key]; return; } else { @@ -898,8 +686,8 @@ public: cache_registered[idx] = true; cache_success[idx] = success(len); if (success(len)) { - auto key = std::make_pair(col, def_id); - cache_values[key] = std::make_pair(len, val); + auto key = std::pair(col, def_id); + cache_values[key] = std::pair(len, val); } return; } @@ -910,23 +698,22 @@ public: if (value_stack_size == value_stack.size()) { value_stack.emplace_back(std::make_shared()); } else { - auto &sv = *value_stack[value_stack_size]; - if (!sv.empty()) { - sv.clear(); - if (!sv.tags.empty()) { sv.tags.clear(); } + auto &vs = *value_stack[value_stack_size]; + if (!vs.empty()) { + vs.clear(); + if (!vs.tags.empty()) { vs.tags.clear(); } } - sv.s_ = nullptr; - sv.n_ = 0; - sv.choice_count_ = 0; - sv.choice_ = 0; - if (!sv.tokens.empty()) { sv.tokens.clear(); } + vs.sv_ = std::string_view(); + vs.choice_count_ = 0; + vs.choice_ = 0; + if (!vs.tokens.empty()) { vs.tokens.clear(); } } - auto &sv = *value_stack[value_stack_size++]; - sv.path = path; - sv.ss = s; - sv.source_line_index = &source_line_index; - return sv; + auto &vs = *value_stack[value_stack_size++]; + vs.path = path; + vs.ss = s; + vs.source_line_index = &source_line_index; + return vs; } void pop() { value_stack_size--; } @@ -944,7 +731,8 @@ public: void push_capture_scope() { assert(capture_scope_stack_size <= capture_scope_stack.size()); if (capture_scope_stack_size == capture_scope_stack.size()) { - capture_scope_stack.emplace_back(std::map()); + capture_scope_stack.emplace_back( + std::map()); } else { auto &cs = capture_scope_stack[capture_scope_stack_size]; if (!cs.empty()) { cs.clear(); } @@ -968,9 +756,9 @@ public: } void trace_enter(const char *name, const char *a_s, size_t n, - SemanticValues &sv, any &dt) const; + SemanticValues &vs, std::any &dt) const; void trace_leave(const char *name, const char *a_s, size_t n, - SemanticValues &sv, any &dt, size_t len) const; + SemanticValues &vs, std::any &dt, size_t len) const; bool is_traceable(const Ope &ope) const; mutable size_t next_trace_id = 0; @@ -985,10 +773,10 @@ public: struct Visitor; virtual ~Ope() {} - size_t parse(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const; - virtual size_t parse_core(const char *s, size_t n, SemanticValues &sv, - Context &c, any &dt) const = 0; + size_t parse(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const; + virtual size_t parse_core(const char *s, size_t n, SemanticValues &vs, + Context &c, std::any &dt) const = 0; virtual void accept(Visitor &v) = 0; }; @@ -1000,10 +788,10 @@ public: Sequence(const std::vector> &opes) : opes_(opes) {} Sequence(std::vector> &&opes) : opes_(opes) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { auto &chldsv = c.push(); - auto pop_se = make_scope_exit([&]() { c.pop(); }); + auto pop_se = scope_exit([&]() { c.pop(); }); size_t i = 0; for (const auto &ope : opes_) { const auto &rule = *ope; @@ -1013,19 +801,18 @@ public: } if (!chldsv.empty()) { for (size_t j = 0; j < chldsv.size(); j++) { - sv.emplace_back(std::move(chldsv[j])); + vs.emplace_back(std::move(chldsv[j])); } } if (!chldsv.tags.empty()) { for (size_t j = 0; j < chldsv.tags.size(); j++) { - sv.tags.emplace_back(std::move(chldsv.tags[j])); + vs.tags.emplace_back(std::move(chldsv.tags[j])); } } - sv.s_ = chldsv.c_str(); - sv.n_ = chldsv.length(); + vs.sv_ = chldsv.sv_; if (!chldsv.tokens.empty()) { for (size_t j = 0; j < chldsv.tokens.size(); j++) { - sv.tokens.emplace_back(std::move(chldsv.tokens[j])); + vs.tokens.emplace_back(std::move(chldsv.tokens[j])); } } return i; @@ -1045,13 +832,13 @@ public: : opes_(opes) {} PrioritizedChoice(std::vector> &&opes) : opes_(opes) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { size_t id = 0; for (const auto &ope : opes_) { auto &chldsv = c.push(); c.push_capture_scope(); - auto se = make_scope_exit([&]() { + auto se = scope_exit([&]() { c.pop(); c.pop_capture_scope(); }); @@ -1059,21 +846,20 @@ public: if (success(len)) { if (!chldsv.empty()) { for (size_t i = 0; i < chldsv.size(); i++) { - sv.emplace_back(std::move(chldsv[i])); + vs.emplace_back(std::move(chldsv[i])); } } if (!chldsv.tags.empty()) { for (size_t i = 0; i < chldsv.tags.size(); i++) { - sv.tags.emplace_back(std::move(chldsv.tags[i])); + vs.tags.emplace_back(std::move(chldsv.tags[i])); } } - sv.s_ = chldsv.c_str(); - sv.n_ = chldsv.length(); - sv.choice_count_ = opes_.size(); - sv.choice_ = id; + vs.sv_ = chldsv.sv_; + vs.choice_count_ = opes_.size(); + vs.choice_ = id; if (!chldsv.tokens.empty()) { for (size_t i = 0; i < chldsv.tokens.size(); i++) { - sv.tokens.emplace_back(std::move(chldsv.tokens[i])); + vs.tokens.emplace_back(std::move(chldsv.tokens[i])); } } @@ -1097,15 +883,15 @@ public: Repetition(const std::shared_ptr &ope, size_t min, size_t max) : ope_(ope), min_(min), max_(max) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { size_t count = 0; size_t i = 0; while (count < min_) { c.push_capture_scope(); - auto se = make_scope_exit([&]() { c.pop_capture_scope(); }); + auto se = scope_exit([&]() { c.pop_capture_scope(); }); const auto &rule = *ope_; - auto len = rule.parse(s + i, n - i, sv, c, dt); + auto len = rule.parse(s + i, n - i, vs, c, dt); if (success(len)) { c.shift_capture_values(); } else { @@ -1118,21 +904,21 @@ public: auto save_error_pos = c.error_pos; while (n - i > 0 && count < max_) { c.push_capture_scope(); - auto se = make_scope_exit([&]() { c.pop_capture_scope(); }); - auto save_sv_size = sv.size(); - auto save_tok_size = sv.tokens.size(); + auto se = scope_exit([&]() { c.pop_capture_scope(); }); + auto save_sv_size = vs.size(); + auto save_tok_size = vs.tokens.size(); const auto &rule = *ope_; - auto len = rule.parse(s + i, n - i, sv, c, dt); + auto len = rule.parse(s + i, n - i, vs, c, dt); if (success(len)) { c.shift_capture_values(); } else { - if (sv.size() != save_sv_size) { - sv.erase(sv.begin() + static_cast(save_sv_size)); - sv.tags.erase(sv.tags.begin() + + if (vs.size() != save_sv_size) { + vs.erase(vs.begin() + static_cast(save_sv_size)); + vs.tags.erase(vs.tags.begin() + static_cast(save_sv_size)); } - if (sv.tokens.size() != save_tok_size) { - sv.tokens.erase(sv.tokens.begin() + + if (vs.tokens.size() != save_tok_size) { + vs.tokens.erase(vs.tokens.begin() + static_cast(save_tok_size)); } c.error_pos = save_error_pos; @@ -1173,11 +959,11 @@ class AndPredicate : public Ope { public: AndPredicate(const std::shared_ptr &ope) : ope_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues & /*sv*/, - Context &c, any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/, + Context &c, std::any &dt) const override { auto &chldsv = c.push(); c.push_capture_scope(); - auto se = make_scope_exit([&]() { + auto se = scope_exit([&]() { c.pop(); c.pop_capture_scope(); }); @@ -1199,12 +985,12 @@ class NotPredicate : public Ope { public: NotPredicate(const std::shared_ptr &ope) : ope_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues & /*sv*/, - Context &c, any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/, + Context &c, std::any &dt) const override { auto save_error_pos = c.error_pos; auto &chldsv = c.push(); c.push_capture_scope(); - auto se = make_scope_exit([&]() { + auto se = scope_exit([&]() { c.pop(); c.pop_capture_scope(); }); @@ -1227,8 +1013,8 @@ class Dictionary : public Ope, public std::enable_shared_from_this { public: Dictionary(const std::vector &v) : trie_(v) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override; + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override; void accept(Visitor &v) override; @@ -1244,8 +1030,8 @@ public: LiteralString(const std::string &s, bool ignore_case) : lit_(s), ignore_case_(ignore_case), is_word_(false) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override; + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override; void accept(Visitor &v) override; @@ -1259,17 +1045,17 @@ class CharacterClass : public Ope, public std::enable_shared_from_this { public: CharacterClass(const std::string &s, bool negated) : negated_(negated) { - auto chars = decode(s.c_str(), s.length()); + auto chars = decode(s.data(), s.length()); auto i = 0u; while (i < chars.size()) { if (i + 2 < chars.size() && chars[i + 1] == '-') { auto cp1 = chars[i]; auto cp2 = chars[i + 2]; - ranges_.emplace_back(std::make_pair(cp1, cp2)); + ranges_.emplace_back(std::pair(cp1, cp2)); i += 3; } else { auto cp = chars[i]; - ranges_.emplace_back(std::make_pair(cp, cp)); + ranges_.emplace_back(std::pair(cp, cp)); i += 1; } } @@ -1282,8 +1068,8 @@ public: assert(!ranges_.empty()); } - size_t parse_core(const char *s, size_t n, SemanticValues & /*sv*/, - Context &c, any & /*dt*/) const override { + size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/, + Context &c, std::any & /*dt*/) const override { if (n < 1) { c.set_error_pos(s); return static_cast(-1); @@ -1321,8 +1107,8 @@ class Character : public Ope, public std::enable_shared_from_this { public: Character(char ch) : ch_(ch) {} - size_t parse_core(const char *s, size_t n, SemanticValues & /*sv*/, - Context &c, any & /*dt*/) const override { + size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/, + Context &c, std::any & /*dt*/) const override { if (n < 1 || s[0] != ch_) { c.set_error_pos(s); return static_cast(-1); @@ -1338,8 +1124,8 @@ public: class AnyCharacter : public Ope, public std::enable_shared_from_this { public: - size_t parse_core(const char *s, size_t n, SemanticValues & /*sv*/, - Context &c, any & /*dt*/) const override { + size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/, + Context &c, std::any & /*dt*/) const override { auto len = codepoint_length(s, n); if (len < 1) { c.set_error_pos(s); @@ -1355,12 +1141,12 @@ class CaptureScope : public Ope { public: CaptureScope(const std::shared_ptr &ope) : ope_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { c.push_capture_scope(); - auto se = make_scope_exit([&]() { c.pop_capture_scope(); }); + auto se = scope_exit([&]() { c.pop_capture_scope(); }); const auto &rule = *ope_; - auto len = rule.parse(s, n, sv, c, dt); + auto len = rule.parse(s, n, vs, c, dt); return len; } @@ -1371,15 +1157,15 @@ public: class Capture : public Ope { public: - typedef std::function MatchAction; + using MatchAction = std::function; Capture(const std::shared_ptr &ope, MatchAction ma) : ope_(ope), match_action_(ma) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { const auto &rule = *ope_; - auto len = rule.parse(s, n, sv, c, dt); + auto len = rule.parse(s, n, vs, c, dt); if (success(len) && match_action_) { match_action_(s, len, c); } return len; } @@ -1394,8 +1180,8 @@ class TokenBoundary : public Ope { public: TokenBoundary(const std::shared_ptr &ope) : ope_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override; + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override; void accept(Visitor &v) override; @@ -1406,11 +1192,11 @@ class Ignore : public Ope { public: Ignore(const std::shared_ptr &ope) : ope_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues & /*sv*/, - Context &c, any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/, + Context &c, std::any &dt) const override { const auto &rule = *ope_; auto &chldsv = c.push(); - auto se = make_scope_exit([&]() { c.pop(); }); + auto se = scope_exit([&]() { c.pop(); }); return rule.parse(s, n, chldsv, c, dt); } @@ -1419,20 +1205,20 @@ public: std::shared_ptr ope_; }; -typedef std::function - Parser; +using Parser = std::function; class User : public Ope { public: User(Parser fn) : fn_(fn) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, - Context & /*c*/, any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, + Context & /*c*/, std::any &dt) const override { assert(fn_); - return fn_(s, n, sv, dt); + return fn_(s, n, vs, dt); } void accept(Visitor &v) override; - std::function + std::function fn_; }; @@ -1440,12 +1226,12 @@ class WeakHolder : public Ope { public: WeakHolder(const std::shared_ptr &ope) : weak_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { auto ope = weak_.lock(); assert(ope); const auto &rule = *ope; - return rule.parse(s, n, sv, c, dt); + return rule.parse(s, n, vs, c, dt); } void accept(Visitor &v) override; @@ -1457,12 +1243,12 @@ class Holder : public Ope { public: Holder(Definition *outer) : outer_(outer) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override; + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override; void accept(Visitor &v) override; - any reduce(SemanticValues &sv, any &dt) const; + std::any reduce(SemanticValues &vs, std::any &dt) const; const char *trace_name() const; @@ -1473,7 +1259,7 @@ public: friend class Definition; }; -typedef std::unordered_map Grammar; +using Grammar = std::unordered_map; class Reference : public Ope, public std::enable_shared_from_this { public: @@ -1482,8 +1268,8 @@ public: : grammar_(grammar), name_(name), s_(s), is_macro_(is_macro), args_(args), rule_(nullptr), iarg_(0) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override; + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override; void accept(Visitor &v) override; @@ -1504,13 +1290,13 @@ class Whitespace : public Ope { public: Whitespace(const std::shared_ptr &ope) : ope_(ope) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { if (c.in_whitespace) { return 0; } c.in_whitespace = true; - auto se = make_scope_exit([&]() { c.in_whitespace = false; }); + auto se = scope_exit([&]() { c.in_whitespace = false; }); const auto &rule = *ope_; - return rule.parse(s, n, sv, c, dt); + return rule.parse(s, n, vs, c, dt); } void accept(Visitor &v) override; @@ -1520,10 +1306,12 @@ public: class BackReference : public Ope { public: + BackReference(std::string &&name) : name_(name) {} + BackReference(const std::string &name) : name_(name) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override; + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override; void accept(Visitor &v) override; @@ -1532,16 +1320,16 @@ public: class PrecedenceClimbing : public Ope { public: - using BinOpeInfo = std::map>; + using BinOpeInfo = std::map>; PrecedenceClimbing(const std::shared_ptr &atom, const std::shared_ptr &binop, const BinOpeInfo &info, const Definition &rule) : atom_(atom), binop_(binop), info_(info), rule_(rule) {} - size_t parse_core(const char *s, size_t n, SemanticValues &sv, Context &c, - any &dt) const override { - return parse_expression(s, n, sv, c, dt, 0); + size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, + std::any &dt) const override { + return parse_expression(s, n, vs, c, dt, 0); } void accept(Visitor &v) override; @@ -1552,8 +1340,8 @@ public: const Definition &rule_; private: - size_t parse_expression(const char *s, size_t n, SemanticValues &sv, - Context &c, any &dt, size_t min_prec) const; + size_t parse_expression(const char *s, size_t n, SemanticValues &vs, + Context &c, std::any &dt, size_t min_prec) const; Definition &get_reference_for_binop(Context &c) const; }; @@ -1649,7 +1437,8 @@ inline std::shared_ptr ign(const std::shared_ptr &ope) { } inline std::shared_ptr -usr(std::function +usr(std::function fn) { return std::make_shared(fn); } @@ -1664,7 +1453,7 @@ inline std::shared_ptr wsp(const std::shared_ptr &ope) { return std::make_shared(std::make_shared(ope)); } -inline std::shared_ptr bkr(const std::string &name) { +inline std::shared_ptr bkr(std::string &&name) { return std::make_shared(name); } @@ -1680,68 +1469,61 @@ inline std::shared_ptr pre(const std::shared_ptr &atom, */ struct Ope::Visitor { virtual ~Visitor() {} - virtual void visit(Sequence & /*ope*/) {} - virtual void visit(PrioritizedChoice & /*ope*/) {} - virtual void visit(Repetition & /*ope*/) {} - virtual void visit(AndPredicate & /*ope*/) {} - virtual void visit(NotPredicate & /*ope*/) {} - virtual void visit(Dictionary & /*ope*/) {} - virtual void visit(LiteralString & /*ope*/) {} - virtual void visit(CharacterClass & /*ope*/) {} - virtual void visit(Character & /*ope*/) {} - virtual void visit(AnyCharacter & /*ope*/) {} - virtual void visit(CaptureScope & /*ope*/) {} - virtual void visit(Capture & /*ope*/) {} - virtual void visit(TokenBoundary & /*ope*/) {} - virtual void visit(Ignore & /*ope*/) {} - virtual void visit(User & /*ope*/) {} - virtual void visit(WeakHolder & /*ope*/) {} - virtual void visit(Holder & /*ope*/) {} - virtual void visit(Reference & /*ope*/) {} - virtual void visit(Whitespace & /*ope*/) {} - virtual void visit(BackReference & /*ope*/) {} - virtual void visit(PrecedenceClimbing & /*ope*/) {} + virtual void visit(Sequence &) {} + virtual void visit(PrioritizedChoice &) {} + virtual void visit(Repetition &) {} + virtual void visit(AndPredicate &) {} + virtual void visit(NotPredicate &) {} + virtual void visit(Dictionary &) {} + virtual void visit(LiteralString &) {} + virtual void visit(CharacterClass &) {} + virtual void visit(Character &) {} + virtual void visit(AnyCharacter &) {} + virtual void visit(CaptureScope &) {} + virtual void visit(Capture &) {} + virtual void visit(TokenBoundary &) {} + virtual void visit(Ignore &) {} + virtual void visit(User &) {} + virtual void visit(WeakHolder &) {} + virtual void visit(Holder &) {} + virtual void visit(Reference &) {} + virtual void visit(Whitespace &) {} + virtual void visit(BackReference &) {} + virtual void visit(PrecedenceClimbing &) {} }; struct IsReference : public Ope::Visitor { - using Ope::Visitor::visit; - void visit(Reference & /*ope*/) override { is_reference = true; } + void visit(Reference &) override { is_reference = true; } bool is_reference = false; }; struct TraceOpeName : public Ope::Visitor { - void visit(Sequence & /*ope*/) override { name = "Sequence"; } - void visit(PrioritizedChoice & /*ope*/) override { - name = "PrioritizedChoice"; - } - void visit(Repetition & /*ope*/) override { name = "Repetition"; } - void visit(AndPredicate & /*ope*/) override { name = "AndPredicate"; } - void visit(NotPredicate & /*ope*/) override { name = "NotPredicate"; } - void visit(Dictionary & /*ope*/) override { name = "Dictionary"; } - void visit(LiteralString & /*ope*/) override { name = "LiteralString"; } - void visit(CharacterClass & /*ope*/) override { name = "CharacterClass"; } - void visit(Character & /*ope*/) override { name = "Character"; } - void visit(AnyCharacter & /*ope*/) override { name = "AnyCharacter"; } - void visit(CaptureScope & /*ope*/) override { name = "CaptureScope"; } - void visit(Capture & /*ope*/) override { name = "Capture"; } - void visit(TokenBoundary & /*ope*/) override { name = "TokenBoundary"; } - void visit(Ignore & /*ope*/) override { name = "Ignore"; } - void visit(User & /*ope*/) override { name = "User"; } - void visit(WeakHolder & /*ope*/) override { name = "WeakHolder"; } + void visit(Sequence &) override { name = "Sequence"; } + void visit(PrioritizedChoice &) override { name = "PrioritizedChoice"; } + void visit(Repetition &) override { name = "Repetition"; } + void visit(AndPredicate &) override { name = "AndPredicate"; } + void visit(NotPredicate &) override { name = "NotPredicate"; } + void visit(Dictionary &) override { name = "Dictionary"; } + void visit(LiteralString &) override { name = "LiteralString"; } + void visit(CharacterClass &) override { name = "CharacterClass"; } + void visit(Character &) override { name = "Character"; } + void visit(AnyCharacter &) override { name = "AnyCharacter"; } + void visit(CaptureScope &) override { name = "CaptureScope"; } + void visit(Capture &) override { name = "Capture"; } + void visit(TokenBoundary &) override { name = "TokenBoundary"; } + void visit(Ignore &) override { name = "Ignore"; } + void visit(User &) override { name = "User"; } + void visit(WeakHolder &) override { name = "WeakHolder"; } void visit(Holder &ope) override { name = ope.trace_name(); } - void visit(Reference & /*ope*/) override { name = "Reference"; } - void visit(Whitespace & /*ope*/) override { name = "Whitespace"; } - void visit(BackReference & /*ope*/) override { name = "BackReference"; } - void visit(PrecedenceClimbing & /*ope*/) override { - name = "PrecedenceClimbing"; - } + void visit(Reference &) override { name = "Reference"; } + void visit(Whitespace &) override { name = "Whitespace"; } + void visit(BackReference &) override { name = "BackReference"; } + void visit(PrecedenceClimbing &) override { name = "PrecedenceClimbing"; } const char *name = nullptr; }; struct AssignIDToDefinition : public Ope::Visitor { - using Ope::Visitor::visit; - void visit(Sequence &ope) override { for (auto op : ope.opes_) { op->accept(*this); @@ -1769,8 +1551,6 @@ struct AssignIDToDefinition : public Ope::Visitor { }; struct IsLiteralToken : public Ope::Visitor { - using Ope::Visitor::visit; - void visit(PrioritizedChoice &ope) override { for (auto op : ope.opes_) { if (!IsLiteralToken::check(*op)) { return; } @@ -1778,8 +1558,8 @@ struct IsLiteralToken : public Ope::Visitor { result_ = true; } - void visit(Dictionary & /*ope*/) override { result_ = true; } - void visit(LiteralString & /*ope*/) override { result_ = true; } + void visit(Dictionary &) override { result_ = true; } + void visit(LiteralString &) override { result_ = true; } static bool check(Ope &ope) { IsLiteralToken vis; @@ -1792,8 +1572,6 @@ private: }; struct TokenChecker : public Ope::Visitor { - using Ope::Visitor::visit; - void visit(Sequence &ope) override { for (auto op : ope.opes_) { op->accept(*this); @@ -1807,7 +1585,7 @@ struct TokenChecker : public Ope::Visitor { void visit(Repetition &ope) override { ope.ope_->accept(*this); } void visit(CaptureScope &ope) override { ope.ope_->accept(*this); } void visit(Capture &ope) override { ope.ope_->accept(*this); } - void visit(TokenBoundary & /*ope*/) override { has_token_boundary_ = true; } + void visit(TokenBoundary &) override { has_token_boundary_ = true; } void visit(Ignore &ope) override { ope.ope_->accept(*this); } void visit(WeakHolder &ope) override; void visit(Reference &ope) override; @@ -1862,21 +1640,21 @@ struct DetectLeftRecursion : public Ope::Visitor { ope.ope_->accept(*this); done_ = false; } - void visit(Dictionary & /*ope*/) override { done_ = true; } + void visit(Dictionary &) override { done_ = true; } void visit(LiteralString &ope) override { done_ = !ope.lit_.empty(); } - void visit(CharacterClass & /*ope*/) override { done_ = true; } - void visit(Character & /*ope*/) override { done_ = true; } - void visit(AnyCharacter & /*ope*/) override { done_ = true; } + void visit(CharacterClass &) override { done_ = true; } + void visit(Character &) override { done_ = true; } + void visit(AnyCharacter &) override { done_ = true; } void visit(CaptureScope &ope) override { ope.ope_->accept(*this); } void visit(Capture &ope) override { ope.ope_->accept(*this); } void visit(TokenBoundary &ope) override { ope.ope_->accept(*this); } void visit(Ignore &ope) override { ope.ope_->accept(*this); } - void visit(User & /*ope*/) override { done_ = true; } + void visit(User &) override { done_ = true; } void visit(WeakHolder &ope) override { ope.weak_.lock()->accept(*this); } void visit(Holder &ope) override { ope.ope_->accept(*this); } void visit(Reference &ope) override; void visit(Whitespace &ope) override { ope.ope_->accept(*this); } - void visit(BackReference & /*ope*/) override { done_ = true; } + void visit(BackReference &) override { done_ = true; } void visit(PrecedenceClimbing &ope) override { ope.atom_->accept(*this); } const char *error_s = nullptr; @@ -1888,13 +1666,11 @@ private: }; struct HasEmptyElement : public Ope::Visitor { - using Ope::Visitor::visit; - HasEmptyElement(std::list> &refs) : refs_(refs) {} void visit(Sequence &ope) override { - bool save_is_empty = false; + auto save_is_empty = false; const char *save_error_s = nullptr; std::string save_error_name; for (auto op : ope.opes_) { @@ -1923,8 +1699,8 @@ struct HasEmptyElement : public Ope::Visitor { ope.ope_->accept(*this); } } - void visit(AndPredicate & /*ope*/) override { set_error(); } - void visit(NotPredicate & /*ope*/) override { set_error(); } + void visit(AndPredicate &) override { set_error(); } + void visit(NotPredicate &) override { set_error(); } void visit(LiteralString &ope) override { if (ope.lit_.empty()) { set_error(); } } @@ -1952,8 +1728,6 @@ private: }; struct DetectInfiniteLoop : public Ope::Visitor { - using Ope::Visitor::visit; - DetectInfiniteLoop(const char *s, const std::string &name) { refs_.emplace_back(s, name); } @@ -2004,8 +1778,6 @@ private: }; struct ReferenceChecker : public Ope::Visitor { - using Ope::Visitor::visit; - ReferenceChecker(const Grammar &grammar, const std::vector ¶ms) : grammar_(grammar), params_(params) {} @@ -2042,8 +1814,6 @@ private: }; struct LinkReferences : public Ope::Visitor { - using Ope::Visitor::visit; - LinkReferences(Grammar &grammar, const std::vector ¶ms) : grammar_(grammar), params_(params) {} @@ -2076,8 +1846,6 @@ private: }; struct FindReference : public Ope::Visitor { - using Ope::Visitor::visit; - FindReference(const std::vector> &args, const std::vector ¶ms) : args_(args), params_(params) {} @@ -2155,9 +1923,7 @@ private: }; struct IsPrioritizedChoice : public Ope::Visitor { - using Ope::Visitor::visit; - - void visit(PrioritizedChoice & /*ope*/) override { result_ = true; } + void visit(PrioritizedChoice &) override { result_ = true; } static bool check(Ope &ope) { IsPrioritizedChoice vis; @@ -2209,9 +1975,9 @@ public: } Result parse(const char *s, size_t n, const char *path = nullptr) const { - SemanticValues sv; - any dt; - return parse_core(s, n, sv, dt, path); + SemanticValues vs; + std::any dt; + return parse_core(s, n, vs, dt, path); } Result parse(const char *s, const char *path = nullptr) const { @@ -2219,13 +1985,13 @@ public: return parse(s, n, path); } - Result parse(const char *s, size_t n, any &dt, + Result parse(const char *s, size_t n, std::any &dt, const char *path = nullptr) const { - SemanticValues sv; - return parse_core(s, n, sv, dt, path); + SemanticValues vs; + return parse_core(s, n, vs, dt, path); } - Result parse(const char *s, any &dt, const char *path = nullptr) const { + Result parse(const char *s, std::any &dt, const char *path = nullptr) const { auto n = strlen(s); return parse(s, n, dt, path); } @@ -2233,11 +1999,11 @@ public: template Result parse_and_get_value(const char *s, size_t n, T &val, const char *path = nullptr) const { - SemanticValues sv; - any dt; - auto r = parse_core(s, n, sv, dt, path); - if (r.ret && !sv.empty() && sv.front().has_value()) { - val = any_cast(sv[0]); + SemanticValues vs; + std::any dt; + auto r = parse_core(s, n, vs, dt, path); + if (r.ret && !vs.empty() && vs.front().has_value()) { + val = std::any_cast(vs[0]); } return r; } @@ -2250,27 +2016,24 @@ public: } template - Result parse_and_get_value(const char *s, size_t n, any &dt, T &val, + Result parse_and_get_value(const char *s, size_t n, std::any &dt, T &val, const char *path = nullptr) const { - SemanticValues sv; - auto r = parse_core(s, n, sv, dt, path); - if (r.ret && !sv.empty() && sv.front().has_value()) { - val = any_cast(sv[0]); + SemanticValues vs; + auto r = parse_core(s, n, vs, dt, path); + if (r.ret && !vs.empty() && vs.front().has_value()) { + val = std::any_cast(vs[0]); } return r; } template - Result parse_and_get_value(const char *s, any &dt, T &val, + Result parse_and_get_value(const char *s, std::any &dt, T &val, const char *path = nullptr) const { auto n = strlen(s); return parse_and_get_value(s, n, dt, val, path); } - Action operator=(Action a) { - action = a; - return a; - } + void operator=(Action a) { action = a; } template Definition &operator,(T fn) { operator=(fn); @@ -2298,9 +2061,9 @@ public: size_t id = 0; Action action; - std::function enter; - std::function + std::function enter; + std::function leave; std::function error_message; bool ignoreSemanticValue = false; @@ -2330,7 +2093,7 @@ private: }); } - Result parse_core(const char *s, size_t n, SemanticValues &sv, any &dt, + Result parse_core(const char *s, size_t n, SemanticValues &vs, std::any &dt, const char *path) const { initialize_definition_ids(); @@ -2340,7 +2103,7 @@ private: Context cxt(path, s, n, definition_ids_.size(), whitespaceOpe, wordOpe, enablePackratParsing, tracer_enter, tracer_leave); - auto len = ope->parse(s, n, sv, cxt, dt); + auto len = ope->parse(s, n, vs, cxt, dt); return Result{success(len), len, cxt.error_pos, cxt.message_pos, cxt.message}; } @@ -2357,8 +2120,8 @@ private: * Implementations */ -inline size_t parse_literal(const char *s, size_t n, SemanticValues &sv, - Context &c, any &dt, const std::string &lit, +inline size_t parse_literal(const char *s, size_t n, SemanticValues &vs, + Context &c, std::any &dt, const std::string &lit, std::once_flag &init_is_word, bool &is_word, bool ignore_case) { size_t i = 0; @@ -2374,7 +2137,7 @@ inline size_t parse_literal(const char *s, size_t n, SemanticValues &sv, static Context dummy_c(nullptr, c.s, c.l, 0, nullptr, nullptr, false, nullptr, nullptr); static SemanticValues dummy_sv; - static any dummy_dt; + static std::any dummy_dt; std::call_once(init_is_word, [&]() { if (c.wordOpe) { @@ -2394,7 +2157,7 @@ inline size_t parse_literal(const char *s, size_t n, SemanticValues &sv, // Skip whiltespace if (!c.in_token_boundary_count) { if (c.whitespaceOpe) { - auto len = c.whitespaceOpe->parse(s + i, n - i, sv, c, dt); + auto len = c.whitespaceOpe->parse(s + i, n - i, vs, c, dt); if (fail(len)) { return static_cast(-1); } i += len; } @@ -2404,15 +2167,15 @@ inline size_t parse_literal(const char *s, size_t n, SemanticValues &sv, } inline void Context::trace_enter(const char *name, const char *a_s, size_t n, - SemanticValues &sv, any &dt) const { + SemanticValues &vs, std::any &dt) const { trace_ids.push_back(next_trace_id++); - tracer_enter(name, a_s, n, sv, *this, dt); + tracer_enter(name, a_s, n, vs, *this, dt); } inline void Context::trace_leave(const char *name, const char *a_s, size_t n, - SemanticValues &sv, any &dt, + SemanticValues &vs, std::any &dt, size_t len) const { - tracer_leave(name, a_s, n, sv, *this, dt, len); + tracer_leave(name, a_s, n, vs, *this, dt, len); trace_ids.pop_back(); } @@ -2425,22 +2188,22 @@ inline bool Context::is_traceable(const Ope &ope) const { return false; } -inline size_t Ope::parse(const char *s, size_t n, SemanticValues &sv, - Context &c, any &dt) const { +inline size_t Ope::parse(const char *s, size_t n, SemanticValues &vs, + Context &c, std::any &dt) const { if (c.is_traceable(*this)) { TraceOpeName vis; const_cast(*this).accept(vis); - c.trace_enter(vis.name, s, n, sv, dt); - auto len = parse_core(s, n, sv, c, dt); - c.trace_leave(vis.name, s, n, sv, dt, len); + c.trace_enter(vis.name, s, n, vs, dt); + auto len = parse_core(s, n, vs, c, dt); + c.trace_leave(vis.name, s, n, vs, dt, len); return len; } - return parse_core(s, n, sv, c, dt); + return parse_core(s, n, vs, c, dt); } inline size_t Dictionary::parse_core(const char *s, size_t n, - SemanticValues & /*sv*/, Context &c, - any & /*dt*/) const { + SemanticValues & /*vs*/, Context &c, + std::any & /*dt*/) const { auto len = trie_.match(s, n); if (len > 0) { return len; } c.set_error_pos(s); @@ -2448,28 +2211,28 @@ inline size_t Dictionary::parse_core(const char *s, size_t n, } inline size_t LiteralString::parse_core(const char *s, size_t n, - SemanticValues &sv, Context &c, - any &dt) const { - return parse_literal(s, n, sv, c, dt, lit_, init_is_word_, is_word_, + SemanticValues &vs, Context &c, + std::any &dt) const { + return parse_literal(s, n, vs, c, dt, lit_, init_is_word_, is_word_, ignore_case_); } inline size_t TokenBoundary::parse_core(const char *s, size_t n, - SemanticValues &sv, Context &c, - any &dt) const { + SemanticValues &vs, Context &c, + std::any &dt) const { size_t len; { c.in_token_boundary_count++; - auto se = make_scope_exit([&]() { c.in_token_boundary_count--; }); - len = ope_->parse(s, n, sv, c, dt); + auto se = scope_exit([&]() { c.in_token_boundary_count--; }); + len = ope_->parse(s, n, vs, c, dt); } if (success(len)) { - sv.tokens.emplace_back(std::make_pair(s, len)); + vs.tokens.emplace_back(std::string_view(s, len)); if (!c.in_token_boundary_count) { if (c.whitespaceOpe) { - auto l = c.whitespaceOpe->parse(s + len, n - len, sv, c, dt); + auto l = c.whitespaceOpe->parse(s + len, n - len, vs, c, dt); if (fail(l)) { return static_cast(-1); } len += l; } @@ -2478,8 +2241,8 @@ inline size_t TokenBoundary::parse_core(const char *s, size_t n, return len; } -inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &sv, - Context &c, any &dt) const { +inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs, + Context &c, std::any &dt) const { if (!ope_) { throw std::logic_error("Uninitialized definition ope was used..."); } @@ -2487,20 +2250,19 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &sv, // Macro reference if (outer_->is_macro) { c.rule_stack.push_back(outer_); - auto len = ope_->parse(s, n, sv, c, dt); + auto len = ope_->parse(s, n, vs, c, dt); c.rule_stack.pop_back(); return len; } size_t len; - any val; + std::any val; - c.packrat(s, outer_->id, len, val, [&](any &a_val) { + c.packrat(s, outer_->id, len, val, [&](std::any &a_val) { if (outer_->enter) { outer_->enter(s, n, dt); } - auto se2 = make_scope_exit([&]() { + auto se2 = scope_exit([&]() { c.pop(); - if (outer_->leave) { outer_->leave(s, n, len, a_val, dt); } }); @@ -2512,8 +2274,7 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &sv, // Invoke action if (success(len)) { - chldsv.s_ = s; - chldsv.n_ = len; + chldsv.sv_ = std::string_view(s, len); chldsv.name_ = outer_->name; if (!IsPrioritizedChoice::check(*ope_)) { @@ -2537,8 +2298,8 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &sv, if (success(len)) { if (!outer_->ignoreSemanticValue) { - sv.emplace_back(std::move(val)); - sv.tags.emplace_back(str2tag(outer_->name.c_str())); + vs.emplace_back(std::move(val)); + vs.tags.emplace_back(str2tag(outer_->name)); } } else { if (outer_->error_message) { @@ -2552,23 +2313,23 @@ inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &sv, return len; } -inline any Holder::reduce(SemanticValues &sv, any &dt) const { +inline std::any Holder::reduce(SemanticValues &vs, std::any &dt) const { if (outer_->action && !outer_->disable_action) { - return outer_->action(sv, dt); - } else if (sv.empty()) { - return any(); + return outer_->action(vs, dt); + } else if (vs.empty()) { + return std::any(); } else { - return std::move(sv.front()); + return std::move(vs.front()); } } inline const char *Holder::trace_name() const { if (trace_name_.empty()) { trace_name_ = "[" + outer_->name + "]"; } - return trace_name_.c_str(); + return trace_name_.data(); } -inline size_t Reference::parse_core(const char *s, size_t n, SemanticValues &sv, - Context &c, any &dt) const { +inline size_t Reference::parse_core(const char *s, size_t n, SemanticValues &vs, + Context &c, std::any &dt) const { if (rule_) { // Reference rule if (rule_->is_macro) { @@ -2583,20 +2344,20 @@ inline size_t Reference::parse_core(const char *s, size_t n, SemanticValues &sv, } c.push_args(std::move(args)); - auto se = make_scope_exit([&]() { c.pop_args(); }); + auto se = scope_exit([&]() { c.pop_args(); }); auto ope = get_core_operator(); - return ope->parse(s, n, sv, c, dt); + return ope->parse(s, n, vs, c, dt); } else { // Definition c.push_args(std::vector>()); - auto se = make_scope_exit([&]() { c.pop_args(); }); + auto se = scope_exit([&]() { c.pop_args(); }); auto ope = get_core_operator(); - return ope->parse(s, n, sv, c, dt); + return ope->parse(s, n, vs, c, dt); } } else { // Reference parameter in macro const auto &args = c.top_args(); - return args[iarg_]->parse(s, n, sv, c, dt); + return args[iarg_]->parse(s, n, vs, c, dt); } } @@ -2605,8 +2366,8 @@ inline std::shared_ptr Reference::get_core_operator() const { } inline size_t BackReference::parse_core(const char *s, size_t n, - SemanticValues &sv, Context &c, - any &dt) const { + SemanticValues &vs, Context &c, + std::any &dt) const { auto size = static_cast(c.capture_scope_stack_size); for (auto i = size - 1; i >= 0; i--) { auto index = static_cast(i); @@ -2615,7 +2376,7 @@ inline size_t BackReference::parse_core(const char *s, size_t n, const auto &lit = cs.at(name_); std::once_flag init_is_word; auto is_word = false; - return parse_literal(s, n, sv, c, dt, lit, init_is_word, is_word, false); + return parse_literal(s, n, vs, c, dt, lit, init_is_word, is_word, false); } } throw std::runtime_error("Invalid back reference..."); @@ -2635,33 +2396,33 @@ PrecedenceClimbing::get_reference_for_binop(Context &c) const { } inline size_t PrecedenceClimbing::parse_expression(const char *s, size_t n, - SemanticValues &sv, - Context &c, any &dt, + SemanticValues &vs, + Context &c, std::any &dt, size_t min_prec) const { - auto len = atom_->parse(s, n, sv, c, dt); + auto len = atom_->parse(s, n, vs, c, dt); if (fail(len)) { return len; } std::string tok; auto &rule = get_reference_for_binop(c); - auto action = rule.action; + auto action = std::move(rule.action); - rule.action = [&](SemanticValues &sv2, any &dt2) -> any { - tok = sv2.token(); + rule.action = [&](SemanticValues &vs2, std::any &dt2) { + tok = vs2.token(); if (action) { - return action(sv2, dt2); - } else if (!sv2.empty()) { - return sv2[0]; + return action(vs2, dt2); + } else if (!vs2.empty()) { + return vs2[0]; } - return any(); + return std::any(); }; - auto action_se = make_scope_exit([&]() { rule.action = action; }); + auto action_se = scope_exit([&]() { rule.action = std::move(action); }); auto save_error_pos = c.error_pos; auto i = len; while (i < n) { - std::vector save_values(sv.begin(), sv.end()); - auto save_tokens = sv.tokens; + std::vector save_values(vs.begin(), vs.end()); + auto save_tokens = vs.tokens; auto chv = c.push(); auto chl = binop_->parse(s + i, n - i, chv, c, dt); @@ -2680,7 +2441,7 @@ inline size_t PrecedenceClimbing::parse_expression(const char *s, size_t n, if (level < min_prec) { break; } - sv.emplace_back(std::move(chv[0])); + vs.emplace_back(std::move(chv[0])); i += chl; auto next_min_prec = level; @@ -2691,25 +2452,24 @@ inline size_t PrecedenceClimbing::parse_expression(const char *s, size_t n, c.pop(); if (fail(chl)) { - sv.assign(save_values.begin(), save_values.end()); - sv.tokens = save_tokens; + vs.assign(save_values.begin(), save_values.end()); + vs.tokens = save_tokens; c.error_pos = save_error_pos; break; } - sv.emplace_back(std::move(chv[0])); + vs.emplace_back(std::move(chv[0])); i += chl; - any val; + std::any val; if (rule_.action) { - sv.s_ = s; - sv.n_ = i; - val = rule_.action(sv, dt); - } else if (!sv.empty()) { - val = sv[0]; + vs.sv_ = std::string_view(s, i); + val = rule_.action(vs, dt); + } else if (!vs.empty()) { + val = vs[0]; } - sv.clear(); - sv.emplace_back(std::move(val)); + vs.clear(); + vs.emplace_back(std::move(val)); } return i; @@ -2760,7 +2520,7 @@ inline void AssignIDToDefinition::visit(PrecedenceClimbing &ope) { ope.binop_->accept(*this); } -inline void TokenChecker::visit(WeakHolder & /*ope*/) { has_rule_ = true; } +inline void TokenChecker::visit(WeakHolder &) { has_rule_ = true; } inline void TokenChecker::visit(Reference &ope) { if (ope.is_macro_) { @@ -2873,8 +2633,8 @@ inline void FindReference::visit(Reference &ope) { * PEG parser generator *---------------------------------------------------------------------------*/ -typedef std::unordered_map> Rules; -typedef std::function Log; +using Rules = std::unordered_map>; +using Log = std::function; class ParserGenerator { public: @@ -2906,7 +2666,7 @@ private: struct Instruction { std::string type; - any data; + std::any data; }; struct Data { @@ -3061,25 +2821,25 @@ private: } void setup_actions() { - g["Definition"] = [&](const SemanticValues &sv, any &dt) { - Data &data = *any_cast(dt); + g["Definition"] = [&](const SemanticValues &vs, std::any &dt) { + Data &data = *std::any_cast(dt); - auto is_macro = sv.choice() == 0; - auto ignore = any_cast(sv[0]); - auto name = any_cast(sv[1]); + auto is_macro = vs.choice() == 0; + auto ignore = std::any_cast(vs[0]); + auto name = std::any_cast(vs[1]); std::vector params; std::shared_ptr ope; if (is_macro) { - params = any_cast>(sv[2]); - ope = any_cast>(sv[4]); - if (sv.size() == 6) { - data.instructions[name] = any_cast(sv[5]); + params = std::any_cast>(vs[2]); + ope = std::any_cast>(vs[4]); + if (vs.size() == 6) { + data.instructions[name] = std::any_cast(vs[5]); } } else { - ope = any_cast>(sv[3]); - if (sv.size() == 5) { - data.instructions[name] = any_cast(sv[4]); + ope = std::any_cast>(vs[3]); + if (vs.size() == 5) { + data.instructions[name] = std::any_cast(vs[4]); } } @@ -3088,27 +2848,27 @@ private: auto &rule = grammar[name]; rule <= ope; rule.name = name; - rule.s_ = sv.c_str(); + rule.s_ = vs.sv().data(); rule.ignoreSemanticValue = ignore; rule.is_macro = is_macro; rule.params = params; if (data.start.empty()) { data.start = name; - data.start_pos = sv.c_str(); + data.start_pos = vs.sv().data(); } } else { - data.duplicates.emplace_back(name, sv.c_str()); + data.duplicates.emplace_back(name, vs.sv().data()); } }; - g["Expression"] = [&](const SemanticValues &sv) { - if (sv.size() == 1) { - return any_cast>(sv[0]); + g["Expression"] = [&](const SemanticValues &vs) { + if (vs.size() == 1) { + return std::any_cast>(vs[0]); } else { std::vector> opes; - for (auto i = 0u; i < sv.size(); i++) { - opes.emplace_back(any_cast>(sv[i])); + for (auto i = 0u; i < vs.size(); i++) { + opes.emplace_back(std::any_cast>(vs[i])); } const std::shared_ptr ope = std::make_shared(opes); @@ -3116,27 +2876,27 @@ private: } }; - g["Sequence"] = [&](const SemanticValues &sv) { - if (sv.size() == 1) { - return any_cast>(sv[0]); + g["Sequence"] = [&](const SemanticValues &vs) { + if (vs.size() == 1) { + return std::any_cast>(vs[0]); } else { std::vector> opes; - for (const auto &x : sv) { - opes.emplace_back(any_cast>(x)); + for (const auto &x : vs) { + opes.emplace_back(std::any_cast>(x)); } const std::shared_ptr ope = std::make_shared(opes); return ope; } }; - g["Prefix"] = [&](const SemanticValues &sv) { + g["Prefix"] = [&](const SemanticValues &vs) { std::shared_ptr ope; - if (sv.size() == 1) { - ope = any_cast>(sv[0]); + if (vs.size() == 1) { + ope = std::any_cast>(vs[0]); } else { - assert(sv.size() == 2); - auto tok = any_cast(sv[0]); - ope = any_cast>(sv[1]); + assert(vs.size() == 2); + auto tok = std::any_cast(vs[0]); + ope = std::any_cast>(vs[1]); if (tok == '&') { ope = apd(ope); } else { // '!' @@ -3152,13 +2912,13 @@ private: std::pair range; }; - g["Suffix"] = [&](const SemanticValues &sv) { - auto ope = any_cast>(sv[0]); - if (sv.size() == 1) { + g["Suffix"] = [&](const SemanticValues &vs) { + auto ope = std::any_cast>(vs[0]); + if (vs.size() == 1) { return ope; } else { - assert(sv.size() == 2); - auto loop = any_cast(sv[1]); + assert(vs.size() == 2); + auto loop = std::any_cast(vs[1]); switch (loop.type) { case Loop::Type::opt: return opt(ope); case Loop::Type::zom: return zom(ope); @@ -3169,8 +2929,8 @@ private: } }; - g["Loop"] = [&](const SemanticValues &sv) { - switch (sv.choice()) { + g["Loop"] = [&](const SemanticValues &vs) { + switch (vs.choice()) { case 0: // Option return Loop{Loop::Type::opt, std::pair()}; case 1: // Zero or More @@ -3179,53 +2939,50 @@ private: return Loop{Loop::Type::oom, std::pair()}; default: // Regex-like repetition return Loop{Loop::Type::rep, - any_cast>(sv[0])}; + std::any_cast>(vs[0])}; } }; - g["RepetitionRange"] = [&](const SemanticValues &sv) { - switch (sv.choice()) { + g["RepetitionRange"] = [&](const SemanticValues &vs) { + switch (vs.choice()) { case 0: { // Number COMMA Number - auto min = any_cast(sv[0]); - auto max = any_cast(sv[1]); - return std::make_pair(min, max); + auto min = std::any_cast(vs[0]); + auto max = std::any_cast(vs[1]); + return std::pair(min, max); } case 1: // Number COMMA - return std::make_pair(any_cast(sv[0]), - std::numeric_limits::max()); + return std::pair(std::any_cast(vs[0]), + std::numeric_limits::max()); case 2: { // Number - auto n = any_cast(sv[0]); - return std::make_pair(n, n); + auto n = std::any_cast(vs[0]); + return std::pair(n, n); } default: // COMMA Number - return std::make_pair(std::numeric_limits::min(), - any_cast(sv[0])); + return std::pair(std::numeric_limits::min(), + std::any_cast(vs[0])); } }; - g["Number"] = [&](const SemanticValues &sv) { - std::stringstream ss(sv.str()); - size_t n; - ss >> n; - return n; + g["Number"] = [&](const SemanticValues &vs) { + return vs.token_to_number(); }; - g["Primary"] = [&](const SemanticValues &sv, any &dt) { - Data &data = *any_cast(dt); + g["Primary"] = [&](const SemanticValues &vs, std::any &dt) { + Data &data = *std::any_cast(dt); - switch (sv.choice()) { + switch (vs.choice()) { case 0: // Macro Reference case 1: { // Reference - auto is_macro = sv.choice() == 0; - auto ignore = any_cast(sv[0]); - const auto &ident = any_cast(sv[1]); + auto is_macro = vs.choice() == 0; + auto ignore = std::any_cast(vs[0]); + const auto &ident = std::any_cast(vs[1]); std::vector> args; if (is_macro) { - args = any_cast>>(sv[2]); + args = std::any_cast>>(vs[2]); } std::shared_ptr ope = - ref(*data.grammar, ident, sv.c_str(), is_macro, args); + ref(*data.grammar, ident, vs.sv().data(), is_macro, args); if (ignore) { return ign(ope); @@ -3234,110 +2991,111 @@ private: } } case 2: { // (Expression) - return any_cast>(sv[0]); + return std::any_cast>(vs[0]); } case 3: { // TokenBoundary - return tok(any_cast>(sv[0])); + return tok(std::any_cast>(vs[0])); } case 4: { // CaptureScope - return csc(any_cast>(sv[0])); + return csc(std::any_cast>(vs[0])); } case 5: { // Capture - const auto &name = any_cast(sv[0]); - auto ope = any_cast>(sv[1]); + const auto &name = std::any_cast(vs[0]); + auto ope = std::any_cast>(vs[1]); return cap(ope, [name](const char *a_s, size_t a_n, Context &c) { auto &cs = c.capture_scope_stack[c.capture_scope_stack_size - 1]; cs[name] = std::string(a_s, a_n); }); } default: { - return any_cast>(sv[0]); + return std::any_cast>(vs[0]); } } }; - g["IdentCont"] = [](const SemanticValues &sv) { - return std::string(sv.c_str(), sv.length()); + g["IdentCont"] = [](const SemanticValues &vs) { + return std::string(vs.sv().data(), vs.sv().length()); }; - g["Dictionary"] = [](const SemanticValues &sv) { - auto items = sv.transform(); + g["Dictionary"] = [](const SemanticValues &vs) { + auto items = vs.transform(); return dic(items); }; - g["Literal"] = [](const SemanticValues &sv) { - const auto &tok = sv.tokens.front(); - return lit(resolve_escape_sequence(tok.first, tok.second)); + g["Literal"] = [](const SemanticValues &vs) { + const auto &tok = vs.tokens.front(); + return lit(resolve_escape_sequence(tok.data(), tok.size())); }; - g["LiteralI"] = [](const SemanticValues &sv) { - const auto &tok = sv.tokens.front(); - return liti(resolve_escape_sequence(tok.first, tok.second)); + g["LiteralI"] = [](const SemanticValues &vs) { + const auto &tok = vs.tokens.front(); + return liti(resolve_escape_sequence(tok.data(), tok.size())); }; - g["LiteralD"] = [](const SemanticValues &sv) { - auto &tok = sv.tokens.front(); - return resolve_escape_sequence(tok.first, tok.second); + g["LiteralD"] = [](const SemanticValues &vs) { + auto &tok = vs.tokens.front(); + return resolve_escape_sequence(tok.data(), tok.size()); }; - g["Class"] = [](const SemanticValues &sv) { - auto ranges = sv.transform>(); + g["Class"] = [](const SemanticValues &vs) { + auto ranges = vs.transform>(); return cls(ranges); }; - g["NegatedClass"] = [](const SemanticValues &sv) { - auto ranges = sv.transform>(); + g["NegatedClass"] = [](const SemanticValues &vs) { + auto ranges = vs.transform>(); return ncls(ranges); }; - g["Range"] = [](const SemanticValues &sv) { - switch (sv.choice()) { + g["Range"] = [](const SemanticValues &vs) { + switch (vs.choice()) { case 0: { - auto s1 = any_cast(sv[0]); - auto s2 = any_cast(sv[1]); - auto cp1 = decode_codepoint(s1.c_str(), s1.length()); - auto cp2 = decode_codepoint(s2.c_str(), s2.length()); - return std::make_pair(cp1, cp2); + auto s1 = std::any_cast(vs[0]); + auto s2 = std::any_cast(vs[1]); + auto cp1 = decode_codepoint(s1.data(), s1.length()); + auto cp2 = decode_codepoint(s2.data(), s2.length()); + return std::pair(cp1, cp2); } case 1: { - auto s = any_cast(sv[0]); - auto cp = decode_codepoint(s.c_str(), s.length()); - return std::make_pair(cp, cp); + auto s = std::any_cast(vs[0]); + auto cp = decode_codepoint(s.data(), s.length()); + return std::pair(cp, cp); } } - return std::make_pair(0, 0); + return std::pair(0, 0); }; - g["Char"] = [](const SemanticValues &sv) { - return resolve_escape_sequence(sv.c_str(), sv.length()); + g["Char"] = [](const SemanticValues &vs) { + return resolve_escape_sequence(vs.sv().data(), vs.sv().length()); }; - g["AND"] = [](const SemanticValues &sv) { return *sv.c_str(); }; - g["NOT"] = [](const SemanticValues &sv) { return *sv.c_str(); }; - g["QUESTION"] = [](const SemanticValues &sv) { return *sv.c_str(); }; - g["STAR"] = [](const SemanticValues &sv) { return *sv.c_str(); }; - g["PLUS"] = [](const SemanticValues &sv) { return *sv.c_str(); }; + g["AND"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + g["NOT"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + g["QUESTION"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + g["STAR"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + g["PLUS"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; - g["DOT"] = [](const SemanticValues & /*sv*/) { return dot(); }; + g["DOT"] = [](const SemanticValues & /*vs*/) { return dot(); }; - g["BeginCap"] = [](const SemanticValues &sv) { return sv.token(); }; + g["BeginCap"] = [](const SemanticValues &vs) { return vs.token(); }; - g["BackRef"] = [&](const SemanticValues &sv) { return bkr(sv.token()); }; + g["BackRef"] = [&](const SemanticValues &vs) { + return bkr(vs.token_to_string()); + }; - g["Ignore"] = [](const SemanticValues &sv) { return sv.size() > 0; }; + g["Ignore"] = [](const SemanticValues &vs) { return vs.size() > 0; }; - g["Parameters"] = [](const SemanticValues &sv) { - return sv.transform(); + g["Parameters"] = [](const SemanticValues &vs) { + return vs.transform(); }; - g["Arguments"] = [](const SemanticValues &sv) { - return sv.transform>(); + g["Arguments"] = [](const SemanticValues &vs) { + return vs.transform>(); }; - g["PrecedenceClimbing"] = [](const SemanticValues &sv) { + g["PrecedenceClimbing"] = [](const SemanticValues &vs) { PrecedenceClimbing::BinOpeInfo binOpeInfo; size_t level = 1; - for (auto v : sv) { - auto tokens = any_cast>(v); + for (auto v : vs) { + auto tokens = std::any_cast>(v); auto assoc = tokens[0][0]; for (size_t i = 1; i < tokens.size(); i++) { - const auto &tok = tokens[i]; - binOpeInfo[tok] = std::make_pair(level, assoc); + binOpeInfo[tokens[i]] = std::pair(level, assoc); } level++; } @@ -3346,11 +3104,11 @@ private: instruction.data = binOpeInfo; return instruction; }; - g["PrecedenceInfo"] = [](const SemanticValues &sv) { - return sv.transform(); + g["PrecedenceInfo"] = [](const SemanticValues &vs) { + return vs.transform(); }; - g["PrecedenceOpe"] = [](const SemanticValues &sv) { return sv.token(); }; - g["PrecedenceAssoc"] = [](const SemanticValues &sv) { return sv.token(); }; + g["PrecedenceOpe"] = [](const SemanticValues &vs) { return vs.token(); }; + g["PrecedenceAssoc"] = [](const SemanticValues &vs) { return vs.token(); }; } bool apply_precedence_instruction(Definition &rule, @@ -3396,7 +3154,7 @@ private: const Rules &rules, std::string &start, Log log) { Data data; - any dt = &data; + std::any dt = &data; auto r = g["Grammar"].parse(s, n, dt); if (!r.ret) { @@ -3417,7 +3175,7 @@ private: // User provided rules for (const auto &x : rules) { auto name = x.first; - bool ignore = false; + auto ignore = false; if (!name.empty() && name[0] == '~') { ignore = true; name.erase(0, 1); @@ -3431,7 +3189,7 @@ private: } // Check duplicated definitions - bool ret = data.duplicates.empty(); + auto ret = data.duplicates.empty(); for (const auto &x : data.duplicates) { if (log) { @@ -3546,7 +3304,7 @@ private: if (instruction.type == "precedence") { const auto &info = - any_cast(instruction.data); + std::any_cast(instruction.data); if (!apply_precedence_instruction(rule, info, s, log)) { return nullptr; @@ -3581,8 +3339,9 @@ template struct AstBase : public Annotation { nodes(a_nodes) {} AstBase(const char *a_path, size_t a_line, size_t a_column, - const char *a_name, const std::string &a_token, size_t a_position = 0, - size_t a_length = 0, size_t a_choice_count = 0, size_t a_choice = 0) + const char *a_name, const std::string_view &a_token, + size_t a_position = 0, size_t a_length = 0, size_t a_choice_count = 0, + size_t a_choice = 0) : path(a_path ? a_path : ""), line(a_line), column(a_column), name(a_name), position(a_position), length(a_length), choice_count(a_choice_count), choice(a_choice), original_name(a_name), @@ -3617,10 +3376,22 @@ template struct AstBase : public Annotation { const unsigned int original_tag; const bool is_token; - const std::string token; + const std::string_view token; std::vector>> nodes; std::weak_ptr> parent; + + std::string token_to_string() const { + assert(is_token); + return std::string(token); + } + + template T token_to_number() const { + assert(is_token); + T n = 0; + std::from_chars(token.data(), token.data() + token.size(), n); + return n; + } }; template @@ -3636,7 +3407,9 @@ void ast_to_s_core(const std::shared_ptr &ptr, std::string &s, int level, } if (ast.name != ast.original_name) { name += "[" + ast.name + "]"; } if (ast.is_token) { - s += "- " + name + " (" + ast.token + ")\n"; + s += "- " + name + " ("; + s += ast.token; + s += ")\n"; } else { s += "+ " + name + "\n"; } @@ -3668,7 +3441,7 @@ struct AstOptimizer { if (opt && original->nodes.size() == 1) { auto child = optimize(original->nodes[0], parent); - return std::make_shared(*child, original->name.c_str(), + return std::make_shared(*child, original->name.data(), original->choice_count, original->position, original->length, original->choice); } @@ -3689,23 +3462,24 @@ private: }; struct EmptyType {}; -typedef AstBase Ast; +using Ast = AstBase; template void add_ast_action(Definition &rule) { - rule.action = [&](const SemanticValues &sv) { - auto line = sv.line_info(); + rule.action = [&](const SemanticValues &vs) { + auto line = vs.line_info(); if (rule.is_token()) { - return std::make_shared(sv.path, line.first, line.second, - rule.name.c_str(), sv.token(), - std::distance(sv.ss, sv.c_str()), sv.length(), - sv.choice_count(), sv.choice()); + return std::make_shared( + vs.path, line.first, line.second, rule.name.data(), vs.token(), + std::distance(vs.ss, vs.sv().data()), vs.sv().length(), + vs.choice_count(), vs.choice()); } - auto ast = std::make_shared( - sv.path, line.first, line.second, rule.name.c_str(), - sv.transform>(), std::distance(sv.ss, sv.c_str()), - sv.length(), sv.choice_count(), sv.choice()); + auto ast = + std::make_shared(vs.path, line.first, line.second, rule.name.data(), + vs.transform>(), + std::distance(vs.ss, vs.sv().data()), + vs.sv().length(), vs.choice_count(), vs.choice()); for (auto node : ast->nodes) { node->parent = ast; @@ -3899,7 +3673,7 @@ public: return parse_n(s, n, path); } - bool parse_n(const char *s, size_t n, any &dt, + bool parse_n(const char *s, size_t n, std::any &dt, const char *path = nullptr) const { if (grammar_ != nullptr) { const auto &rule = (*grammar_)[start_]; @@ -3910,7 +3684,7 @@ public: return false; } - bool parse(const char *s, any &dt, const char *path = nullptr) const { + bool parse(const char *s, std::any &dt, const char *path = nullptr) const { auto n = strlen(s); return parse_n(s, n, dt, path); } @@ -3934,7 +3708,7 @@ public: } template - bool parse_n(const char *s, size_t n, any &dt, T &val, + bool parse_n(const char *s, size_t n, std::any &dt, T &val, const char *path = nullptr) const { if (grammar_ != nullptr) { const auto &rule = (*grammar_)[start_]; @@ -3946,7 +3720,7 @@ public: } template - bool parse(const char *s, any &dt, T &val, + bool parse(const char *s, std::any &dt, T &val, const char * /*path*/ = nullptr) const { auto n = strlen(s); return parse_n(s, n, dt, val); @@ -4013,7 +3787,3 @@ private: }; } // namespace peg - -#endif - -// vim: et ts=2 sw=2 cin cino={1s ff=unix diff --git a/pl0/CMakeLists.txt b/pl0/CMakeLists.txt index 8485819..5d88b45 100644 --- a/pl0/CMakeLists.txt +++ b/pl0/CMakeLists.txt @@ -1,14 +1,11 @@ cmake_minimum_required(VERSION 3.1) -project(tcp) - -enable_language(CXX) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_EXTENSIONS OFF) +project(pl0) include_directories(..) -add_executable(pl0 pl0.cc) +set(CMAKE_CXX_STANDARD 17) + +add_executable(pl0 pl0.cc) find_package(LLVM REQUIRED CONFIG) set(add_link_deps ${add_link_deps} LLVM) target_include_directories(pl0 PUBLIC ${LLVM_INCLUDE_DIRS}) diff --git a/pl0/pl0.cc b/pl0/pl0.cc index 6598c36..6ce8544 100644 --- a/pl0/pl0.cc +++ b/pl0/pl0.cc @@ -182,11 +182,11 @@ struct SymbolTable { // _)? const auto& nodes = ast->nodes; for (auto i = 0u; i < nodes.size(); i += 2) { - const auto& ident = nodes[i + 0]->token; + const auto& ident = nodes[i + 0]->token_to_string(); if (scope->has_symbol(ident)) { throw_runtime_error(nodes[i], "'" + ident + "' is already defined..."); } - auto number = stoi(nodes[i + 1]->token); + auto number = nodes[i + 1]->token_to_number(); scope->constants.emplace(ident, number); } } @@ -196,7 +196,7 @@ struct SymbolTable { // var <- ('VAR' __ ident(',' _ ident)* ';' _) ? const auto& nodes = ast->nodes; for (auto i = 0u; i < nodes.size(); i += 1) { - const auto& ident = nodes[i]->token; + const auto& ident = nodes[i]->token_to_string(); if (scope->has_symbol(ident)) { throw_runtime_error(nodes[i], "'" + ident + "' is already defined..."); } @@ -209,7 +209,7 @@ struct SymbolTable { // procedure <- ('PROCEDURE' __ ident ';' _ block ';' _)* const auto& nodes = ast->nodes; for (auto i = 0u; i < nodes.size(); i += 2) { - const auto& ident = nodes[i + 0]->token; + const auto& ident = nodes[i + 0]->token_to_string(); auto block = nodes[i + 1]; scope->procedures[ident] = block; build_on_ast(block, scope); @@ -219,7 +219,7 @@ struct SymbolTable { static void assignment(const shared_ptr ast, shared_ptr scope) { // assignment <- ident ':=' _ expression - const auto& ident = ast->nodes[0]->token; + const auto& ident = ast->nodes[0]->token_to_string(); if (scope->has_constant(ident)) { throw_runtime_error(ast->nodes[0], "cannot modify constant value '" + ident + "'..."); @@ -238,7 +238,7 @@ struct SymbolTable { static void call(const shared_ptr ast, shared_ptr scope) { // call <- 'CALL' __ ident - const auto& ident = ast->nodes[0]->token; + const auto& ident = ast->nodes[0]->token_to_string(); if (!scope->has_procedure(ident)) { throw_runtime_error(ast->nodes[0], "undefined procedure '" + ident + "'..."); @@ -256,7 +256,7 @@ struct SymbolTable { static void ident(const shared_ptr ast, shared_ptr scope) { - const auto& ident = ast->token; + const auto& ident = ast->token_to_string(); if (!scope->has_symbol(ident)) { throw_runtime_error(ast, "undefined variable '" + ident + "'..."); } @@ -360,13 +360,13 @@ struct Interpreter { static void exec_assignment(const shared_ptr ast, shared_ptr env) { // assignment <- ident ':=' _ expression - env->set_variable(ast->nodes[0]->token, eval(ast->nodes[1], env)); + env->set_variable(ast->nodes[0]->token_to_string(), eval(ast->nodes[1], env)); } static void exec_call(const shared_ptr ast, shared_ptr env) { // call <- 'CALL' __ ident - exec_block(env->get_procedure(ast->nodes[0]->token), env); + exec_block(env->get_procedure(ast->nodes[0]->token_to_string()), env); } static void exec_statements(const shared_ptr ast, @@ -406,7 +406,7 @@ struct Interpreter { // in <- ('in' __ / 'read' __ / '?' _) ident int val; cin >> val; - env->set_variable(ast->nodes[0]->token, val); + env->set_variable(ast->nodes[0]->token_to_string(), val); } static bool eval_condition(const shared_ptr ast, @@ -434,7 +434,7 @@ struct Interpreter { // compare <- expression compare_op expression const auto& nodes = ast->nodes; auto lval = eval_expression(nodes[0], env); - auto op = peg::str2tag(nodes[1]->token.c_str()); + auto op = peg::str2tag(nodes[1]->token_to_string().c_str()); auto rval = eval_expression(nodes[2], env); switch (op) { case "="_: @@ -473,11 +473,11 @@ struct Interpreter { shared_ptr env) { // expression <- sign term (term_op term)* const auto& nodes = ast->nodes; - auto sign = nodes[0]->token; + auto sign = nodes[0]->token_to_string(); auto sign_val = (sign.empty() || sign == "+") ? 1 : -1; auto val = eval(nodes[1], env) * sign_val; for (auto i = 2u; i < nodes.size(); i += 2) { - auto ope = nodes[i + 0]->token[0]; + auto ope = nodes[i + 0]->token_to_string()[0]; auto rval = eval(nodes[i + 1], env); switch (ope) { case '+': @@ -497,7 +497,7 @@ struct Interpreter { const auto& nodes = ast->nodes; auto val = eval(nodes[0], env); for (auto i = 1u; i < nodes.size(); i += 2) { - auto ope = nodes[i + 0]->token[0]; + auto ope = nodes[i + 0]->token_to_string()[0]; auto rval = eval(nodes[i + 1], env); switch (ope) { case '*': @@ -516,12 +516,12 @@ struct Interpreter { static int eval_ident(const shared_ptr ast, shared_ptr env) { - return env->get_value(ast, ast->token); + return env->get_value(ast, ast->token_to_string()); } static int eval_number(const shared_ptr ast, shared_ptr env) { - return stol(ast->token); + return stol(ast->token_to_string()); } }; @@ -653,8 +653,8 @@ struct LLVM { void compile_const(const shared_ptr ast) { for (auto i = 0u; i < ast->nodes.size(); i += 2) { - auto ident = ast->nodes[i]->token; - auto number = stoi(ast->nodes[i + 1]->token); + auto ident = ast->nodes[i]->token_to_string(); + auto number = stoi(ast->nodes[i + 1]->token_to_string()); auto alloca = builder_.CreateAlloca(builder_.getInt32Ty(), nullptr, ident); @@ -664,14 +664,14 @@ struct LLVM { void compile_var(const shared_ptr ast) { for (const auto node : ast->nodes) { - auto ident = node->token; + auto ident = node->token_to_string(); builder_.CreateAlloca(builder_.getInt32Ty(), nullptr, ident); } } void compile_procedure(const shared_ptr ast) { for (auto i = 0u; i < ast->nodes.size(); i += 2) { - auto ident = ast->nodes[i]->token; + auto ident = ast->nodes[i]->token_to_string(); auto block = ast->nodes[i + 1]; std::vector pt(block->scope->free_variables.size(), @@ -712,7 +712,7 @@ struct LLVM { } void compile_assignment(const shared_ptr ast) { - auto ident = ast->nodes[0]->token; + auto ident = ast->nodes[0]->token_to_string(); auto fn = builder_.GetInsertBlock()->getParent(); auto tbl = fn->getValueSymbolTable(); @@ -726,7 +726,7 @@ struct LLVM { } void compile_call(const shared_ptr ast) { - auto ident = ast->nodes[0]->token; + auto ident = ast->nodes[0]->token_to_string(); auto scope = get_closest_scope(ast); auto block = scope->get_procedure(ident); @@ -805,7 +805,7 @@ struct LLVM { auto lhs = compile_expression(ast->nodes[0]); auto rhs = compile_expression(ast->nodes[2]); - const auto& ope = ast->nodes[1]->token; + const auto& ope = ast->nodes[1]->token_to_string(); switch (ope[0]) { case '=': return builder_.CreateICmpEQ(lhs, rhs, "icmpeq"); @@ -836,7 +836,7 @@ struct LLVM { Value* compile_expression(const shared_ptr ast) { const auto& nodes = ast->nodes; - auto sign = nodes[0]->token; + auto sign = nodes[0]->token_to_string(); auto negative = !(sign.empty() || sign == "+"); auto val = compile_term(nodes[1]); @@ -845,7 +845,7 @@ struct LLVM { } for (auto i = 2u; i < nodes.size(); i += 2) { - auto ope = nodes[i + 0]->token[0]; + auto ope = nodes[i + 0]->token_to_string()[0]; auto rval = compile_term(nodes[i + 1]); switch (ope) { case '+': @@ -863,7 +863,7 @@ struct LLVM { const auto& nodes = ast->nodes; auto val = compile_factor(nodes[0]); for (auto i = 1u; i < nodes.size(); i += 2) { - auto ope = nodes[i + 0]->token[0]; + auto ope = nodes[i + 0]->token_to_string()[0]; auto rval = compile_switch_value(nodes[i + 1]); switch (ope) { case '*': @@ -889,7 +889,7 @@ struct LLVM { } Value* compile_ident(const shared_ptr ast) { - auto ident = ast->token; + auto ident = ast->token_to_string(); auto fn = builder_.GetInsertBlock()->getParent(); auto tbl = fn->getValueSymbolTable(); @@ -903,7 +903,7 @@ struct LLVM { Value* compile_number(const shared_ptr ast) { return ConstantInt::getIntegerValue(builder_.getInt32Ty(), - APInt(32, ast->token, 10)); + APInt(32, ast->token_to_string(), 10)); } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9944772..1a1da03 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,13 +1,14 @@ cmake_minimum_required(VERSION 3.1) project(test) -enable_language(CXX) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_EXTENSIONS OFF) - include_directories(..) + +set(CMAKE_CXX_STANDARD 17) + add_executable(test-main test-main.cc test1.cc test2.cc test3.cc) target_link_libraries(test-main ${add_link_deps}) -add_test(TestMain test-main) +add_test( + NAME TestMain + COMMAND test-main + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/test/test1.cc b/test/test1.cc index a583e81..dcde402 100644 --- a/test/test1.cc +++ b/test/test1.cc @@ -4,198 +4,178 @@ using namespace peg; #if !defined(PEGLIB_NO_UNICODE_CHARS) -TEST_CASE("Simple syntax test (with unicode)", "[general]") -{ - parser parser( - u8" ROOT ← _ " - " _ <- ' ' " - ); - - bool ret = parser; - REQUIRE(ret == true); +TEST_CASE("Simple syntax test (with unicode)", "[general]") { + parser parser(u8" ROOT ← _ " + " _ <- ' ' "); + + bool ret = parser; + REQUIRE(ret == true); } #endif -TEST_CASE("Simple syntax test", "[general]") -{ - parser parser(R"( +TEST_CASE("Simple syntax test", "[general]") { + parser parser(R"( ROOT <- _ _ <- ' ' )"); - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); } -TEST_CASE("Empty syntax test", "[general]") -{ - parser parser(""); - bool ret = parser; - REQUIRE(ret == false); +TEST_CASE("Empty syntax test", "[general]") { + parser parser(""); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Start rule with ignore operator test", "[general]") -{ - parser parser(R"( +TEST_CASE("Start rule with ignore operator test", "[general]") { + parser parser(R"( ~ROOT <- _ _ <- ' ' )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Invalid UTF-8 text test", "[general]") -{ - std::string s = "a <- '"; - s += static_cast(0xe8); // Make invalid utf8 text... +TEST_CASE("Invalid UTF-8 text test", "[general]") { + std::string s = "a <- '"; + s += static_cast(0xe8); // Make invalid utf8 text... - parser parser(s.c_str()); + parser parser(s.data()); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Backslash escape sequence test", "[general]") -{ - parser parser(R"( +TEST_CASE("Backslash escape sequence test", "[general]") { + parser parser(R"( ROOT <- _ _ <- '\\' )"); - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); } -TEST_CASE("Invalid escape sequence test", "[general]") -{ - parser parser(R"( +TEST_CASE("Invalid escape sequence test", "[general]") { + parser parser(R"( ROOT <- _ _ <- '\' )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Action taking non const Semantic Values parameter", "[general]") -{ - parser parser(R"( +TEST_CASE("Action taking non const Semantic Values parameter", "[general]") { + parser parser(R"( ROOT <- TEXT TEXT <- [a-zA-Z]+ )"); - parser["ROOT"] = [&](SemanticValues& sv) { - auto s = any_cast(sv[0]); - s[0] = 'H'; // mutate - return std::string(std::move(s)); // move - }; + parser["ROOT"] = [&](SemanticValues &vs) { + auto s = std::string(std::any_cast(vs[0])); + s[0] = 'H'; // mutate + return s; // move + }; - parser["TEXT"] = [&](SemanticValues& sv) { - return sv.token(); - }; + parser["TEXT"] = [&](SemanticValues &vs) { return vs.token(); }; - std::string val; - auto ret = parser.parse("hello", val); - REQUIRE(ret == true); - REQUIRE(val == "Hello"); + std::string val; + auto ret = parser.parse("hello", val); + REQUIRE(ret == true); + REQUIRE(val == "Hello"); } -TEST_CASE("String capture test", "[general]") -{ - parser parser(R"( +TEST_CASE("String capture test", "[general]") { + parser parser(R"( ROOT <- _ ('[' TAG_NAME ']' _)* TAG_NAME <- (!']' .)+ _ <- [ \t]* )"); - std::vector tags; + std::vector tags; - parser["TAG_NAME"] = [&](const SemanticValues& sv) { - tags.push_back(sv.str()); - }; + parser["TAG_NAME"] = [&](const SemanticValues &vs) { + tags.push_back(vs.sv()); + }; - auto ret = parser.parse(" [tag1] [tag:2] [tag-3] "); + auto ret = parser.parse(" [tag1] [tag:2] [tag-3] "); - REQUIRE(ret == true); - REQUIRE(tags.size() == 3); - REQUIRE(tags[0] == "tag1"); - REQUIRE(tags[1] == "tag:2"); - REQUIRE(tags[2] == "tag-3"); + REQUIRE(ret == true); + REQUIRE(tags.size() == 3); + REQUIRE(tags[0] == "tag1"); + REQUIRE(tags[1] == "tag:2"); + REQUIRE(tags[2] == "tag-3"); } using namespace peg; -TEST_CASE("String capture test2", "[general]") -{ - std::vector tags; +TEST_CASE("String capture test2", "[general]") { + std::vector tags; - Definition ROOT, TAG, TAG_NAME, WS; - ROOT <= seq(WS, zom(TAG)); - TAG <= seq(chr('['), TAG_NAME, chr(']'), WS); - TAG_NAME <= oom(seq(npd(chr(']')), dot())), [&](const SemanticValues& sv) { tags.push_back(sv.str()); }; - WS <= zom(cls(" \t")); + Definition ROOT, TAG, TAG_NAME, WS; + ROOT <= seq(WS, zom(TAG)); + TAG <= seq(chr('['), TAG_NAME, chr(']'), WS); + TAG_NAME <= oom(seq(npd(chr(']')), dot())), + [&](const SemanticValues &vs) { tags.push_back(vs.sv()); }; + WS <= zom(cls(" \t")); - auto r = ROOT.parse(" [tag1] [tag:2] [tag-3] "); + auto r = ROOT.parse(" [tag1] [tag:2] [tag-3] "); - REQUIRE(r.ret == true); - REQUIRE(tags.size() == 3); - REQUIRE(tags[0] == "tag1"); - REQUIRE(tags[1] == "tag:2"); - REQUIRE(tags[2] == "tag-3"); + REQUIRE(r.ret == true); + REQUIRE(tags.size() == 3); + REQUIRE(tags[0] == "tag1"); + REQUIRE(tags[1] == "tag:2"); + REQUIRE(tags[2] == "tag-3"); } -TEST_CASE("String capture test3", "[general]") -{ - parser pg(R"( +TEST_CASE("String capture test3", "[general]") { + parser pg(R"( ROOT <- _ TOKEN* TOKEN <- '[' < (!']' .)+ > ']' _ _ <- [ \t\r\n]* )"); + std::vector tags; - std::vector tags; + pg["TOKEN"] = [&](const SemanticValues &vs) { tags.push_back(vs.token()); }; - pg["TOKEN"] = [&](const SemanticValues& sv) { - tags.push_back(sv.token()); - }; + auto ret = pg.parse(" [tag1] [tag:2] [tag-3] "); - auto ret = pg.parse(" [tag1] [tag:2] [tag-3] "); - - REQUIRE(ret == true); - REQUIRE(tags.size() == 3); - REQUIRE(tags[0] == "tag1"); - REQUIRE(tags[1] == "tag:2"); - REQUIRE(tags[2] == "tag-3"); + REQUIRE(ret == true); + REQUIRE(tags.size() == 3); + REQUIRE(tags[0] == "tag1"); + REQUIRE(tags[1] == "tag:2"); + REQUIRE(tags[2] == "tag-3"); } -TEST_CASE("Cyclic grammer test", "[general]") -{ - Definition PARENT; - Definition CHILD; +TEST_CASE("Cyclic grammer test", "[general]") { + Definition PARENT; + Definition CHILD; - PARENT <= seq(CHILD); - CHILD <= seq(PARENT); + PARENT <= seq(CHILD); + CHILD <= seq(PARENT); } -TEST_CASE("Visit test", "[general]") -{ - Definition ROOT, TAG, TAG_NAME, WS; +TEST_CASE("Visit test", "[general]") { + Definition ROOT, TAG, TAG_NAME, WS; - ROOT <= seq(WS, zom(TAG)); - TAG <= seq(chr('['), TAG_NAME, chr(']'), WS); - TAG_NAME <= oom(seq(npd(chr(']')), dot())); - WS <= zom(cls(" \t")); + ROOT <= seq(WS, zom(TAG)); + TAG <= seq(chr('['), TAG_NAME, chr(']'), WS); + TAG_NAME <= oom(seq(npd(chr(']')), dot())); + WS <= zom(cls(" \t")); - AssignIDToDefinition defIds; - ROOT.accept(defIds); + AssignIDToDefinition defIds; + ROOT.accept(defIds); - REQUIRE(defIds.ids.size() == 4); + REQUIRE(defIds.ids.size() == 4); } -TEST_CASE("Token check test", "[general]") -{ - parser parser(R"( +TEST_CASE("Token check test", "[general]") { + parser parser(R"( EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ @@ -205,78 +185,74 @@ TEST_CASE("Token check test", "[general]") _ <- [ \t\r\n]* )"); - REQUIRE(parser["EXPRESSION"].is_token() == false); - REQUIRE(parser["FACTOR"].is_token() == false); - REQUIRE(parser["FACTOR_OPERATOR"].is_token() == true); - REQUIRE(parser["NUMBER"].is_token() == true); - REQUIRE(parser["_"].is_token() == true); + REQUIRE(parser["EXPRESSION"].is_token() == false); + REQUIRE(parser["FACTOR"].is_token() == false); + REQUIRE(parser["FACTOR_OPERATOR"].is_token() == true); + REQUIRE(parser["NUMBER"].is_token() == true); + REQUIRE(parser["_"].is_token() == true); } -TEST_CASE("Lambda action test", "[general]") -{ - parser parser(R"( +TEST_CASE("Lambda action test", "[general]") { + parser parser(R"( START <- (CHAR)* CHAR <- . )"); - std::string ss; - parser["CHAR"] = [&](const SemanticValues& sv) { - ss += *sv.c_str(); - }; + std::string ss; + parser["CHAR"] = [&](const SemanticValues &vs) { ss += *vs.sv().data(); }; - bool ret = parser.parse("hello"); - REQUIRE(ret == true); - REQUIRE(ss == "hello"); + bool ret = parser.parse("hello"); + REQUIRE(ret == true); + REQUIRE(ss == "hello"); } -TEST_CASE("enter/leave handlers test", "[general]") -{ - parser parser(R"( +TEST_CASE("enter/leave handlers test", "[general]") { + parser parser(R"( START <- LTOKEN '=' RTOKEN LTOKEN <- TOKEN RTOKEN <- TOKEN TOKEN <- [A-Za-z]+ )"); - parser["LTOKEN"].enter = [&](const char*, size_t, any& dt) { - auto& require_upper_case = *any_cast(dt); - require_upper_case = false; - }; - parser["LTOKEN"].leave = [&](const char*, size_t, size_t, any&, any& dt) { - auto& require_upper_case = *any_cast(dt); - require_upper_case = true; - }; + parser["LTOKEN"].enter = [&](const char *, size_t, std::any &dt) { + auto &require_upper_case = *std::any_cast(dt); + require_upper_case = false; + }; + parser["LTOKEN"].leave = [&](const char *, size_t, size_t, std::any &, + std::any &dt) { + auto &require_upper_case = *std::any_cast(dt); + require_upper_case = true; + }; - auto message = "should be upper case string..."; + auto message = "should be upper case string..."; - parser["TOKEN"] = [&](const SemanticValues& sv, any& dt) { - auto& require_upper_case = *any_cast(dt); - if (require_upper_case) { - const auto& s = sv.str(); - if (!std::all_of(s.begin(), s.end(), ::isupper)) { - throw parse_error(message); - } - } - }; + parser["TOKEN"] = [&](const SemanticValues &vs, std::any &dt) { + auto &require_upper_case = *std::any_cast(dt); + if (require_upper_case) { + const auto &s = vs.sv(); + if (!std::all_of(s.begin(), s.end(), ::isupper)) { + throw parse_error(message); + } + } + }; - bool require_upper_case = false; - any dt = &require_upper_case; - REQUIRE(parser.parse("hello=world", dt) == false); - REQUIRE(parser.parse("HELLO=world", dt) == false); - REQUIRE(parser.parse("hello=WORLD", dt) == true); - REQUIRE(parser.parse("HELLO=WORLD", dt) == true); - - parser.log = [&](size_t ln, size_t col, const std::string& msg) { - REQUIRE(ln == 1); - REQUIRE(col == 7); - REQUIRE(msg == message); - }; - parser.parse("hello=world", dt); + bool require_upper_case = false; + std::any dt = &require_upper_case; + REQUIRE(parser.parse("hello=world", dt) == false); + REQUIRE(parser.parse("HELLO=world", dt) == false); + REQUIRE(parser.parse("hello=WORLD", dt) == true); + REQUIRE(parser.parse("HELLO=WORLD", dt) == true); + + parser.log = [&](size_t ln, size_t col, const std::string &msg) { + REQUIRE(ln == 1); + REQUIRE(col == 7); + REQUIRE(msg == message); + }; + parser.parse("hello=world", dt); } -TEST_CASE("WHITESPACE test", "[general]") -{ - parser parser(R"( +TEST_CASE("WHITESPACE test", "[general]") { + parser parser(R"( # Rules ROOT <- ITEM (',' ITEM)* ITEM <- WORD / PHRASE @@ -288,14 +264,13 @@ TEST_CASE("WHITESPACE test", "[general]") %whitespace <- [ \t\r\n]* )"); - auto ret = parser.parse(R"( one, "two, three", four )"); + auto ret = parser.parse(R"( one, "two, three", four )"); - REQUIRE(ret == true); + REQUIRE(ret == true); } -TEST_CASE("WHITESPACE test2", "[general]") -{ - parser parser(R"( +TEST_CASE("WHITESPACE test2", "[general]") { + parser parser(R"( # Rules ROOT <- ITEM (',' ITEM)* ITEM <- '[' < [a-zA-Z0-9_]+ > ']' @@ -305,22 +280,22 @@ TEST_CASE("WHITESPACE test2", "[general]") TAB <- '\t' )"); - std::vector items; - parser["ITEM"] = [&](const SemanticValues& sv) { - items.push_back(sv.token()); - }; + std::vector items; + parser["ITEM"] = [&](const SemanticValues &vs) { + items.push_back(vs.token()); + }; - auto ret = parser.parse(R"([one], [two] ,[three] )"); + auto ret = parser.parse(R"([one], [two] ,[three] )"); - REQUIRE(ret == true); - REQUIRE(items.size() == 3); - REQUIRE(items[0] == "one"); - REQUIRE(items[1] == "two"); - REQUIRE(items[2] == "three"); + REQUIRE(ret == true); + REQUIRE(items.size() == 3); + REQUIRE(items[0] == "one"); + REQUIRE(items[1] == "two"); + REQUIRE(items[2] == "three"); } TEST_CASE("WHITESPACE test3", "[general]") { - parser parser(R"( + parser parser(R"( StrQuot <- < '"' < (StrEscape / StrChars)* > '"' > StrEscape <- '\\' any StrChars <- (!'"' !'\\' any)+ @@ -328,16 +303,16 @@ TEST_CASE("WHITESPACE test3", "[general]") { %whitespace <- [ \t]* )"); - parser["StrQuot"] = [](const SemanticValues& sv) { - REQUIRE(sv.token() == R"( aaa \" bbb )"); - }; + parser["StrQuot"] = [](const SemanticValues &vs) { + REQUIRE(vs.token() == R"( aaa \" bbb )"); + }; - auto ret = parser.parse(R"( " aaa \" bbb " )"); - REQUIRE(ret == true); + auto ret = parser.parse(R"( " aaa \" bbb " )"); + REQUIRE(ret == true); } TEST_CASE("WHITESPACE test4", "[general]") { - parser parser(R"( + parser parser(R"( ROOT <- HELLO OPE WORLD HELLO <- 'hello' OPE <- < [-+] > @@ -345,249 +320,221 @@ TEST_CASE("WHITESPACE test4", "[general]") { %whitespace <- [ \t\r\n]* )"); - parser["HELLO"] = [](const SemanticValues& sv) { - REQUIRE(sv.token() == "hello"); - }; + parser["HELLO"] = [](const SemanticValues &vs) { + REQUIRE(vs.token() == "hello"); + }; - parser["OPE"] = [](const SemanticValues& sv) { - REQUIRE(sv.token() == "+"); - }; + parser["OPE"] = [](const SemanticValues &vs) { REQUIRE(vs.token() == "+"); }; - parser["WORLD"] = [](const SemanticValues& sv) { - REQUIRE(sv.token() == "world"); - }; + parser["WORLD"] = [](const SemanticValues &vs) { + REQUIRE(vs.token() == "world"); + }; - auto ret = parser.parse(" hello + world "); - REQUIRE(ret == true); + auto ret = parser.parse(" hello + world "); + REQUIRE(ret == true); } TEST_CASE("Word expression test", "[general]") { - parser parser(R"( + parser parser(R"( ROOT <- 'hello' ','? 'world' %whitespace <- [ \t\r\n]* %word <- [a-z]+ )"); - REQUIRE(parser.parse("helloworld") == false); - REQUIRE(parser.parse("hello world") == true); - REQUIRE(parser.parse("hello,world") == true); - REQUIRE(parser.parse("hello, world") == true); - REQUIRE(parser.parse("hello , world") == true); + REQUIRE(parser.parse("helloworld") == false); + REQUIRE(parser.parse("hello world") == true); + REQUIRE(parser.parse("hello,world") == true); + REQUIRE(parser.parse("hello, world") == true); + REQUIRE(parser.parse("hello , world") == true); } -TEST_CASE("Skip token test", "[general]") -{ - parser parser( - " ROOT <- _ ITEM (',' _ ITEM _)* " - " ITEM <- ([a-z0-9])+ " - " ~_ <- [ \t]* " - ); +TEST_CASE("Skip token test", "[general]") { + parser parser(" ROOT <- _ ITEM (',' _ ITEM _)* " + " ITEM <- ([a-z0-9])+ " + " ~_ <- [ \t]* "); - parser["ROOT"] = [&](const SemanticValues& sv) { - REQUIRE(sv.size() == 2); - }; + parser["ROOT"] = [&](const SemanticValues &vs) { REQUIRE(vs.size() == 2); }; - auto ret = parser.parse(" item1, item2 "); + auto ret = parser.parse(" item1, item2 "); - REQUIRE(ret == true); + REQUIRE(ret == true); } -TEST_CASE("Skip token test2", "[general]") -{ - parser parser(R"( +TEST_CASE("Skip token test2", "[general]") { + parser parser(R"( ROOT <- ITEM (',' ITEM)* ITEM <- < ([a-z0-9])+ > %whitespace <- [ \t]* )"); - parser["ROOT"] = [&](const SemanticValues& sv) { - REQUIRE(sv.size() == 2); - }; + parser["ROOT"] = [&](const SemanticValues &vs) { REQUIRE(vs.size() == 2); }; - auto ret = parser.parse(" item1, item2 "); + auto ret = parser.parse(" item1, item2 "); - REQUIRE(ret == true); + REQUIRE(ret == true); } -TEST_CASE("Custom AST test", "[general]") -{ - struct CustomType {}; - using CustomAst = AstBase; - - parser parser(R"( +TEST_CASE("Custom AST test", "[general]") { + struct CustomType {}; + using CustomAst = AstBase; + + parser parser(R"( ROOT <- _ TEXT* TEXT <- [a-zA-Z]+ _ _ <- [ \t\r\n]* )"); - parser.enable_ast(); - std::shared_ptr ast; - bool ret = parser.parse("a b c", ast); - REQUIRE(ret == true); - REQUIRE(ast->nodes.size() == 4); + parser.enable_ast(); + std::shared_ptr ast; + bool ret = parser.parse("a b c", ast); + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 4); } -TEST_CASE("Backtracking test", "[general]") -{ - parser parser(R"( +TEST_CASE("Backtracking test", "[general]") { + parser parser(R"( START <- PAT1 / PAT2 PAT1 <- HELLO ' One' PAT2 <- HELLO ' Two' HELLO <- 'Hello' )"); - size_t count = 0; - parser["HELLO"] = [&](const SemanticValues& /*sv*/) { - count++; - }; + size_t count = 0; + parser["HELLO"] = [&](const SemanticValues & /*vs*/) { count++; }; - parser.enable_packrat_parsing(); + parser.enable_packrat_parsing(); - bool ret = parser.parse("Hello Two"); - REQUIRE(ret == true); - REQUIRE(count == 1); // Skip second time + bool ret = parser.parse("Hello Two"); + REQUIRE(ret == true); + REQUIRE(count == 1); // Skip second time } -TEST_CASE("Backtracking with AST", "[general]") -{ - parser parser(R"( +TEST_CASE("Backtracking with AST", "[general]") { + parser parser(R"( S <- A? B (A B)* A A <- 'a' B <- 'b' )"); - parser.enable_ast(); - std::shared_ptr ast; - bool ret = parser.parse("ba", ast); - REQUIRE(ret == true); - REQUIRE(ast->nodes.size() == 2); + parser.enable_ast(); + std::shared_ptr ast; + bool ret = parser.parse("ba", ast); + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 2); } -TEST_CASE("Octal/Hex/Unicode value test", "[general]") -{ - parser parser( - R"( ROOT <- '\132\x7a\u30f3' )" - ); +TEST_CASE("Octal/Hex/Unicode value test", "[general]") { + parser parser(R"( ROOT <- '\132\x7a\u30f3' )"); - auto ret = parser.parse("Zzン"); + auto ret = parser.parse("Zzン"); - REQUIRE(ret == true); + REQUIRE(ret == true); } TEST_CASE("Ignore case test", "[general]") { - parser parser(R"( + parser parser(R"( ROOT <- HELLO WORLD HELLO <- 'hello'i WORLD <- 'world'i %whitespace <- [ \t\r\n]* )"); - parser["HELLO"] = [](const SemanticValues& sv) { - REQUIRE(sv.token() == "Hello"); - }; + parser["HELLO"] = [](const SemanticValues &vs) { + REQUIRE(vs.token() == "Hello"); + }; - parser["WORLD"] = [](const SemanticValues& sv) { - REQUIRE(sv.token() == "World"); - }; + parser["WORLD"] = [](const SemanticValues &vs) { + REQUIRE(vs.token() == "World"); + }; - auto ret = parser.parse(" Hello World "); - REQUIRE(ret == true); + auto ret = parser.parse(" Hello World "); + REQUIRE(ret == true); } -TEST_CASE("mutable lambda test", "[general]") -{ - std::vector vec; +TEST_CASE("mutable lambda test", "[general]") { + std::vector vec; - parser pg("ROOT <- 'mutable lambda test'"); + parser pg("ROOT <- 'mutable lambda test'"); - // This test makes sure if the following code can be compiled. - pg["TOKEN"] = [=](const SemanticValues& sv) mutable { - vec.push_back(sv.str()); - }; + // This test makes sure if the following code can be compiled. + pg["TOKEN"] = [=](const SemanticValues &vs) mutable { + vec.push_back(vs.sv()); + }; } -TEST_CASE("Simple calculator test", "[general]") -{ - parser parser(R"( +TEST_CASE("Simple calculator test", "[general]") { + parser parser(R"( Additive <- Multitive '+' Additive / Multitive Multitive <- Primary '*' Multitive / Primary Primary <- '(' Additive ')' / Number Number <- [0-9]+ )"); - parser["Additive"] = [](const SemanticValues& sv) { - switch (sv.choice()) { - case 0: - return any_cast(sv[0]) + any_cast(sv[1]); - default: - return any_cast(sv[0]); - } - }; + parser["Additive"] = [](const SemanticValues &vs) { + switch (vs.choice()) { + case 0: return std::any_cast(vs[0]) + std::any_cast(vs[1]); + default: return std::any_cast(vs[0]); + } + }; - parser["Multitive"] = [](const SemanticValues& sv) { - switch (sv.choice()) { - case 0: - return any_cast(sv[0]) * any_cast(sv[1]); - default: - return any_cast(sv[0]); - } - }; + parser["Multitive"] = [](const SemanticValues &vs) { + switch (vs.choice()) { + case 0: return std::any_cast(vs[0]) * std::any_cast(vs[1]); + default: return std::any_cast(vs[0]); + } + }; - parser["Number"] = [](const SemanticValues& sv) { - return atoi(sv.c_str()); - }; + parser["Number"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; - int val; - parser.parse("(1+2)*3", val); - - REQUIRE(val == 9); -} - -TEST_CASE("Calculator test", "[general]") -{ - // Construct grammer - Definition EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, NUMBER; - - EXPRESSION <= seq(TERM, zom(seq(TERM_OPERATOR, TERM))); - TERM <= seq(FACTOR, zom(seq(FACTOR_OPERATOR, FACTOR))); - FACTOR <= cho(NUMBER, seq(chr('('), EXPRESSION, chr(')'))); - TERM_OPERATOR <= cls("+-"); - FACTOR_OPERATOR <= cls("*/"); - NUMBER <= oom(cls("0-9")); - - // Setup actions - auto reduce = [](const SemanticValues& sv) -> long { - long ret = any_cast(sv[0]); - for (auto i = 1u; i < sv.size(); i += 2) { - auto num = any_cast(sv[i + 1]); - switch (any_cast(sv[i])) { - case '+': ret += num; break; - case '-': ret -= num; break; - case '*': ret *= num; break; - case '/': ret /= num; break; - } - } - return ret; - }; + int val; + parser.parse("(1+2)*3", val); - EXPRESSION = reduce; - TERM = reduce; - TERM_OPERATOR = [](const SemanticValues& sv) { return *sv.c_str(); }; - FACTOR_OPERATOR = [](const SemanticValues& sv) { return *sv.c_str(); }; - NUMBER = [](const SemanticValues& sv) { return stol(sv.str(), nullptr, 10); }; + REQUIRE(val == 9); +} + +TEST_CASE("Calculator test", "[general]") { + // Construct grammer + Definition EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, NUMBER; - // Parse - long val; - auto r = EXPRESSION.parse_and_get_value("1+2*3*(4-5+6)/7-8", val); + EXPRESSION <= seq(TERM, zom(seq(TERM_OPERATOR, TERM))); + TERM <= seq(FACTOR, zom(seq(FACTOR_OPERATOR, FACTOR))); + FACTOR <= cho(NUMBER, seq(chr('('), EXPRESSION, chr(')'))); + TERM_OPERATOR <= cls("+-"); + FACTOR_OPERATOR <= cls("*/"); + NUMBER <= oom(cls("0-9")); - REQUIRE(r.ret == true); - REQUIRE(val == -3); + // Setup actions + auto reduce = [](const SemanticValues &vs) -> long { + long ret = std::any_cast(vs[0]); + for (auto i = 1u; i < vs.size(); i += 2) { + auto num = std::any_cast(vs[i + 1]); + switch (std::any_cast(vs[i])) { + case '+': ret += num; break; + case '-': ret -= num; break; + case '*': ret *= num; break; + case '/': ret /= num; break; + } + } + return ret; + }; + + EXPRESSION = reduce; + TERM = reduce; + TERM_OPERATOR = [](const SemanticValues &vs) { return *vs.sv().data(); }; + FACTOR_OPERATOR = [](const SemanticValues &vs) { return *vs.sv().data(); }; + NUMBER = [](const SemanticValues &vs) { return vs.token_to_number(); }; + + // Parse + long val; + auto r = EXPRESSION.parse_and_get_value("1+2*3*(4-5+6)/7-8", val); + + REQUIRE(r.ret == true); + REQUIRE(val == -3); } -TEST_CASE("Calculator test2", "[general]") -{ - // Parse syntax - auto syntax = R"( +TEST_CASE("Calculator test2", "[general]") { + // Parse syntax + auto syntax = R"( # Grammar for Calculator... EXPRESSION <- TERM (TERM_OPERATOR TERM)* TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* @@ -597,43 +544,42 @@ TEST_CASE("Calculator test2", "[general]") NUMBER <- [0-9]+ )"; - std::string start; - auto grammar = ParserGenerator::parse(syntax, strlen(syntax), start, nullptr); - auto& g = *grammar; - - // Setup actions - auto reduce = [](const SemanticValues& sv) -> long { - long ret = any_cast(sv[0]); - for (auto i = 1u; i < sv.size(); i += 2) { - auto num = any_cast(sv[i + 1]); - switch (any_cast(sv[i])) { - case '+': ret += num; break; - case '-': ret -= num; break; - case '*': ret *= num; break; - case '/': ret /= num; break; - } - } - return ret; - }; + std::string start; + auto grammar = ParserGenerator::parse(syntax, strlen(syntax), start, nullptr); + auto &g = *grammar; + + // Setup actions + auto reduce = [](const SemanticValues &vs) -> long { + long ret = std::any_cast(vs[0]); + for (auto i = 1u; i < vs.size(); i += 2) { + auto num = std::any_cast(vs[i + 1]); + switch (std::any_cast(vs[i])) { + case '+': ret += num; break; + case '-': ret -= num; break; + case '*': ret *= num; break; + case '/': ret /= num; break; + } + } + return ret; + }; - g["EXPRESSION"] = reduce; - g["TERM"] = reduce; - g["TERM_OPERATOR"] = [](const SemanticValues& sv) { return *sv.c_str(); }; - g["FACTOR_OPERATOR"] = [](const SemanticValues& sv) { return *sv.c_str(); }; - g["NUMBER"] = [](const SemanticValues& sv) { return stol(sv.str(), nullptr, 10); }; + g["EXPRESSION"] = reduce; + g["TERM"] = reduce; + g["TERM_OPERATOR"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + g["FACTOR_OPERATOR"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + g["NUMBER"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; - // Parse - long val; - auto r = g[start].parse_and_get_value("1+2*3*(4-5+6)/7-8", val); + // Parse + long val; + auto r = g[start].parse_and_get_value("1+2*3*(4-5+6)/7-8", val); - REQUIRE(r.ret == true); - REQUIRE(val == -3); + REQUIRE(r.ret == true); + REQUIRE(val == -3); } -TEST_CASE("Calculator test3", "[general]") -{ - // Parse syntax - parser parser(R"( +TEST_CASE("Calculator test3", "[general]") { + // Parse syntax + parser parser(R"( # Grammar for Calculator... EXPRESSION <- TERM (TERM_OPERATOR TERM)* TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* @@ -643,38 +589,41 @@ TEST_CASE("Calculator test3", "[general]") NUMBER <- [0-9]+ )"); - auto reduce = [](const SemanticValues& sv) -> long { - long ret = any_cast(sv[0]); - for (auto i = 1u; i < sv.size(); i += 2) { - auto num = any_cast(sv[i + 1]); - switch (any_cast(sv[i])) { - case '+': ret += num; break; - case '-': ret -= num; break; - case '*': ret *= num; break; - case '/': ret /= num; break; - } - } - return ret; - }; + auto reduce = [](const SemanticValues &vs) -> long { + long ret = std::any_cast(vs[0]); + for (auto i = 1u; i < vs.size(); i += 2) { + auto num = std::any_cast(vs[i + 1]); + switch (std::any_cast(vs[i])) { + case '+': ret += num; break; + case '-': ret -= num; break; + case '*': ret *= num; break; + case '/': ret /= num; break; + } + } + return ret; + }; - // Setup actions - parser["EXPRESSION"] = reduce; - parser["TERM"] = reduce; - parser["TERM_OPERATOR"] = [](const SemanticValues& sv) { return static_cast(*sv.c_str()); }; - parser["FACTOR_OPERATOR"] = [](const SemanticValues& sv) { return static_cast(*sv.c_str()); }; - parser["NUMBER"] = [](const SemanticValues& sv) { return stol(sv.str(), nullptr, 10); }; + // Setup actions + parser["EXPRESSION"] = reduce; + parser["TERM"] = reduce; + parser["TERM_OPERATOR"] = [](const SemanticValues &vs) { + return static_cast(*vs.sv().data()); + }; + parser["FACTOR_OPERATOR"] = [](const SemanticValues &vs) { + return static_cast(*vs.sv().data()); + }; + parser["NUMBER"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; - // Parse - long val; - auto ret = parser.parse("1+2*3*(4-5+6)/7-8", val); + // Parse + long val; + auto ret = parser.parse("1+2*3*(4-5+6)/7-8", val); - REQUIRE(ret == true); - REQUIRE(val == -3); + REQUIRE(ret == true); + REQUIRE(val == -3); } -TEST_CASE("Calculator test with AST", "[general]") -{ - parser parser(R"( +TEST_CASE("Calculator test with AST", "[general]") { + parser parser(R"( EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ @@ -684,40 +633,41 @@ TEST_CASE("Calculator test with AST", "[general]") ~_ <- [ \t\r\n]* )"); - parser.enable_ast(); - - std::function eval = [&](const Ast& ast) { - if (ast.name == "NUMBER") { - return stol(ast.token); - } else { - const auto& nodes = ast.nodes; - auto result = eval(*nodes[0]); - for (auto i = 1u; i < nodes.size(); i += 2) { - auto num = eval(*nodes[i + 1]); - auto ope = nodes[i]->token[0]; - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; + parser.enable_ast(); + + std::function eval = [&](const Ast &ast) { + if (ast.name == "NUMBER") { + return ast.token_to_number(); + } else { + const auto &nodes = ast.nodes; + auto result = eval(*nodes[0]); + for (auto i = 1u; i < nodes.size(); i += 2) { + auto num = eval(*nodes[i + 1]); + auto ope = nodes[i]->token[0]; + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; } - }; + } + return result; + } + }; - std::shared_ptr ast; - auto ret = parser.parse("1+2*3*(4-5+6)/7-8", ast); - ast = AstOptimizer(true).optimize(ast); - auto val = eval(*ast); + std::shared_ptr ast; + auto ret = parser.parse("1+2*3*(4-5+6)/7-8", ast); + ast = AstOptimizer(true).optimize(ast); + auto val = eval(*ast); - REQUIRE(ret == true); - REQUIRE(val == -3); + REQUIRE(ret == true); + REQUIRE(val == -3); } TEST_CASE("Calculator test with combinators and AST", "[general]") { // Construct grammer - AST_DEFINITIONS(EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, NUMBER); + AST_DEFINITIONS(EXPRESSION, TERM, FACTOR, TERM_OPERATOR, FACTOR_OPERATOR, + NUMBER); EXPRESSION <= seq(TERM, zom(seq(TERM_OPERATOR, TERM))); TERM <= seq(FACTOR, zom(seq(FACTOR_OPERATOR, FACTOR))); @@ -728,7 +678,7 @@ TEST_CASE("Calculator test with combinators and AST", "[general]") { std::function eval = [&](const Ast &ast) { if (ast.name == "NUMBER") { - return stol(ast.token); + return ast.token_to_number(); } else { const auto &nodes = ast.nodes; auto result = eval(*nodes[0]); @@ -755,28 +705,26 @@ TEST_CASE("Calculator test with combinators and AST", "[general]") { REQUIRE(val == -3); } -TEST_CASE("Ignore semantic value test", "[general]") -{ - parser parser(R"( +TEST_CASE("Ignore semantic value test", "[general]") { + parser parser(R"( START <- ~HELLO WORLD HELLO <- 'Hello' _ WORLD <- 'World' _ _ <- [ \t\r\n]* )"); - parser.enable_ast(); + parser.enable_ast(); - std::shared_ptr ast; - auto ret = parser.parse("Hello World", ast); + std::shared_ptr ast; + auto ret = parser.parse("Hello World", ast); - REQUIRE(ret == true); - REQUIRE(ast->nodes.size() == 1); - REQUIRE(ast->nodes[0]->name == "WORLD"); + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 1); + REQUIRE(ast->nodes[0]->name == "WORLD"); } -TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]") -{ - parser parser(R"( +TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]") { + parser parser(R"( START <- _ !DUMMY HELLO_WORLD '.' HELLO_WORLD <- HELLO 'World' _ HELLO <- 'Hello' _ @@ -784,109 +732,102 @@ TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]") ~_ <- [ \t\r\n]* )"); - parser.enable_ast(); + parser.enable_ast(); - std::shared_ptr ast; - auto ret = parser.parse("Hello World.", ast); + std::shared_ptr ast; + auto ret = parser.parse("Hello World.", ast); - REQUIRE(ret == true); - REQUIRE(ast->nodes.size() == 1); - REQUIRE(ast->nodes[0]->name == "HELLO_WORLD"); + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 1); + REQUIRE(ast->nodes[0]->name == "HELLO_WORLD"); } -TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]") -{ - parser parser(R"( +TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]") { + parser parser(R"( START <- _ &HELLO HELLO_WORLD '.' HELLO_WORLD <- HELLO 'World' _ HELLO <- 'Hello' _ ~_ <- [ \t\r\n]* )"); - parser.enable_ast(); + parser.enable_ast(); - std::shared_ptr ast; - auto ret = parser.parse("Hello World.", ast); + std::shared_ptr ast; + auto ret = parser.parse("Hello World.", ast); - REQUIRE(ret == true); - REQUIRE(ast->nodes.size() == 1); - REQUIRE(ast->nodes[0]->name == "HELLO_WORLD"); + REQUIRE(ret == true); + REQUIRE(ast->nodes.size() == 1); + REQUIRE(ast->nodes[0]->name == "HELLO_WORLD"); } -TEST_CASE("Literal token on AST test1", "[general]") -{ - parser parser(R"( +TEST_CASE("Literal token on AST test1", "[general]") { + parser parser(R"( STRING_LITERAL <- '"' (('\\"' / '\\t' / '\\n') / (!["] .))* '"' )"); - parser.enable_ast(); + parser.enable_ast(); - std::shared_ptr ast; - auto ret = parser.parse(R"("a\tb")", ast); + std::shared_ptr ast; + auto ret = parser.parse(R"("a\tb")", ast); - REQUIRE(ret == true); - REQUIRE(ast->is_token == true); - REQUIRE(ast->token == R"("a\tb")"); - REQUIRE(ast->nodes.empty()); + REQUIRE(ret == true); + REQUIRE(ast->is_token == true); + REQUIRE(ast->token == R"("a\tb")"); + REQUIRE(ast->nodes.empty()); } -TEST_CASE("Literal token on AST test2", "[general]") -{ - parser parser(R"( +TEST_CASE("Literal token on AST test2", "[general]") { + parser parser(R"( STRING_LITERAL <- '"' (ESC / CHAR)* '"' ESC <- ('\\"' / '\\t' / '\\n') CHAR <- (!["] .) )"); - parser.enable_ast(); + parser.enable_ast(); - std::shared_ptr ast; - auto ret = parser.parse(R"("a\tb")", ast); + std::shared_ptr ast; + auto ret = parser.parse(R"("a\tb")", ast); - REQUIRE(ret == true); - REQUIRE(ast->is_token == false); - REQUIRE(ast->token.empty()); - REQUIRE(ast->nodes.size() == 3); + REQUIRE(ret == true); + REQUIRE(ast->is_token == false); + REQUIRE(ast->token.empty()); + REQUIRE(ast->nodes.size() == 3); } -TEST_CASE("Literal token on AST test3", "[general]") -{ - parser parser(R"( +TEST_CASE("Literal token on AST test3", "[general]") { + parser parser(R"( STRING_LITERAL <- < '"' (ESC / CHAR)* '"' > ESC <- ('\\"' / '\\t' / '\\n') CHAR <- (!["] .) )"); - parser.enable_ast(); + parser.enable_ast(); - std::shared_ptr ast; - auto ret = parser.parse(R"("a\tb")", ast); + std::shared_ptr ast; + auto ret = parser.parse(R"("a\tb")", ast); - REQUIRE(ret == true); - REQUIRE(ast->is_token == true); - REQUIRE(ast->token == R"("a\tb")"); - REQUIRE(ast->nodes.empty()); + REQUIRE(ret == true); + REQUIRE(ast->is_token == true); + REQUIRE(ast->token == R"("a\tb")"); + REQUIRE(ast->nodes.empty()); } -TEST_CASE("Missing missing definitions test", "[general]") -{ - parser parser(R"( +TEST_CASE("Missing missing definitions test", "[general]") { + parser parser(R"( A <- B C )"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("Definition duplicates test", "[general]") -{ - parser parser(R"( +TEST_CASE("Definition duplicates test", "[general]") { + parser parser(R"( A <- '' A <- '' )"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("Semantic values test", "[general]") -{ - parser parser(R"( +TEST_CASE("Semantic values test", "[general]") { + parser parser(R"( term <- ( a b c x )? a b c a <- 'a' b <- 'b' @@ -894,108 +835,104 @@ TEST_CASE("Semantic values test", "[general]") x <- 'x' )"); - for (const auto& rule: parser.get_rule_names()){ - parser[rule.c_str()] = [rule](const SemanticValues& sv, any&) { - if (rule == "term") { - REQUIRE(any_cast(sv[0]) == "a at 0"); - REQUIRE(any_cast(sv[1]) == "b at 1"); - REQUIRE(any_cast(sv[2]) == "c at 2"); - return std::string(); - } else { - return rule + " at " + std::to_string(sv.c_str() - sv.ss); - } - }; - } + for (const auto &rule : parser.get_rule_names()) { + parser[rule.data()] = [rule](const SemanticValues &vs, std::any &) { + if (rule == "term") { + REQUIRE(std::any_cast(vs[0]) == "a at 0"); + REQUIRE(std::any_cast(vs[1]) == "b at 1"); + REQUIRE(std::any_cast(vs[2]) == "c at 2"); + return std::string(); + } else { + return rule + " at " + std::to_string(vs.sv().data() - vs.ss); + } + }; + } - REQUIRE(parser.parse("abc")); + REQUIRE(parser.parse("abc")); } -TEST_CASE("Ordered choice count", "[general]") -{ - parser parser(R"( +TEST_CASE("Ordered choice count", "[general]") { + parser parser(R"( S <- 'a' / 'b' )"); - parser["S"] = [](const SemanticValues& sv) { - REQUIRE(sv.choice() == 1); - REQUIRE(sv.choice_count() == 2); - }; + parser["S"] = [](const SemanticValues &vs) { + REQUIRE(vs.choice() == 1); + REQUIRE(vs.choice_count() == 2); + }; - parser.parse("b"); + parser.parse("b"); } -TEST_CASE("Ordered choice count 2", "[general]") -{ - parser parser(R"( +TEST_CASE("Ordered choice count 2", "[general]") { + parser parser(R"( S <- ('a' / 'b')* )"); - parser["S"] = [](const SemanticValues& sv) { - REQUIRE(sv.choice() == 0); - REQUIRE(sv.choice_count() == 0); - }; + parser["S"] = [](const SemanticValues &vs) { + REQUIRE(vs.choice() == 0); + REQUIRE(vs.choice_count() == 0); + }; - parser.parse("b"); + parser.parse("b"); } -TEST_CASE("Semantic value tag", "[general]") -{ - parser parser(R"( +TEST_CASE("Semantic value tag", "[general]") { + parser parser(R"( S <- A? B* C? A <- 'a' B <- 'b' C <- 'c' )"); - { - using namespace udl; - parser["S"] = [](const SemanticValues& sv) { - REQUIRE(sv.size() == 1); - REQUIRE(sv.tags.size() == 1); - REQUIRE(sv.tags[0] == "C"_); - }; - auto ret = parser.parse("c"); - REQUIRE(ret == true); - } - - { - using namespace udl; - parser["S"] = [](const SemanticValues& sv) { - REQUIRE(sv.size() == 2); - REQUIRE(sv.tags.size() == 2); - REQUIRE(sv.tags[0] == "B"_); - REQUIRE(sv.tags[1] == "B"_); - }; - auto ret = parser.parse("bb"); - REQUIRE(ret == true); - } - - { - using namespace udl; - parser["S"] = [](const SemanticValues& sv) { - REQUIRE(sv.size() == 2); - REQUIRE(sv.tags.size() == 2); - REQUIRE(sv.tags[0] == "A"_); - REQUIRE(sv.tags[1] == "C"_); - }; - auto ret = parser.parse("ac"); - REQUIRE(ret == true); - } + { + using namespace udl; + parser["S"] = [](const SemanticValues &vs) { + REQUIRE(vs.size() == 1); + REQUIRE(vs.tags.size() == 1); + REQUIRE(vs.tags[0] == "C"_); + }; + auto ret = parser.parse("c"); + REQUIRE(ret == true); + } + + { + using namespace udl; + parser["S"] = [](const SemanticValues &vs) { + REQUIRE(vs.size() == 2); + REQUIRE(vs.tags.size() == 2); + REQUIRE(vs.tags[0] == "B"_); + REQUIRE(vs.tags[1] == "B"_); + }; + auto ret = parser.parse("bb"); + REQUIRE(ret == true); + } + + { + using namespace udl; + parser["S"] = [](const SemanticValues &vs) { + REQUIRE(vs.size() == 2); + REQUIRE(vs.tags.size() == 2); + REQUIRE(vs.tags[0] == "A"_); + REQUIRE(vs.tags[1] == "C"_); + }; + auto ret = parser.parse("ac"); + REQUIRE(ret == true); + } } -TEST_CASE("Negated Class test", "[general]") -{ - parser parser(R"( +TEST_CASE("Negated Class test", "[general]") { + parser parser(R"( ROOT <- [^a-z_]+ )"); - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); - REQUIRE(parser.parse("ABC123")); - REQUIRE_FALSE(parser.parse("ABcZ")); - REQUIRE_FALSE(parser.parse("ABCZ_")); - REQUIRE_FALSE(parser.parse("")); + REQUIRE(parser.parse("ABC123")); + REQUIRE_FALSE(parser.parse("ABcZ")); + REQUIRE_FALSE(parser.parse("ABCZ_")); + REQUIRE_FALSE(parser.parse("")); } // vim: et ts=4 sw=4 cin cino={1s ff=unix diff --git a/test/test2.cc b/test/test2.cc index 2ee83f7..4c60112 100644 --- a/test/test2.cc +++ b/test/test2.cc @@ -98,100 +98,91 @@ TEST_CASE("Infinite loop 1", "[infinite loop]") WH <- [ \t]* )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Infinite loop 2", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Infinite loop 2", "[infinite loop]") { + parser pg(R"( ROOT <- WH TOKEN+ WH TOKEN <- [a-z0-9]* WH <- [ \t]* )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Infinite loop 3", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Infinite loop 3", "[infinite loop]") { + parser pg(R"( ROOT <- WH TOKEN* WH TOKEN <- !'word1' WH <- [ \t]* )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Infinite loop 4", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Infinite loop 4", "[infinite loop]") { + parser pg(R"( ROOT <- WH TOKEN* WH TOKEN <- &'word1' WH <- [ \t]* )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Infinite loop 5", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Infinite loop 5", "[infinite loop]") { + parser pg(R"( Numbers <- Number* Number <- [0-9]+ / Spacing Spacing <- ' ' / '\t' / '\n' / EOF # EOF is empty EOF <- !. )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Infinite loop 6", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Infinite loop 6", "[infinite loop]") { + parser pg(R"( S <- ''* )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Infinite loop 7", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Infinite loop 7", "[infinite loop]") { + parser pg(R"( S <- A* A <- '' )"); - REQUIRE(!pg); + REQUIRE(!pg); } -TEST_CASE("Not infinite 1", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Not infinite 1", "[infinite loop]") { + parser pg(R"( Numbers <- Number* EOF Number <- [0-9]+ / Spacing Spacing <- ' ' / '\t' / '\n' EOF <- !. )"); - REQUIRE(!!pg); // OK + REQUIRE(!!pg); // OK } -TEST_CASE("Not infinite 2", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Not infinite 2", "[infinite loop]") { + parser pg(R"( ROOT <- _ ('[' TAG_NAME ']' _)* # In a sequence operator, if there is at least one non-empty element, we can treat it as non-empty TAG_NAME <- (!']' .)+ _ <- [ \t]* )"); - REQUIRE(!!pg); // OK + REQUIRE(!!pg); // OK } -TEST_CASE("Not infinite 3", "[infinite loop]") -{ - parser pg(R"( +TEST_CASE("Not infinite 3", "[infinite loop]") { + parser pg(R"( EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ # Recursive... @@ -201,12 +192,11 @@ TEST_CASE("Not infinite 3", "[infinite loop]") _ <- [ \t\r\n]* )"); - REQUIRE(!!pg); // OK + REQUIRE(!!pg); // OK } -TEST_CASE("Precedence climbing", "[precedence]") -{ - parser parser(R"( +TEST_CASE("Precedence climbing", "[precedence]") { + parser parser(R"( START <- _ EXPRESSION EXPRESSION <- ATOM (OPERATOR ATOM)* { precedence @@ -220,52 +210,51 @@ TEST_CASE("Precedence climbing", "[precedence]") T(S) <- < S > _ )"); - parser.enable_packrat_parsing(); - - // Setup actions - parser["EXPRESSION"] = [](const SemanticValues& sv) -> long { - auto result = any_cast(sv[0]); - if (sv.size() > 1) { - auto ope = any_cast(sv[1]); - auto num = any_cast(sv[2]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; - }; - parser["OPERATOR"] = [](const SemanticValues& sv) { return *sv.c_str(); }; - parser["NUMBER"] = [](const SemanticValues& sv) { return atol(sv.c_str()); }; - - bool ret = parser; - REQUIRE(ret == true); - - { - auto expr = " 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "; - long val = 0; - ret = parser.parse(expr, val); + parser.enable_packrat_parsing(); - REQUIRE(ret == true); - REQUIRE(val == -3); + // Setup actions + parser["EXPRESSION"] = [](const SemanticValues &vs) -> long { + auto result = std::any_cast(vs[0]); + if (vs.size() > 1) { + auto ope = std::any_cast(vs[1]); + auto num = std::any_cast(vs[2]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; + } } + return result; + }; + parser["OPERATOR"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + parser["NUMBER"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; + + bool ret = parser; + REQUIRE(ret == true); - { - auto expr = "-1+-2--3"; // -1 + -2 - -3 = 0 - long val = 0; - ret = parser.parse(expr, val); + { + auto expr = " 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "; + long val = 0; + ret = parser.parse(expr, val); - REQUIRE(ret == true); - REQUIRE(val == 0); - } + REQUIRE(ret == true); + REQUIRE(val == -3); + } + + { + auto expr = "-1+-2--3"; // -1 + -2 - -3 = 0 + long val = 0; + ret = parser.parse(expr, val); + + REQUIRE(ret == true); + REQUIRE(val == 0); + } } -TEST_CASE("Precedence climbing with macro", "[precedence]") -{ - // Create a PEG parser - parser parser(R"( +TEST_CASE("Precedence climbing with macro", "[precedence]") { + // Create a PEG parser + parser parser(R"( EXPRESSION <- INFIX_EXPRESSION(ATOM, OPERATOR) INFIX_EXPRESSION(A, O) <- A (O A)* { precedence @@ -278,51 +267,50 @@ TEST_CASE("Precedence climbing with macro", "[precedence]") %whitespace <- [ \t]* )"); - parser.enable_packrat_parsing(); + parser.enable_packrat_parsing(); - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); - // Setup actions - parser["INFIX_EXPRESSION"] = [](const SemanticValues& sv) -> long { - auto result = any_cast(sv[0]); - if (sv.size() > 1) { - auto ope = any_cast(sv[1]); - auto num = any_cast(sv[2]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; - }; - parser["OPERATOR"] = [](const SemanticValues& sv) { return *sv.c_str(); }; - parser["NUMBER"] = [](const SemanticValues& sv) { return atol(sv.c_str()); }; - - { - auto expr = " 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "; - long val = 0; - ret = parser.parse(expr, val); - - REQUIRE(ret == true); - REQUIRE(val == -3); + // Setup actions + parser["INFIX_EXPRESSION"] = [](const SemanticValues &vs) -> long { + auto result = std::any_cast(vs[0]); + if (vs.size() > 1) { + auto ope = std::any_cast(vs[1]); + auto num = std::any_cast(vs[2]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; + } } + return result; + }; + parser["OPERATOR"] = [](const SemanticValues &vs) { return *vs.sv().data(); }; + parser["NUMBER"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; - { - auto expr = "-1+-2--3"; // -1 + -2 - -3 = 0 - long val = 0; - ret = parser.parse(expr, val); + { + auto expr = " 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "; + long val = 0; + ret = parser.parse(expr, val); - REQUIRE(ret == true); - REQUIRE(val == 0); - } + REQUIRE(ret == true); + REQUIRE(val == -3); + } + + { + auto expr = "-1+-2--3"; // -1 + -2 - -3 = 0 + long val = 0; + ret = parser.parse(expr, val); + + REQUIRE(ret == true); + REQUIRE(val == 0); + } } -TEST_CASE("Precedence climbing error1", "[precedence]") -{ - parser parser(R"( +TEST_CASE("Precedence climbing error1", "[precedence]") { + parser parser(R"( START <- _ EXPRESSION EXPRESSION <- ATOM (OPERATOR ATOM1)* { precedence @@ -337,13 +325,12 @@ TEST_CASE("Precedence climbing error1", "[precedence]") T(S) <- < S > _ )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Precedence climbing error2", "[precedence]") -{ - parser parser(R"( +TEST_CASE("Precedence climbing error2", "[precedence]") { + parser parser(R"( START <- _ EXPRESSION EXPRESSION <- ATOM OPERATOR ATOM { precedence @@ -357,12 +344,12 @@ TEST_CASE("Precedence climbing error2", "[precedence]") T(S) <- < S > _ )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } TEST_CASE("Precedence climbing error3", "[precedence]") { - parser parser(R"( + parser parser(R"( EXPRESSION <- PRECEDENCE_PARSING(ATOM, OPERATOR) PRECEDENCE_PARSING(A, O) <- A (O A)+ { precedence @@ -375,26 +362,25 @@ TEST_CASE("Precedence climbing error3", "[precedence]") { %whitespace <- [ \t]* )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } TEST_CASE("Packrat parser test with %whitespace%", "[packrat]") { - peg::parser parser(R"( + peg::parser parser(R"( ROOT <- 'a' %whitespace <- SPACE* SPACE <- ' ' )"); - parser.enable_packrat_parsing(); + parser.enable_packrat_parsing(); - auto ret = parser.parse("a"); - REQUIRE(ret == true); + auto ret = parser.parse("a"); + REQUIRE(ret == true); } -TEST_CASE("Packrat parser test with macro", "[packrat]") -{ - parser parser(R"( +TEST_CASE("Packrat parser test with macro", "[packrat]") { + parser parser(R"( EXPRESSION <- _ LIST(TERM, TERM_OPERATOR) TERM <- LIST(FACTOR, FACTOR_OPERATOR) FACTOR <- NUMBER / T('(') EXPRESSION T(')') @@ -406,13 +392,14 @@ TEST_CASE("Packrat parser test with macro", "[packrat]") T(S) <- < S > _ )"); - parser.enable_packrat_parsing(); + parser.enable_packrat_parsing(); - auto ret = parser.parse(" 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "); - REQUIRE(ret == true); + auto ret = parser.parse(" 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "); + REQUIRE(ret == true); } -TEST_CASE("Packrat parser test with precedence expression parser", "[packrat]") { +TEST_CASE("Packrat parser test with precedence expression parser", + "[packrat]") { peg::parser parser(R"( Expression <- Atom (Operator Atom)* { precedence L + - L * / } Atom <- _? Number _? @@ -430,81 +417,74 @@ TEST_CASE("Packrat parser test with precedence expression parser", "[packrat]") REQUIRE(ret == true); } -TEST_CASE("Backreference test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Backreference test", "[backreference]") { + parser parser(R"( START <- _ LQUOTE < (!RQUOTE .)* > RQUOTE _ LQUOTE <- 'R"' $delm< [a-zA-Z]* > '(' RQUOTE <- ')' $delm '"' ~_ <- [ \t\r\n]* )"); - std::string token; - parser["START"] = [&](const SemanticValues& sv) { - token = sv.token(); - }; + std::string token; + parser["START"] = [&](const SemanticValues &vs) { token = vs.token(); }; - { - token.clear(); - auto ret = parser.parse(R"delm( + { + token.clear(); + auto ret = parser.parse(R"delm( R"("hello world")" )delm"); - REQUIRE(ret == true); - REQUIRE(token == "\"hello world\""); - } + REQUIRE(ret == true); + REQUIRE(token == "\"hello world\""); + } - { - token.clear(); - auto ret = parser.parse(R"delm( + { + token.clear(); + auto ret = parser.parse(R"delm( R"foo("(hello world)")foo" )delm"); - REQUIRE(ret == true); - REQUIRE(token == "\"(hello world)\""); - } + REQUIRE(ret == true); + REQUIRE(token == "\"(hello world)\""); + } - { - token.clear(); - auto ret = parser.parse(R"delm( + { + token.clear(); + auto ret = parser.parse(R"delm( R"foo("(hello world)foo")foo" )delm"); - REQUIRE(ret == false); - REQUIRE(token == "\"(hello world"); - } + REQUIRE(ret == false); + REQUIRE(token == "\"(hello world"); + } - { - token.clear(); - auto ret = parser.parse(R"delm( + { + token.clear(); + auto ret = parser.parse(R"delm( R"foo("(hello world)")bar" )delm"); - REQUIRE(ret == false); - REQUIRE(token.empty()); - } + REQUIRE(ret == false); + REQUIRE(token.empty()); + } } -TEST_CASE("Invalid backreference test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Invalid backreference test", "[backreference]") { + parser parser(R"( START <- _ LQUOTE (!RQUOTE .)* RQUOTE _ LQUOTE <- 'R"' $delm< [a-zA-Z]* > '(' RQUOTE <- ')' $delm2 '"' ~_ <- [ \t\r\n]* )"); - REQUIRE_THROWS_AS( - parser.parse(R"delm( + REQUIRE_THROWS_AS(parser.parse(R"delm( R"foo("(hello world)")foo" )delm"), - std::runtime_error); + std::runtime_error); } - -TEST_CASE("Nested capture test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Nested capture test", "[backreference]") { + parser parser(R"( ROOT <- CONTENT CONTENT <- (ELEMENT / TEXT)* ELEMENT <- $(STAG CONTENT ETAG) @@ -515,15 +495,14 @@ TEST_CASE("Nested capture test", "[backreference]") TEXT_DATA <- ![<] . )"); - REQUIRE(parser.parse("This is a test text.")); - REQUIRE(!parser.parse("This is a test text.")); - REQUIRE(!parser.parse("This is a test text.")); - REQUIRE(!parser.parse("This is a test text.")); + REQUIRE(parser.parse("This is a test text.")); + REQUIRE(!parser.parse("This is a test text.")); + REQUIRE(!parser.parse("This is a test text.")); + REQUIRE(!parser.parse("This is a test text.")); } -TEST_CASE("Backreference with Prioritized Choice test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Backreference with Prioritized Choice test", "[backreference]") { + parser parser(R"( TREE <- WRONG_BRANCH / CORRECT_BRANCH WRONG_BRANCH <- BRANCH THAT IS_capture WRONG CORRECT_BRANCH <- BRANCH THAT IS_backref CORRECT @@ -535,12 +514,11 @@ TEST_CASE("Backreference with Prioritized Choice test", "[backreference]") CORRECT <- 'correct' )"); - REQUIRE_THROWS_AS(parser.parse("branchthatiscorrect"), std::runtime_error); + REQUIRE_THROWS_AS(parser.parse("branchthatiscorrect"), std::runtime_error); } -TEST_CASE("Backreference with Zero or More test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Backreference with Zero or More test", "[backreference]") { + parser parser(R"( TREE <- WRONG_BRANCH* CORRECT_BRANCH WRONG_BRANCH <- BRANCH THAT IS_capture WRONG CORRECT_BRANCH <- BRANCH THAT IS_backref CORRECT @@ -552,17 +530,19 @@ TEST_CASE("Backreference with Zero or More test", "[backreference]") CORRECT <- 'correct' )"); - REQUIRE(parser.parse("branchthatiswrongbranchthatiscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIswrongbranchthatiscorrect")); - REQUIRE(parser.parse("branchthatiswrongbranchthatIswrongbranchthatIscorrect")); - REQUIRE_THROWS_AS(parser.parse("branchthatiscorrect"), std::runtime_error); - REQUIRE_THROWS_AS(parser.parse("branchthatiswron_branchthatiscorrect"), std::runtime_error); + REQUIRE(parser.parse("branchthatiswrongbranchthatiscorrect")); + REQUIRE(!parser.parse("branchthatiswrongbranchthatIscorrect")); + REQUIRE( + !parser.parse("branchthatiswrongbranchthatIswrongbranchthatiscorrect")); + REQUIRE( + parser.parse("branchthatiswrongbranchthatIswrongbranchthatIscorrect")); + REQUIRE_THROWS_AS(parser.parse("branchthatiscorrect"), std::runtime_error); + REQUIRE_THROWS_AS(parser.parse("branchthatiswron_branchthatiscorrect"), + std::runtime_error); } -TEST_CASE("Backreference with One or More test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Backreference with One or More test", "[backreference]") { + parser parser(R"( TREE <- WRONG_BRANCH+ CORRECT_BRANCH WRONG_BRANCH <- BRANCH THAT IS_capture WRONG CORRECT_BRANCH <- BRANCH THAT IS_backref CORRECT @@ -574,17 +554,18 @@ TEST_CASE("Backreference with One or More test", "[backreference]") CORRECT <- 'correct' )"); - REQUIRE(parser.parse("branchthatiswrongbranchthatiscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIswrongbranchthatiscorrect")); - REQUIRE(parser.parse("branchthatiswrongbranchthatIswrongbranchthatIscorrect")); - REQUIRE(!parser.parse("branchthatiscorrect")); - REQUIRE(!parser.parse("branchthatiswron_branchthatiscorrect")); + REQUIRE(parser.parse("branchthatiswrongbranchthatiscorrect")); + REQUIRE(!parser.parse("branchthatiswrongbranchthatIscorrect")); + REQUIRE( + !parser.parse("branchthatiswrongbranchthatIswrongbranchthatiscorrect")); + REQUIRE( + parser.parse("branchthatiswrongbranchthatIswrongbranchthatIscorrect")); + REQUIRE(!parser.parse("branchthatiscorrect")); + REQUIRE(!parser.parse("branchthatiswron_branchthatiscorrect")); } -TEST_CASE("Backreference with Option test", "[backreference]") -{ - parser parser(R"( +TEST_CASE("Backreference with Option test", "[backreference]") { + parser parser(R"( TREE <- WRONG_BRANCH? CORRECT_BRANCH WRONG_BRANCH <- BRANCH THAT IS_capture WRONG CORRECT_BRANCH <- BRANCH THAT IS_backref CORRECT @@ -596,175 +577,157 @@ TEST_CASE("Backreference with Option test", "[backreference]") CORRECT <- 'correct' )"); - REQUIRE(parser.parse("branchthatiswrongbranchthatiscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIswrongbranchthatiscorrect")); - REQUIRE(!parser.parse("branchthatiswrongbranchthatIswrongbranchthatIscorrect")); - REQUIRE_THROWS_AS(parser.parse("branchthatiscorrect"), std::runtime_error); - REQUIRE_THROWS_AS(parser.parse("branchthatiswron_branchthatiscorrect"), std::runtime_error); + REQUIRE(parser.parse("branchthatiswrongbranchthatiscorrect")); + REQUIRE(!parser.parse("branchthatiswrongbranchthatIscorrect")); + REQUIRE( + !parser.parse("branchthatiswrongbranchthatIswrongbranchthatiscorrect")); + REQUIRE( + !parser.parse("branchthatiswrongbranchthatIswrongbranchthatIscorrect")); + REQUIRE_THROWS_AS(parser.parse("branchthatiscorrect"), std::runtime_error); + REQUIRE_THROWS_AS(parser.parse("branchthatiswron_branchthatiscorrect"), + std::runtime_error); } -TEST_CASE("Repetition {0}", "[repetition]") -{ - parser parser(R"( +TEST_CASE("Repetition {0}", "[repetition]") { + parser parser(R"( START <- '(' DIGIT{3} ') ' DIGIT{3} '-' DIGIT{4} DIGIT <- [0-9] )"); - REQUIRE(parser.parse("(123) 456-7890")); - REQUIRE(!parser.parse("(12a) 456-7890")); - REQUIRE(!parser.parse("(123) 45-7890")); - REQUIRE(!parser.parse("(123) 45-7a90")); + REQUIRE(parser.parse("(123) 456-7890")); + REQUIRE(!parser.parse("(12a) 456-7890")); + REQUIRE(!parser.parse("(123) 45-7890")); + REQUIRE(!parser.parse("(123) 45-7a90")); } -TEST_CASE("Repetition {2,4}", "[repetition]") -{ - parser parser(R"( +TEST_CASE("Repetition {2,4}", "[repetition]") { + parser parser(R"( START <- DIGIT{2,4} DIGIT <- [0-9] )"); - REQUIRE(!parser.parse("1")); - REQUIRE(parser.parse("12")); - REQUIRE(parser.parse("123")); - REQUIRE(parser.parse("1234")); - REQUIRE(!parser.parse("12345")); + REQUIRE(!parser.parse("1")); + REQUIRE(parser.parse("12")); + REQUIRE(parser.parse("123")); + REQUIRE(parser.parse("1234")); + REQUIRE(!parser.parse("12345")); } -TEST_CASE("Repetition {2,1}", "[repetition]") -{ - parser parser(R"( +TEST_CASE("Repetition {2,1}", "[repetition]") { + parser parser(R"( START <- DIGIT{2,1} # invalid range DIGIT <- [0-9] )"); - REQUIRE(!parser.parse("1")); - REQUIRE(parser.parse("12")); - REQUIRE(!parser.parse("123")); + REQUIRE(!parser.parse("1")); + REQUIRE(parser.parse("12")); + REQUIRE(!parser.parse("123")); } -TEST_CASE("Repetition {2,}", "[repetition]") -{ - parser parser(R"( +TEST_CASE("Repetition {2,}", "[repetition]") { + parser parser(R"( START <- DIGIT{2,} DIGIT <- [0-9] )"); - REQUIRE(!parser.parse("1")); - REQUIRE(parser.parse("12")); - REQUIRE(parser.parse("123")); - REQUIRE(parser.parse("1234")); + REQUIRE(!parser.parse("1")); + REQUIRE(parser.parse("12")); + REQUIRE(parser.parse("123")); + REQUIRE(parser.parse("1234")); } -TEST_CASE("Repetition {,2}", "[repetition]") -{ - parser parser(R"( +TEST_CASE("Repetition {,2}", "[repetition]") { + parser parser(R"( START <- DIGIT{,2} DIGIT <- [0-9] )"); - REQUIRE(parser.parse("1")); - REQUIRE(parser.parse("12")); - REQUIRE(!parser.parse("123")); - REQUIRE(!parser.parse("1234")); + REQUIRE(parser.parse("1")); + REQUIRE(parser.parse("12")); + REQUIRE(!parser.parse("123")); + REQUIRE(!parser.parse("1234")); } -TEST_CASE("Left recursive test", "[left recursive]") -{ - parser parser(R"( +TEST_CASE("Left recursive test", "[left recursive]") { + parser parser(R"( A <- A 'a' B <- A 'a' )"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("Left recursive with option test", "[left recursive]") -{ - parser parser(R"( +TEST_CASE("Left recursive with option test", "[left recursive]") { + parser parser(R"( A <- 'a' / 'b'? B 'c' B <- A )"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("Left recursive with zom test", "[left recursive]") -{ - parser parser(R"( +TEST_CASE("Left recursive with zom test", "[left recursive]") { + parser parser(R"( A <- 'a'* A* )"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("Left recursive with a ZOM content rule", "[left recursive]") -{ - parser parser(R"( +TEST_CASE("Left recursive with a ZOM content rule", "[left recursive]") { + parser parser(R"( A <- B B <- _ A _ <- ' '* # Zero or more )"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("Left recursive with empty string test", "[left recursive]") -{ - parser parser( - " A <- '' A" - ); +TEST_CASE("Left recursive with empty string test", "[left recursive]") { + parser parser(" A <- '' A"); - REQUIRE(!parser); + REQUIRE(!parser); } -TEST_CASE("User defined rule test", "[user rule]") -{ - auto g = parser(R"( +TEST_CASE("User defined rule test", "[user rule]") { + auto g = parser(R"( ROOT <- _ 'Hello' _ NAME '!' _ )", - { - { - "NAME", usr([](const char* s, size_t n, SemanticValues& /*sv*/, any& /*dt*/) -> size_t { - static std::vector names = { "PEG", "BNF" }; - for (const auto& name: names) { - if (name.size() <= n && !name.compare(0, name.size(), s, name.size())) { - return name.size(); - } - } - return static_cast(-1); - }) - }, - { - "~_", zom(cls(" \t\r\n")) - } - }); - - REQUIRE(g.parse(" Hello BNF! ") == true); -} - -TEST_CASE("Semantic predicate test", "[predicate]") -{ - parser parser("NUMBER <- [0-9]+"); - - parser["NUMBER"] = [](const SemanticValues& sv) { - auto val = stol(sv.token(), nullptr, 10); - if (val != 100) { - throw parse_error("value error!!"); - } - return val; - }; - - long val; - REQUIRE(parser.parse("100", val)); - REQUIRE(val == 100); - - parser.log = [](size_t line, size_t col, const std::string& msg) { - REQUIRE(line == 1); - REQUIRE(col == 1); - REQUIRE(msg == "value error!!"); - }; - REQUIRE(!parser.parse("200", val)); -} - -TEST_CASE("Japanese character", "[unicode]") -{ - peg::parser parser(u8R"( + {{"NAME", usr([](const char *s, size_t n, SemanticValues &, + std::any &) -> size_t { + static std::vector names = {"PEG", "BNF"}; + for (const auto &name : names) { + if (name.size() <= n && + !name.compare(0, name.size(), s, name.size())) { + return name.size(); + } + } + return static_cast(-1); + })}, + {"~_", zom(cls(" \t\r\n"))}}); + + REQUIRE(g.parse(" Hello BNF! ") == true); +} + +TEST_CASE("Semantic predicate test", "[predicate]") { + parser parser("NUMBER <- [0-9]+"); + + parser["NUMBER"] = [](const SemanticValues &vs) { + auto val = vs.token_to_number(); + if (val != 100) { throw parse_error("value error!!"); } + return val; + }; + + long val; + REQUIRE(parser.parse("100", val)); + REQUIRE(val == 100); + + parser.log = [](size_t line, size_t col, const std::string &msg) { + REQUIRE(line == 1); + REQUIRE(col == 1); + REQUIRE(msg == "value error!!"); + }; + REQUIRE(!parser.parse("200", val)); +} + +TEST_CASE("Japanese character", "[unicode]") { + peg::parser parser(u8R"( 文 <- 修飾語? 主語 述語 '。' 主語 <- 名詞 助詞 述語 <- 動詞 助詞 @@ -775,49 +738,46 @@ TEST_CASE("Japanese character", "[unicode]") 助詞 <- 'が' / 'を' / 'た' / 'ます' / 'に' )"); - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); - REQUIRE(parser.parse(u8R"(サーバーを復旧します。)")); + REQUIRE(parser.parse(u8R"(サーバーを復旧します。)")); } -TEST_CASE("dot with a code", "[unicode]") -{ - peg::parser parser(" S <- 'a' . 'b' "); - REQUIRE(parser.parse(u8R"(aあb)")); +TEST_CASE("dot with a code", "[unicode]") { + peg::parser parser(" S <- 'a' . 'b' "); + REQUIRE(parser.parse(u8R"(aあb)")); } -TEST_CASE("dot with a char", "[unicode]") -{ - peg::parser parser(" S <- 'a' . 'b' "); - REQUIRE(parser.parse(u8R"(aåb)")); +TEST_CASE("dot with a char", "[unicode]") { + peg::parser parser(" S <- 'a' . 'b' "); + REQUIRE(parser.parse(u8R"(aåb)")); } -TEST_CASE("character class", "[unicode]") -{ - peg::parser parser(R"( +TEST_CASE("character class", "[unicode]") { + peg::parser parser(R"( S <- 'a' [い-おAさC-Eた-とは] 'b' )"); - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); - REQUIRE(!parser.parse(u8R"(aあb)")); - REQUIRE(parser.parse(u8R"(aいb)")); - REQUIRE(parser.parse(u8R"(aうb)")); - REQUIRE(parser.parse(u8R"(aおb)")); - REQUIRE(!parser.parse(u8R"(aかb)")); - REQUIRE(parser.parse(u8R"(aAb)")); - REQUIRE(!parser.parse(u8R"(aBb)")); - REQUIRE(parser.parse(u8R"(aEb)")); - REQUIRE(!parser.parse(u8R"(aFb)")); - REQUIRE(!parser.parse(u8R"(aそb)")); - REQUIRE(parser.parse(u8R"(aたb)")); - REQUIRE(parser.parse(u8R"(aちb)")); - REQUIRE(parser.parse(u8R"(aとb)")); - REQUIRE(!parser.parse(u8R"(aなb)")); - REQUIRE(parser.parse(u8R"(aはb)")); - REQUIRE(!parser.parse(u8R"(a?b)")); + REQUIRE(!parser.parse(u8R"(aあb)")); + REQUIRE(parser.parse(u8R"(aいb)")); + REQUIRE(parser.parse(u8R"(aうb)")); + REQUIRE(parser.parse(u8R"(aおb)")); + REQUIRE(!parser.parse(u8R"(aかb)")); + REQUIRE(parser.parse(u8R"(aAb)")); + REQUIRE(!parser.parse(u8R"(aBb)")); + REQUIRE(parser.parse(u8R"(aEb)")); + REQUIRE(!parser.parse(u8R"(aFb)")); + REQUIRE(!parser.parse(u8R"(aそb)")); + REQUIRE(parser.parse(u8R"(aたb)")); + REQUIRE(parser.parse(u8R"(aちb)")); + REQUIRE(parser.parse(u8R"(aとb)")); + REQUIRE(!parser.parse(u8R"(aなb)")); + REQUIRE(parser.parse(u8R"(aはb)")); + REQUIRE(!parser.parse(u8R"(a?b)")); } #if 0 // TODO: Unicode Grapheme support @@ -828,77 +788,70 @@ TEST_CASE("dot with a grapheme", "[unicode]") } #endif -TEST_CASE("Macro simple test", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro simple test", "[macro]") { + parser parser(R"( S <- HELLO WORLD HELLO <- T('hello') WORLD <- T('world') T(a) <- a [ \t]* )"); - REQUIRE(parser.parse("hello \tworld ")); + REQUIRE(parser.parse("hello \tworld ")); } -TEST_CASE("Macro two parameters", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro two parameters", "[macro]") { + parser parser(R"( S <- HELLO_WORLD HELLO_WORLD <- T('hello', 'world') T(a, b) <- a [ \t]* b [ \t]* )"); - REQUIRE(parser.parse("hello \tworld ")); + REQUIRE(parser.parse("hello \tworld ")); } -TEST_CASE("Macro syntax error", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro syntax error", "[macro]") { + parser parser(R"( S <- T('hello') T (a) <- a [ \t]* )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Macro missing argument", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro missing argument", "[macro]") { + parser parser(R"( S <- T ('hello') T(a, b) <- a [ \t]* b )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Macro reference syntax error", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro reference syntax error", "[macro]") { + parser parser(R"( S <- T ('hello') T(a) <- a [ \t]* )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Macro invalid macro reference error", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro invalid macro reference error", "[macro]") { + parser parser(R"( S <- T('hello') T <- 'world' )"); - bool ret = parser; - REQUIRE(ret == false); + bool ret = parser; + REQUIRE(ret == false); } -TEST_CASE("Macro calculator", "[macro]") -{ - // Create a PEG parser - parser parser(R"( +TEST_CASE("Macro calculator", "[macro]") { + // Create a PEG parser + parser parser(R"( # Grammar for simple calculator... EXPRESSION <- _ LIST(TERM, TERM_OPERATOR) TERM <- LIST(FACTOR, FACTOR_OPERATOR) @@ -911,83 +864,83 @@ TEST_CASE("Macro calculator", "[macro]") T(S) <- < S > _ )"); - // Setup actions - auto reduce = [](const SemanticValues& sv) -> long { - auto result = any_cast(sv[0]); - for (auto i = 1u; i < sv.size(); i += 2) { - auto num = any_cast(sv[i + 1]); - auto ope = any_cast(sv[i]); - switch (ope) { - case '+': result += num; break; - case '-': result -= num; break; - case '*': result *= num; break; - case '/': result /= num; break; - } - } - return result; - }; - - parser["EXPRESSION"] = reduce; - parser["TERM"] = reduce; - parser["TERM_OPERATOR"] = [](const SemanticValues& sv) { return static_cast(*sv.c_str()); }; - parser["FACTOR_OPERATOR"] = [](const SemanticValues& sv) { return static_cast(*sv.c_str()); }; - parser["NUMBER"] = [](const SemanticValues& sv) { return atol(sv.c_str()); }; - - bool ret = parser; - REQUIRE(ret == true); + // Setup actions + auto reduce = [](const SemanticValues &vs) { + auto result = std::any_cast(vs[0]); + for (auto i = 1u; i < vs.size(); i += 2) { + auto num = std::any_cast(vs[i + 1]); + auto ope = std::any_cast(vs[i]); + switch (ope) { + case '+': result += num; break; + case '-': result -= num; break; + case '*': result *= num; break; + case '/': result /= num; break; + } + } + return result; + }; + + parser["EXPRESSION"] = reduce; + parser["TERM"] = reduce; + parser["TERM_OPERATOR"] = [](const SemanticValues &vs) { + return static_cast(*vs.sv().data()); + }; + parser["FACTOR_OPERATOR"] = [](const SemanticValues &vs) { + return static_cast(*vs.sv().data()); + }; + parser["NUMBER"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; - auto expr = " 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "; - long val = 0; - ret = parser.parse(expr, val); + bool ret = parser; + REQUIRE(ret == true); - REQUIRE(ret == true); - REQUIRE(val == -3); + auto expr = " 1 + 2 * 3 * (4 - 5 + 6) / 7 - 8 "; + long val = 0; + ret = parser.parse(expr, val); + + REQUIRE(ret == true); + REQUIRE(val == -3); } -TEST_CASE("Macro expression arguments", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro expression arguments", "[macro]") { + parser parser(R"( S <- M('hello' / 'Hello', 'world' / 'World') M(arg0, arg1) <- arg0 [ \t]+ arg1 )"); - REQUIRE(parser.parse("Hello world")); + REQUIRE(parser.parse("Hello world")); } -TEST_CASE("Macro recursive", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro recursive", "[macro]") { + parser parser(R"( S <- M('abc') M(s) <- !s / s ' ' M(s / '123') / s )"); - REQUIRE(parser.parse("")); - REQUIRE(parser.parse("abc")); - REQUIRE(parser.parse("abc abc")); - REQUIRE(parser.parse("abc 123 abc")); + REQUIRE(parser.parse("")); + REQUIRE(parser.parse("abc")); + REQUIRE(parser.parse("abc abc")); + REQUIRE(parser.parse("abc 123 abc")); } -TEST_CASE("Macro recursive2", "[macro]") -{ - auto syntaxes = std::vector{ - "S <- M('abc') M(s) <- !s / s ' ' M(s* '-' '123') / s", - "S <- M('abc') M(s) <- !s / s ' ' M(s+ '-' '123') / s", - "S <- M('abc') M(s) <- !s / s ' ' M(s? '-' '123') / s", - "S <- M('abc') M(s) <- !s / s ' ' M(&s s+ '-' '123') / s", - "S <- M('abc') M(s) <- !s / s ' ' M(s '-' !s '123') / s", - "S <- M('abc') M(s) <- !s / s ' ' M(< s > '-' '123') / s", - "S <- M('abc') M(s) <- !s / s ' ' M(~s '-' '123') / s", - }; - - for (const auto& syntax: syntaxes) { - parser parser(syntax); - REQUIRE(parser.parse("abc abc-123")); - } -} - -TEST_CASE("Macro exclusive modifiers", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro recursive2", "[macro]") { + auto syntaxes = std::vector{ + "S <- M('abc') M(s) <- !s / s ' ' M(s* '-' '123') / s", + "S <- M('abc') M(s) <- !s / s ' ' M(s+ '-' '123') / s", + "S <- M('abc') M(s) <- !s / s ' ' M(s? '-' '123') / s", + "S <- M('abc') M(s) <- !s / s ' ' M(&s s+ '-' '123') / s", + "S <- M('abc') M(s) <- !s / s ' ' M(s '-' !s '123') / s", + "S <- M('abc') M(s) <- !s / s ' ' M(< s > '-' '123') / s", + "S <- M('abc') M(s) <- !s / s ' ' M(~s '-' '123') / s", + }; + + for (const auto &syntax : syntaxes) { + parser parser(syntax); + REQUIRE(parser.parse("abc abc-123")); + } +} + +TEST_CASE("Macro exclusive modifiers", "[macro]") { + parser parser(R"( S <- Modifiers(!"") _ Modifiers(Appeared) <- (!Appeared) ( Token('public') Modifiers(Appeared / 'public') / @@ -998,17 +951,16 @@ TEST_CASE("Macro exclusive modifiers", "[macro]") _ <- [ \t\r\n]* )"); - REQUIRE(parser.parse("public")); - REQUIRE(parser.parse("static")); - REQUIRE(parser.parse("final")); - REQUIRE(parser.parse("public static final")); - REQUIRE(!parser.parse("public public")); - REQUIRE(!parser.parse("public static public")); + REQUIRE(parser.parse("public")); + REQUIRE(parser.parse("static")); + REQUIRE(parser.parse("final")); + REQUIRE(parser.parse("public static final")); + REQUIRE(!parser.parse("public public")); + REQUIRE(!parser.parse("public static public")); } -TEST_CASE("Macro token check test", "[macro]") -{ - parser parser(R"( +TEST_CASE("Macro token check test", "[macro]") { + parser parser(R"( # Grammar for simple calculator... EXPRESSION <- _ LIST(TERM, TERM_OPERATOR) TERM <- LIST(FACTOR, FACTOR_OPERATOR) @@ -1021,14 +973,14 @@ TEST_CASE("Macro token check test", "[macro]") T(S) <- < S > _ )"); - REQUIRE(parser["EXPRESSION"].is_token() == false); - REQUIRE(parser["TERM"].is_token() == false); - REQUIRE(parser["FACTOR"].is_token() == false); - REQUIRE(parser["FACTOR_OPERATOR"].is_token() == true); - REQUIRE(parser["NUMBER"].is_token() == true); - REQUIRE(parser["_"].is_token() == true); - REQUIRE(parser["LIST"].is_token() == false); - REQUIRE(parser["T"].is_token() == true); + REQUIRE(parser["EXPRESSION"].is_token() == false); + REQUIRE(parser["TERM"].is_token() == false); + REQUIRE(parser["FACTOR"].is_token() == false); + REQUIRE(parser["FACTOR_OPERATOR"].is_token() == true); + REQUIRE(parser["NUMBER"].is_token() == true); + REQUIRE(parser["_"].is_token() == true); + REQUIRE(parser["LIST"].is_token() == false); + REQUIRE(parser["T"].is_token() == true); } TEST_CASE("Macro passes an arg to another macro", "[macro]") { @@ -1053,66 +1005,63 @@ TEST_CASE("Nested macro call", "[macro]") { REQUIRE(parser.parse("val")); } -TEST_CASE("Nested macro call2", "[macro]") -{ - parser parser(R"( +TEST_CASE("Nested macro call2", "[macro]") { + parser parser(R"( START <- A('TestVal1', 'TestVal2')+ A(Aarg1, Aarg2) <- B(Aarg1) '#End' B(Barg1) <- '#' Barg1 )"); - REQUIRE(parser.parse("#TestVal1#End")); + REQUIRE(parser.parse("#TestVal1#End")); } TEST_CASE("Line information test", "[line information]") { - parser parser(R"( + parser parser(R"( S <- _ (WORD _)+ WORD <- [A-Za-z]+ ~_ <- [ \t\r\n]+ )"); - std::vector> locations; - parser["WORD"] = [&](const peg::SemanticValues& sv) { - locations.push_back(sv.line_info()); - }; + std::vector> locations; + parser["WORD"] = [&](const peg::SemanticValues &vs) { + locations.push_back(vs.line_info()); + }; - bool ret = parser; - REQUIRE(ret == true); + bool ret = parser; + REQUIRE(ret == true); - ret = parser.parse(" Mon Tue Wed \nThu Fri Sat\nSun\n"); - REQUIRE(ret == true); + ret = parser.parse(" Mon Tue Wed \nThu Fri Sat\nSun\n"); + REQUIRE(ret == true); - REQUIRE(locations[0] == std::make_pair(1, 2)); - REQUIRE(locations[1] == std::make_pair(1, 6)); - REQUIRE(locations[2] == std::make_pair(1, 10)); - REQUIRE(locations[3] == std::make_pair(2, 1)); - REQUIRE(locations[4] == std::make_pair(2, 6)); - REQUIRE(locations[5] == std::make_pair(2, 11)); - REQUIRE(locations[6] == std::make_pair(3, 1)); + REQUIRE(locations[0] == std::make_pair(1, 2)); + REQUIRE(locations[1] == std::make_pair(1, 6)); + REQUIRE(locations[2] == std::make_pair(1, 10)); + REQUIRE(locations[3] == std::make_pair(2, 1)); + REQUIRE(locations[4] == std::make_pair(2, 6)); + REQUIRE(locations[5] == std::make_pair(2, 11)); + REQUIRE(locations[6] == std::make_pair(3, 1)); } -TEST_CASE("Dictionary", "[dic]") -{ - parser parser(R"( +TEST_CASE("Dictionary", "[dic]") { + parser parser(R"( START <- 'This month is ' MONTH '.' MONTH <- 'Jan' | 'January' | 'Feb' | 'February' )"); - REQUIRE(parser.parse("This month is Jan.")); - REQUIRE(parser.parse("This month is January.")); - REQUIRE_FALSE(parser.parse("This month is Jannuary.")); - REQUIRE_FALSE(parser.parse("This month is .")); + REQUIRE(parser.parse("This month is Jan.")); + REQUIRE(parser.parse("This month is January.")); + REQUIRE_FALSE(parser.parse("This month is Jannuary.")); + REQUIRE_FALSE(parser.parse("This month is .")); } -TEST_CASE("Dictionary invalid", "[dic]") -{ - parser parser(R"( +TEST_CASE("Dictionary invalid", "[dic]") { + parser parser(R"( START <- 'This month is ' MONTH '.' MONTH <- 'Jan' | 'January' | [a-z]+ | 'Feb' | 'February' )"); - bool ret = parser; - REQUIRE_FALSE(ret); + bool ret = parser; + REQUIRE_FALSE(ret); } // vim: et ts=4 sw=4 cin cino={1s ff=unix