lua_resource.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (c) 2012-2023 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include "core/containers/array.inl"
  7. #include "core/containers/hash_set.inl"
  8. #include "core/filesystem/file.h"
  9. #include "core/memory/temp_allocator.inl"
  10. #include "core/process.h"
  11. #include "core/strings/dynamic_string.inl"
  12. #include "core/strings/string_stream.inl"
  13. #include "core/strings/string_view.inl"
  14. #include "resource/compile_options.inl"
  15. #include "resource/lua_resource.h"
  16. #if CROWN_DEBUG
  17. #define LUAJIT_FLAGS "-bg" // Keep debug info
  18. #else
  19. #define LUAJIT_FLAGS "-b"
  20. #endif
  21. namespace crown
  22. {
  23. namespace lua_resource
  24. {
  25. const char *program(const LuaResource *lr)
  26. {
  27. return (char *)&lr[1];
  28. }
  29. } // namespace lua_resource
  30. #if CROWN_CAN_COMPILE
  31. namespace lua_resource_internal
  32. {
  33. static const char *skip_blanks(const char *lua)
  34. {
  35. lua = skip_spaces(lua);
  36. if (*lua == '-') {
  37. ++lua;
  38. if (*lua++ == '-' && *lua++ == '[' && *lua++ == '[') {
  39. // Multi-line comment.
  40. const char *mlc_end = strstr(lua, "--]]");
  41. if (mlc_end != NULL)
  42. lua = mlc_end + 4;
  43. else
  44. lua += strlen(lua);
  45. } else {
  46. // Single-line comment.
  47. while (*lua && *lua != '\n')
  48. ++lua;
  49. }
  50. }
  51. return skip_spaces(lua);
  52. }
  53. void find_requirements(HashSet<StringView> &requirements, const char *lua)
  54. {
  55. while (*lua) {
  56. lua = skip_blanks(lua);
  57. if (*lua == 'r') { // Find require()s.
  58. const char *require = strstr(lua, "require");
  59. if (!require) {
  60. ++lua;
  61. continue;
  62. }
  63. lua = skip_blanks(require + 7);
  64. if (*lua == '(')
  65. ++lua;
  66. lua = skip_blanks(lua);
  67. if (*lua == '\'' || *lua == '"') {
  68. const char *param_begin = lua + 1;
  69. const char *param_end = strchr(param_begin, *lua);
  70. if (param_end != NULL) {
  71. hash_set::insert(requirements
  72. , StringView(param_begin, param_end - param_begin)
  73. );
  74. lua = param_end + 1;
  75. }
  76. }
  77. } else if (*lua == '-' || isspace(*lua)) {
  78. lua = skip_blanks(lua);
  79. } else if (*lua) {
  80. ++lua;
  81. }
  82. }
  83. }
  84. s32 compile(CompileOptions &opts)
  85. {
  86. TempAllocator1024 ta;
  87. DynamicString lua_src(ta);
  88. DynamicString lua_out(ta);
  89. opts.absolute_path(lua_src, opts.source_path());
  90. opts.temporary_path(lua_out, "lua");
  91. const char *argv[] =
  92. {
  93. EXE_PATH("luajit"),
  94. LUAJIT_FLAGS,
  95. lua_src.c_str(),
  96. lua_out.c_str(),
  97. NULL
  98. };
  99. Process pr;
  100. s32 sc = pr.spawn(argv, CROWN_PROCESS_STDOUT_PIPE | CROWN_PROCESS_STDERR_MERGE);
  101. DATA_COMPILER_ASSERT(sc == 0
  102. , opts
  103. , "Failed to spawn `%s`"
  104. , argv[0]
  105. );
  106. // Scan the .lua code for requirements.
  107. Buffer lua_code = opts.read();
  108. HashSet<StringView> requirements(default_allocator());
  109. lua_resource_internal::find_requirements(requirements, array::begin(lua_code));
  110. auto cur = hash_set::begin(requirements);
  111. auto end = hash_set::end(requirements);
  112. for (; cur != end; ++cur) {
  113. HASH_SET_SKIP_HOLE(requirements, cur);
  114. TempAllocator256 ta;
  115. DynamicString name(ta);
  116. name = *cur;
  117. opts.add_requirement("lua", name.c_str());
  118. }
  119. StringStream output(ta);
  120. opts.read_output(output, pr);
  121. s32 ec = pr.wait();
  122. DATA_COMPILER_ASSERT(ec == 0
  123. , opts
  124. , "Failed to compile lua:\n%s"
  125. , string_stream::c_str(output)
  126. );
  127. Buffer blob = opts.read_temporary(lua_out.c_str());
  128. opts.delete_file(lua_out.c_str());
  129. LuaResource lr;
  130. lr.version = RESOURCE_HEADER(RESOURCE_VERSION_SCRIPT);
  131. lr.size = array::size(blob);
  132. opts.write(lr.version);
  133. opts.write(lr.size);
  134. opts.write(blob);
  135. return 0;
  136. }
  137. } // namespace lua_resource_internal
  138. #endif // if CROWN_CAN_COMPILE
  139. } // namespace crown