yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
5120c1cd0
master
1// slang-fiddle-script.cpp 2#include "slang-fiddle-script.h" 3 4#include "compiler-core/slang-diagnostic-sink.h" 5#include "lua/lapi.h" 6#include "lua/lauxlib.h" 7#include "lua/lualib.h" 8 9#include <cstdio> 10 11namespace fiddle 12{ 13DiagnosticSink * _sink = nullptr ; 14StringBuilder * _builder = nullptr ; 15Count _templateCounter = 0 ; 16 17static void _writeLuaMessage (Severity severity ,String const & message ) 18{ 19if (_sink ) 20 { 21_sink -> diagnoseRaw (severity ,message .getUnownedSlice ()); 22 } 23else 24 { 25fprintf (stderr ,"%s" ,message .getBuffer ()); 26 } 27} 28 29int _trace (lua_State * L ) 30{ 31int argCount = lua_gettop (L ); 32 33for (int i = 0 ;i < argCount ;++ i ) 34 { 35lua_pushliteral (L ," " ); 36luaL_tolstring (L ,i + 1 ,nullptr ); 37 } 38lua_concat (L ,2 * argCount ); 39 40size_t size = 0 ; 41char const * buffer = lua_tolstring (L ,-1 ,& size ); 42 43String message ; 44message .append ("fiddle:" ); 45message .append (UnownedStringSlice (buffer ,size )); 46message .append ("\n" ); 47 48_writeLuaMessage (Severity ::Note ,message ); 49return 0 ; 50} 51 52int _handleLuaErrorRaised (lua_State * L ) 53{ 54lua_pushliteral (L ,"\n" ); 55luaL_traceback (L ,L ,nullptr ,1 ); 56lua_concat (L ,3 ); 57return 1 ; 58} 59 60int _original (lua_State * L ) 61{ 62// We ignore the text that we want to just pass 63// through unmodified... 64return 0 ; 65} 66 67int _raw (lua_State * L ) 68{ 69size_t size = 0 ; 70char const * buffer = lua_tolstring (L ,1 ,& size ); 71 72_builder -> append (UnownedStringSlice (buffer ,size )); 73return 0 ; 74} 75 76int _splice (lua_State * L ) 77{ 78auto savedBuilder = _builder ; 79 80StringBuilder spliceBuilder ; 81_builder = & spliceBuilder ; 82 83lua_pushvalue (L ,1 ); 84lua_call (L ,0 ,1 ); 85 86_builder = savedBuilder ; 87 88// The actual string value follows whatever 89// got printed to the output (unless it is 90// nil). 91// 92_builder -> append (spliceBuilder .produceString ()); 93if (!lua_isnil (L ,-1 )) 94 { 95size_t size = 0 ; 96char const * buffer = luaL_tolstring (L ,-1 ,& size ); 97_builder -> append (UnownedStringSlice (buffer ,size )); 98 } 99return 0 ; 100} 101 102int _template (lua_State * L ) 103{ 104auto templateID = _templateCounter ++ ; 105 106_builder -> append ("\n#if FIDDLE_GENERATED_OUTPUT_ID == " ); 107_builder -> append (templateID ); 108_builder -> append ("\n" ); 109 110lua_pushvalue (L ,1 ); 111lua_call (L ,0 ,0 ); 112 113_builder -> append ("\n#endif\n" ); 114 115return 0 ; 116} 117 118lua_State * L = nullptr ; 119 120// Add a custom searcher that handles relative paths 121// So we can do things like require("source/slang/foo.lua") 122static int path_searcher (lua_State * L ) 123{ 124const char * modname = luaL_checkstring (L ,1 ); 125 126if (luaL_loadfile (L ,modname )== LUA_OK ) 127 { 128lua_pushstring (L ,modname );// Push filename as second return 129return 2 ; 130 } 131 132// Not found 133lua_pushfstring (L ,"\n\tno file '%s'" ,modname ); 134return 1 ; 135} 136 137void install_path_searcher (lua_State * L ) 138{ 139lua_getglobal (L ,"package" ); 140lua_getfield (L ,-1 ,"searchers" ); 141 142// Insert at position 2 (after preload) 143lua_pushcfunction (L ,path_searcher ); 144lua_rawseti (L ,-2 ,2 ); 145 146lua_pop (L ,2 ); 147} 148 149void ensureLuaInitialized () 150{ 151if (L ) 152return ; 153 154L = luaL_newstate (); 155luaL_openlibs (L ); 156 157lua_pushcclosure (L ,& _trace ,0 ); 158lua_setglobal (L ,"TRACE" ); 159 160lua_pushcclosure (L ,& _original ,0 ); 161lua_setglobal (L ,"ORIGINAL" ); 162 163lua_pushcclosure (L ,& _raw ,0 ); 164lua_setglobal (L ,"RAW" ); 165 166lua_pushcclosure (L ,& _splice ,0 ); 167lua_setglobal (L ,"SPLICE" ); 168 169lua_pushcclosure (L ,& _template ,0 ); 170lua_setglobal (L ,"TEMPLATE" ); 171 172install_path_searcher (L ); 173 174// TODO: register custom stuff here... 175} 176 177lua_State * getLuaState () 178{ 179ensureLuaInitialized (); 180return L ; 181} 182 183static void setupLuaEnvironment (const String & originalFileName ) 184{ 185ensureLuaInitialized (); 186 187lua_pushstring (L ,originalFileName .getBuffer ()); 188lua_setglobal (L ,"THIS_FILE" ); 189 190lua_pushcfunction (L ,& _handleLuaErrorRaised ); 191} 192 193static void handleLuaError ( 194SourceLoc loc , 195DiagnosticSink * sink , 196const char * errorType , 197DiagnosticInfo diagnosticID ) 198{ 199size_t size = 0 ; 200char const * buffer = lua_tolstring (L ,-1 ,& size ); 201String message = UnownedStringSlice (buffer ,size ); 202message = message + "\n" ; 203 204sink -> diagnose (loc ,diagnosticID ,message ); 205 206String abortMessage = "fiddle failed during Lua " ; 207abortMessage = abortMessage + errorType ; 208SLANG_ABORT_COMPILATION (abortMessage .getBuffer ()); 209} 210 211String evaluateScriptCode ( 212SourceLoc loc , 213String originalFileName , 214String scriptSource , 215DiagnosticSink * sink ) 216{ 217StringBuilder builder ; 218_builder = & builder ; 219_templateCounter = 0 ; 220 221setupLuaEnvironment (originalFileName ); 222 223String luaChunkName = "@" + originalFileName ; 224 225if (LUA_OK != luaL_loadbuffer ( 226L , 227scriptSource .getBuffer (), 228scriptSource .getLength (), 229luaChunkName .getBuffer ())) 230 { 231handleLuaError (loc ,sink ,"script loading" , fiddle::Diagnostics ::scriptLoadError ); 232 } 233 234if (LUA_OK != lua_pcall (L ,0 ,0 ,-2 )) 235 { 236handleLuaError (loc ,sink ,"script execution" , fiddle::Diagnostics ::scriptExecutionError ); 237 } 238 239_builder = nullptr ; 240return builder .produceString (); 241} 242 243String evaluateLuaExpression ( 244SourceLoc loc , 245String originalFileName , 246String luaExpression , 247DiagnosticSink * sink ) 248{ 249setupLuaEnvironment (originalFileName ); 250 251String luaChunkName = "@" + originalFileName ; 252 253// Wrap expression in return statement to get its value 254String wrappedExpression = "return " + luaExpression ; 255 256if (LUA_OK != luaL_loadbuffer ( 257L , 258wrappedExpression .getBuffer (), 259wrappedExpression .getLength (), 260luaChunkName .getBuffer ())) 261 { 262handleLuaError (loc ,sink ,"expression loading" , fiddle::Diagnostics ::scriptLoadError ); 263 } 264 265// Execute and expect 1 return value 266if (LUA_OK != lua_pcall (L ,0 ,1 ,-2 )) 267 { 268handleLuaError ( 269loc , 270sink , 271"expression evaluation" , 272 fiddle::Diagnostics ::scriptExecutionError ); 273 } 274 275// Convert the result to string 276size_t resultSize = 0 ; 277const char * resultBuffer = lua_tolstring (L ,-1 ,& resultSize ); 278 279if (!resultBuffer ) 280 { 281sink -> diagnose ( 282loc , 283 fiddle::Diagnostics ::scriptExecutionError , 284"Lua expression did not return a string value\n" ); 285SLANG_ABORT_COMPILATION ("fiddle failed: non-string expression result" ); 286 } 287 288String result ; 289result .append (resultBuffer ,resultSize ); 290 291// Pop the result and error handler 292lua_pop (L ,2 ); 293 294return result ; 295} 296}// namespace fiddle