From fe7dcaa92fda9b71c6013f1da680226007dd9fca Mon Sep 17 00:00:00 2001 From: Salad Dais Date: Wed, 19 Oct 2022 12:08:42 +0000 Subject: [PATCH] Add support for parsing LSL from an in-memory buffer --- fuzz/fuzz.cc | 2 +- libtailslide/lslmini.hh | 1 + libtailslide/passes/desugaring.cc | 2 +- libtailslide/tailslide.cc | 39 ++++++++++++++++++++----------- libtailslide/tailslide.hh | 9 +++++-- tailslide_cli/main.cc | 2 +- tests/conformance.cc | 9 +++++++ tests/testutils.cc | 2 +- 8 files changed, 46 insertions(+), 20 deletions(-) diff --git a/fuzz/fuzz.cc b/fuzz/fuzz.cc index 22ec3e1..a58b875 100644 --- a/fuzz/fuzz.cc +++ b/fuzz/fuzz.cc @@ -26,7 +26,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { Tailslide::ScopedScriptParser parser(nullptr); try { - auto *script = parser.parseLSL(file); + auto *script = parser.parseLSLFile(file); if (script) { script->collectSymbols(); script->determineTypes(); diff --git a/libtailslide/lslmini.hh b/libtailslide/lslmini.hh index 667ce66..f02570b 100644 --- a/libtailslide/lslmini.hh +++ b/libtailslide/lslmini.hh @@ -44,6 +44,7 @@ struct ScriptContext { // any nodes created while this is false will be considered synthetic by default bool parsing = false; Tailslide::TailslideLType glloc {0}; + void *scanner = nullptr; }; struct Vector3 { diff --git a/libtailslide/passes/desugaring.cc b/libtailslide/passes/desugaring.cc index 2491c61..f78b30c 100644 --- a/libtailslide/passes/desugaring.cc +++ b/libtailslide/passes/desugaring.cc @@ -4,7 +4,7 @@ namespace Tailslide { // any time an int appears in a binary expression with these it must be promoted -std::vector SIBLINGS_CAUSING_INT_PROMOTION = { +static const std::vector SIBLINGS_CAUSING_INT_PROMOTION = { LST_FLOATINGPOINT, LST_VECTOR, LST_QUATERNION, diff --git a/libtailslide/tailslide.cc b/libtailslide/tailslide.cc index d72b302..47bfd55 100644 --- a/libtailslide/tailslide.cc +++ b/libtailslide/tailslide.cc @@ -4,8 +4,8 @@ #include "lslmini.tab.hh" int tailslide_lex_init_extra(Tailslide::ScriptContext *, void **); - void tailslide_set_in(FILE *, void *); +void *tailslide__scan_bytes ( const char *bytes, int len, void *); int tailslide_lex_destroy(void *); @@ -31,7 +31,7 @@ class FileCloser { FILE *_mFile; }; -LSLScript *ScopedScriptParser::parseLSL(const std::string &filename) { +LSLScript *ScopedScriptParser::parseLSLFile(const std::string &filename) { // can only be used to parse a single script. assert(!script); FILE *yyin = fopen(filename.c_str(), "rb"); @@ -39,35 +39,46 @@ LSLScript *ScopedScriptParser::parseLSL(const std::string &filename) { throw "couldn't open file"; } FileCloser closer(yyin); - auto result = parseLSL(yyin); - return result; + return parseLSLFile(yyin); +} + +LSLScript *ScopedScriptParser::parseLSLFile(FILE *yyin) { + initScanner(); + // set input file + tailslide_set_in(yyin, context.scanner); + parseInternal(); + return script; +} + +LSLScript *ScopedScriptParser::parseLSLBytes(const char *buf, int buf_len) { + initScanner(); + // set input file + tailslide__scan_bytes(buf, buf_len, context.scanner); + parseInternal(); + return script; } -LSLScript *ScopedScriptParser::parseLSL(FILE *yyin) { +void ScopedScriptParser::initScanner() { assert(!script); - void *scanner; // ScopedScriptParser owns the allocator and context instance because we can't // reasonably re-use Allocator instances with our current model of having // it magically pass along the current script context. allocator.setContext(&context); // initialize flex - tailslide_lex_init_extra(&context, &scanner); - - // set input file - tailslide_set_in(yyin, scanner); + tailslide_lex_init_extra(&context, &context.scanner); +} +void ScopedScriptParser::parseInternal() { // parse context.parsing = true; - tailslide_parse(scanner); + tailslide_parse(context.scanner); context.parsing = false; // clean up flex - tailslide_lex_destroy(scanner); + tailslide_lex_destroy(context.scanner); ast_sane = context.ast_sane; script = context.script; - - return script; } } diff --git a/libtailslide/tailslide.hh b/libtailslide/tailslide.hh index 4a36065..2cdd1b7 100644 --- a/libtailslide/tailslide.hh +++ b/libtailslide/tailslide.hh @@ -22,8 +22,13 @@ struct ScopedScriptParser { ScriptContext context; LSLSymbolTableManager table_manager; - LSLScript *parseLSL(FILE *yyin); - LSLScript *parseLSL(const std::string &filename); + LSLScript *parseLSLFile(FILE *yyin); + LSLScript *parseLSLFile(const std::string &filename); + LSLScript *parseLSLBytes(const char *buf, int buf_len); + + protected: + void initScanner(); + void parseInternal(); }; } diff --git a/tailslide_cli/main.cc b/tailslide_cli/main.cc index d284f45..1f49ad0 100644 --- a/tailslide_cli/main.cc +++ b/tailslide_cli/main.cc @@ -146,7 +146,7 @@ int main(int argc, char **argv) { if (check_assertions) logger->setCheckAssertions(true); - auto script = parser.parseLSL(yyin); + auto script = parser.parseLSLFile(yyin); if (yyin != nullptr) fclose(yyin); diff --git a/tests/conformance.cc b/tests/conformance.cc index ddbb6ae..046a281 100644 --- a/tests/conformance.cc +++ b/tests/conformance.cc @@ -302,4 +302,13 @@ TEST_CASE("jump_kinds.lsl") { checkTreeDumpOutput("jump_kinds.lsl", OptimizationOptions{}); } +static const char *SIMPLE_SCRIPT_BYTES = "default{state_entry(){}}"; + +TEST_CASE("Parse script buffer") { + ParserRef parser(new ScopedScriptParser(nullptr)); + auto script = parser->parseLSLBytes(SIMPLE_SCRIPT_BYTES, (int)strlen(SIMPLE_SCRIPT_BYTES)); + CHECK_NE(nullptr, script); + CHECK_EQ(0, parser->logger.getErrors()); +} + TEST_SUITE_END(); diff --git a/tests/testutils.cc b/tests/testutils.cc index 6c88ac5..21ba7d6 100644 --- a/tests/testutils.cc +++ b/tests/testutils.cc @@ -14,7 +14,7 @@ ParserRef runConformance(const char *name, bool allow_syntax_errors) ParserRef parser(new ScopedScriptParser(nullptr)); Logger *logger = &parser->logger; logger->setCheckAssertions(true); - parser->parseLSL(path); + parser->parseLSLFile(path); LSLScript *script = parser->script; if (script == nullptr)