From 7ffb5fc4fdafd37c1bc03ab24c2b7083d4424162 Mon Sep 17 00:00:00 2001 From: Lily Brown Date: Mon, 7 Feb 2022 12:08:43 -0800 Subject: [PATCH] Add Luau.Ast.CLI target (#345) Adds a `luau-ast` CLI that dumps Luau source to JSON. @asajeffrey and I are planning to use this functionality to construct an Agda model of the Luau type system/operational semantics, to allow formally proving properties of Luau's type systems. --- CLI/Ast.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 5 +++ Sources.cmake | 7 +++++ 3 files changed, 96 insertions(+) create mode 100644 CLI/Ast.cpp diff --git a/CLI/Ast.cpp b/CLI/Ast.cpp new file mode 100644 index 00000000..4ea46236 --- /dev/null +++ b/CLI/Ast.cpp @@ -0,0 +1,84 @@ +// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +#include + +#include "Luau/Common.h" +#include "Luau/Ast.h" +#include "Luau/JsonEncoder.h" +#include "Luau/Parser.h" +#include "Luau/ParseOptions.h" + +#include "FileUtils.h" + +static void displayHelp(const char* argv0) +{ + printf("Usage: %s [file]\n", argv0); +} + +static int assertionHandler(const char* expr, const char* file, int line, const char* function) +{ + printf("%s(%d): ASSERTION FAILED: %s\n", file, line, expr); + return 1; +} + +int main(int argc, char** argv) +{ + Luau::assertHandler() = assertionHandler; + + for (Luau::FValue* flag = Luau::FValue::list; flag; flag = flag->next) + if (strncmp(flag->name, "Luau", 4) == 0) + flag->value = true; + + if (argc >= 2 && strcmp(argv[1], "--help") == 0) + { + displayHelp(argv[0]); + return 0; + } + else if (argc < 2) + { + displayHelp(argv[0]); + return 1; + } + + const char* name = argv[1]; + std::optional maybeSource = std::nullopt; + if (strcmp(name, "-") == 0) + { + maybeSource = readStdin(); + } + else + { + maybeSource = readFile(name); + } + + if (!maybeSource) + { + fprintf(stderr, "Couldn't read source %s\n", name); + return 1; + } + + std::string source = *maybeSource; + + Luau::Allocator allocator; + Luau::AstNameTable names(allocator); + + Luau::ParseOptions options; + options.supportContinueStatement = true; + options.allowTypeAnnotations = true; + options.allowDeclarationSyntax = true; + + Luau::ParseResult parseResult = Luau::Parser::parse(source.data(), source.size(), names, allocator, options); + + if (parseResult.errors.size() > 0) + { + fprintf(stderr, "Parse errors were encountered:\n"); + for (const Luau::ParseError& error : parseResult.errors) + { + fprintf(stderr, " %s - %s\n", toString(error.getLocation()).c_str(), error.getMessage().c_str()); + } + fprintf(stderr, "\n"); + } + + printf("%s", Luau::toJson(parseResult.root).c_str()); + + return parseResult.errors.size() > 0 ? 1 : 0; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 881d3c3f..efef6e3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,12 @@ add_library(isocline STATIC) if(LUAU_BUILD_CLI) add_executable(Luau.Repl.CLI) add_executable(Luau.Analyze.CLI) + add_executable(Luau.Ast.CLI) # This also adds target `name` on Linux/macOS and `name.exe` on Windows set_target_properties(Luau.Repl.CLI PROPERTIES OUTPUT_NAME luau) set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze) + set_target_properties(Luau.Ast.CLI PROPERTIES OUTPUT_NAME luau-ast) endif() if(LUAU_BUILD_TESTS) @@ -98,6 +100,7 @@ endif() if(LUAU_BUILD_CLI) target_compile_options(Luau.Repl.CLI PRIVATE ${LUAU_OPTIONS}) target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS}) + target_compile_options(Luau.Ast.CLI PRIVATE ${LUAU_OPTIONS}) target_include_directories(Luau.Repl.CLI PRIVATE extern extern/isocline/include) @@ -111,6 +114,8 @@ if(LUAU_BUILD_CLI) endif() target_link_libraries(Luau.Analyze.CLI PRIVATE Luau.Analysis) + + target_link_libraries(Luau.Ast.CLI PRIVATE Luau.Ast Luau.Analysis) endif() if(LUAU_BUILD_TESTS) diff --git a/Sources.cmake b/Sources.cmake index b36b6db5..4ab1d98e 100644 --- a/Sources.cmake +++ b/Sources.cmake @@ -193,6 +193,13 @@ if(TARGET Luau.Analyze.CLI) CLI/Analyze.cpp) endif() +if (TARGET Luau.Ast.CLI) + target_sources(Luau.Ast.CLI PRIVATE + CLI/FileUtils.h + CLI/FileUtils.cpp + CLI/Ast.cpp) +endif() + if(TARGET Luau.UnitTest) # Luau.UnitTest Sources target_sources(Luau.UnitTest PRIVATE