Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
NativeRuntime_library.cpp
Go to the documentation of this file.
12#include <version.h>
13#include <nativeerror.h>
14#include <phsint.hpp>
15
16#ifdef _WIN32
17#include <windows.h>
18#endif
19
20#include <cstring>
21#include <vformat.hpp>
22
23void set_terminal_title(const char *title) {
24#ifdef _WIN32
25 SetConsoleTitleA(title);
26#else
27 vformat::printf("\033]0;%s\007", title);
28 fflush(stdout);
29#endif
30}
31
32#ifdef _WIN32
33#define setupConsole() \
34 AttachConsole(ATTACH_PARENT_PROCESS); \
35 { FILE* _f; freopen_s(&_f, "CONOUT$", "w", stdout); } \
36 { FILE* _f; freopen_s(&_f, "CONOUT$", "w", stderr); } \
37 puts("")
38
39std::string getCommandLine(LPSTR &lpszCmdLine) {
40 std::string cmdline = lpszCmdLine;
41 return (cmdline.size() >= 2 && cmdline.starts_with('"') && cmdline.ends_with('"')) ? cmdline.substr(1, cmdline.size() - 2) : cmdline;
42}
43#endif
44
45#ifndef _SHARED
46#define PHASOR_API
47#elif _WIN32
48#define PHASOR_API __declspec(dllexport)
49#elif defined(__GNUC__) || defined(__clang__)
50#define PHASOR_API __attribute__((visibility("default")))
51#endif
52
53#define msg error
54
55extern "C"
56{
57 PHASOR_API const char *getVersion()
58 {
59 return PHASOR_VERSION_STRING;
60 }
61
62 PHASOR_API int exec(void *vmPtr, const unsigned char *bytecode, size_t bytecodeSize, const char *moduleName,
63 int argc, const char **argv)
64 {
65 set_terminal_title(moduleName);
66 try
67 {
68 std::vector<Phasor::u8> bytecodeData(bytecode, bytecode + bytecodeSize);
69 Phasor::NativeRuntime NativeRT(static_cast<Phasor::VM *>(vmPtr), bytecodeData, argc, argv);
70
71 return NativeRT.run();
72 }
73 catch (const std::exception &e)
74 {
75 msg(std::string(moduleName) + ": " + e.what());
76 }
77 return -1;
78 }
79
80 PHASOR_API int execFuncInt(void *vmPtr, const unsigned char *bytecode, size_t bytecodeSize, const char *moduleName,
81 int argc, const char **argv, const char *functionName)
82 {
83 set_terminal_title(moduleName);
84 try
85 {
86 std::vector<Phasor::u8> bytecodeData(bytecode, bytecode + bytecodeSize);
87 Phasor::NativeRuntime NativeRT(static_cast<Phasor::VM *>(vmPtr), bytecodeData, argc, argv);
88
89 return NativeRT.runFunctionInt(functionName);
90 }
91 catch (const std::exception &e)
92 {
93 msg(std::string(moduleName) + ": " + e.what());
94 }
95 return -1;
96 }
97
98 PHASOR_API const char *execFuncString(void *vmPtr, const unsigned char *bytecode, size_t bytecodeSize,
99 const char *moduleName, int argc, const char **argv, const char *functionName)
100 {
101 set_terminal_title(moduleName);
102 static std::string ret;
103 try
104 {
105 std::vector<Phasor::u8> bytecodeData(bytecode, bytecode + bytecodeSize);
106 Phasor::NativeRuntime NativeRT(static_cast<Phasor::VM *>(vmPtr), bytecodeData, argc, argv);
107
108 auto result = NativeRT.runFunctionString(functionName);
109 if (!result)
110 return nullptr;
111 else
112 ret = *result;
113 return ret.c_str();
114 }
115 catch (const std::exception &e)
116 {
117 msg(std::string(moduleName) + ": " + e.what());
118 return nullptr;
119 }
120 }
121
122 PHASOR_API int evaluatePHS(void *vmPtr, const char *script, const char *moduleName, const char *modulePath,
123 bool verbose)
124 {
125 set_terminal_title(moduleName);
126 try
127 {
128 return Phasor::Frontend::runScript(script, static_cast<Phasor::VM *>(vmPtr), modulePath, verbose);
129 }
130 catch (const std::exception &e)
131 {
132 msg(std::string(moduleName) + ": " + e.what());
133 }
134 return -1;
135 }
136
137 PHASOR_API int evaluatePUL(void *vmPtr, const char *script, const char *moduleName)
138 {
139 set_terminal_title(moduleName);
140 try
141 {
142 return pulsar::Frontend::runScript(script, static_cast<Phasor::VM *>(vmPtr));
143 }
144 catch (const std::exception &e)
145 {
146 msg(std::string(moduleName) + ": " + e.what());
147 }
148 return -1;
149 }
150
151 PHASOR_API bool compilePHS(const char *script, const char *moduleName, const char *modulePath,
152 unsigned char *buffer, size_t bufferSize, size_t *outSize)
153 {
154 set_terminal_title((std::string("Compiling ") + moduleName).c_str());
155 try
156 {
157 Phasor::CodeGenerator codegen;
159 Phasor::Lexer lexer(script);
160 Phasor::Parser parser(lexer.tokenize());
161
162 if (modulePath && std::filesystem::exists(modulePath))
163 {
164 parser.setSourcePath(modulePath);
165 }
166
167 auto ast = parser.parse();
168 auto bc = codegen.generate(*ast);
169 std::vector<Phasor::u8> data = serializer.serialize(bc);
170
171 if (outSize)
172 *outSize = data.size();
173
174 if (!buffer)
175 return true;
176
177 if (bufferSize < data.size())
178 return false;
179
180 std::memcpy(buffer, data.data(), data.size());
181
182 return true;
183 }
184 catch (const std::exception &e)
185 {
186 msg(std::string(moduleName) + ": " + e.what());
187 }
188 return false;
189 }
190
191 PHASOR_API bool compilePUL(const char *script, const char *moduleName, unsigned char *buffer, size_t bufferSize,
192 size_t *outSize)
193 {
194 set_terminal_title((std::string("Compiling ") + moduleName).c_str());
195 try
196 {
197 Phasor::CodeGenerator codegen;
199 pulsar::Lexer lexer(script);
200 pulsar::Parser parser(lexer.tokenize());
201
202 auto ast = parser.parse();
203 auto bc = codegen.generate(*ast);
204 std::vector<Phasor::u8> data = serializer.serialize(bc);
205
206 if (outSize)
207 *outSize = data.size();
208
209 if (!buffer)
210 return true;
211
212 if (bufferSize < data.size())
213 return false;
214
215 std::memcpy(buffer, data.data(), data.size());
216
217 return true;
218 }
219 catch (const std::exception &e)
220 {
221 msg(std::string(moduleName) + ": " + e.what());
222 }
223 return false;
224 }
225
227 {
228 auto vm = new Phasor::VM();
229 return vm;
230 }
231
232 PHASOR_API void initStdLib(void *vmPtr)
233 {
234 Phasor::StdLib::registerFunctions(*static_cast<Phasor::VM *>(vmPtr));
235 }
236
237 PHASOR_API bool freeState(void *vmPtr)
238 {
239 if (!vmPtr)
240 return false;
241
242 delete static_cast<Phasor::VM *>(vmPtr);
243 return true;
244 }
245
246 PHASOR_API bool resetState(void *vmPtr, bool resetFunctions, bool resetVariables)
247 {
248 if (!vmPtr)
249 return false;
250
251 Phasor::VM *vm = static_cast<Phasor::VM *>(vmPtr);
252 vm->reset(true, resetFunctions, resetVariables);
253 return true;
254 }
255
256 PHASOR_API bool isErrorStatus(void *vmPtr)
257 {
258 if (!vmPtr)
259 return false;
260
261 Phasor::VM *vm = static_cast<Phasor::VM *>(vmPtr);
262 return vm->isErrorStatus();
263 }
264
265#if defined(_SHARED) && defined(_WIN32)
266 PHASOR_API void CALLBACK PhasorSourceStringEvaluateA(HWND hwnd, HINSTANCE, LPSTR lpszCmdLine, int)
267 {
268 setupConsole();
269 int exitCode = evaluatePHS(NULL, getCommandLine(lpszCmdLine).c_str(), __func__, "", false);
270 if (exitCode != 0)
271 {
272 std::string message = std::format("\nFailed with code {}\n", exitCode);
273 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
274 }
275 }
276
277 PHASOR_API void CALLBACK PhasorSourceFileEvaluateA(HWND hwnd, HINSTANCE, LPSTR lpszCmdLine, int)
278 {
279 setupConsole();
280 std::filesystem::path file = getCommandLine(lpszCmdLine);
281 std::string scriptText;
282
283 if (!std::filesystem::exists(file))
284 {
285 std::string message = std::format("File \"{}\" does not exist\n", file.filename().string());
286 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
287 return;
288 }
289
290 std::ifstream fileStream(file);
291 if (!fileStream)
292 {
293 std::string message = std::format("File \"{}\" could not be opened\n", file.filename().string());
294 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
295 return;
296 }
297
298 fileStream.seekg(0, std::ios::end);
299 scriptText.resize(static_cast<size_t>(fileStream.tellg()));
300 fileStream.seekg(0, std::ios::beg);
301
302 fileStream.read(scriptText.data(), scriptText.size());
303
304 int exitCode = evaluatePHS(NULL, scriptText.c_str(), __func__, file.parent_path().string().c_str(), false);
305 if (exitCode != 0)
306 {
307 std::string message = std::format("\nFailed with code {}\n", exitCode);
308 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
309 }
310 }
311
312 PHASOR_API void CALLBACK PulsarSourceStringEvaluateA(HWND hwnd, HINSTANCE, LPSTR lpszCmdLine, int)
313 {
314 setupConsole();
315 int exitCode = evaluatePUL(NULL, getCommandLine(lpszCmdLine).c_str(), __func__);
316 if (exitCode != 0)
317 {
318 std::string message = std::format("\nFailed with code {}\n", exitCode);
319 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
320 }
321 }
322
323 PHASOR_API void CALLBACK PulsarSourceFileEvaluateA(HWND hwnd, HINSTANCE, LPSTR lpszCmdLine, int)
324 {
325 setupConsole();
326 std::filesystem::path file = getCommandLine(lpszCmdLine);
327 std::string scriptText;
328
329 if (!std::filesystem::exists(file))
330 {
331 std::string message = std::format("File \"{}\" does not exist\n", file.filename().string());
332 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
333 return;
334 }
335
336 std::ifstream fileStream(file);
337 if (!fileStream)
338 {
339 std::string message = std::format("File \"{}\" could not be opened\n", file.filename().string());
340 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
341 return;
342 }
343
344 fileStream.seekg(0, std::ios::end);
345 scriptText.resize(static_cast<size_t>(fileStream.tellg()));
346 fileStream.seekg(0, std::ios::beg);
347
348 fileStream.read(scriptText.data(), scriptText.size());
349
350 int exitCode = evaluatePUL(NULL, scriptText.c_str(), __func__);
351 if (exitCode != 0)
352 {
353 std::string message = std::format("\nFailed with code {}\n", exitCode);
354 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
355 }
356 }
357
358 PHASOR_API void CALLBACK PhasorBytecodeFileExecuteA(HWND hwnd, HINSTANCE, LPSTR lpszCmdLine, int)
359 {
360 setupConsole();
361 std::filesystem::path file = getCommandLine(lpszCmdLine);
362 if (!std::filesystem::exists(file))
363 {
364 std::string message = std::format("File \"{}\" does not exist\n", file.filename().string());
365 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
366 return;
367 }
368 if (file.extension().string() != ".phsb")
369 {
370 std::string message = std::format("File \"{}\" is not a .phsb file\n", file.filename().string());
371 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
372 return;
373 }
374 Phasor::BytecodeDeserializer deserializer;
375 auto bytecode = deserializer.loadFromFile(file);
376 std::array<const char *, 2> args = {"phasorrt.dll", __func__};
377 Phasor::NativeRuntime NativeRT(bytecode, static_cast<int>(args.size()), args.data());
378 int exitCode = NativeRT.run();
379 if (exitCode != 0)
380 {
381 std::string message = std::format("\nFailed with code {}\n", exitCode);
382 MessageBoxA(hwnd, message.c_str(), __func__, MB_OK | MB_ICONERROR);
383 }
384 }
385#endif // if _SHARED && _WIN32
386}
PHASOR_API const char * execFuncString(void *vmPtr, const unsigned char *bytecode, size_t bytecodeSize, const char *moduleName, int argc, const char **argv, const char *functionName)
Executes a function from pre-compiled Phasor bytecode, and casts return to an string.
PHASOR_API bool compilePHS(const char *script, const char *moduleName, const char *modulePath, unsigned char *buffer, size_t bufferSize, size_t *outSize)
Compiles a Phasor Programming Language script into Phasor VM bytecode.
#define PHASOR_API
PHASOR_API int evaluatePUL(void *vmPtr, const char *script, const char *moduleName)
Executes a Pulsar Scripting Language script.
void set_terminal_title(const char *title)
PHASOR_API bool compilePUL(const char *script, const char *moduleName, unsigned char *buffer, size_t bufferSize, size_t *outSize)
Compiles a Pulsar Scripting Language script into Phasor VM bytecode.
#define msg
PHASOR_API int evaluatePHS(void *vmPtr, const char *script, const char *moduleName, const char *modulePath, bool verbose)
Executes a Phasor Programming Language script.
PHASOR_API const char * getVersion()
Get the version string for Phasor VM.
PHASOR_API bool freeState(void *vmPtr)
Frees an existing state instance.
PHASOR_API int execFuncInt(void *vmPtr, const unsigned char *bytecode, size_t bytecodeSize, const char *moduleName, int argc, const char **argv, const char *functionName)
Executes a function from pre-compiled Phasor bytecode, and casts return to an integer.
PHASOR_API int exec(void *vmPtr, const unsigned char *bytecode, size_t bytecodeSize, const char *moduleName, int argc, const char **argv)
Executes pre-compiled Phasor bytecode.
PHASOR_API void * createState()
Creates a new state instance.
PHASOR_API void initStdLib(void *vmPtr)
Register standard library to state instance.
PHASOR_API bool resetState(void *vmPtr, bool resetFunctions, bool resetVariables)
Resets the state.
PHASOR_API bool isErrorStatus(void *vmPtr)
Checks if the state is in an error status.
Bytecode binary format deserializer.
Bytecode loadFromFile(const std::filesystem::path &filename)
Load bytecode from .phsb file.
Bytecode binary format serializer.
std::vector< u8 > serialize(const Bytecode &bytecode)
Serialize bytecode to binary buffer.
Code generator for Phasor VM.
Definition CodeGen.hpp:108
Bytecode generate(const AST::Program &program, const std::unordered_map< std::string, int > &existingVars={}, int nextVarIdx=0, bool replMode=false)
Generate bytecode from program.
Definition CodeGen.cpp:9
Lexer.
Definition Lexer.hpp:13
std::vector< Token > tokenize()
Definition Lexer.cpp:28
CLI wrapper for running Phasor scripts and bytecode in-process.
int runFunctionInt(std::string functionName)
std::optional< std::string > runFunctionString(std::string functionName)
Parser.
Definition Parser.hpp:13
std::unique_ptr< AST::Program > parse()
Definition Parser.cpp:74
void setSourcePath(const std::filesystem::path &path)
Definition Parser.hpp:18
static void registerFunctions(VM &vm)
Definition StdLib.hpp:36
Virtual Machine.
Definition VM.hpp:36
bool isErrorStatus()
Definition Utility.cpp:51
void reset(const bool &resetStack=true, const bool &resetFunctions=true, const bool &resetVariables=true)
Reset the virtual machine.
Definition Utility.cpp:191
int runScript(const std::string &source, VM *vm, const std::filesystem::path &path="", bool verbose=false)
Run a script.
Definition Frontend.cpp:17
int runScript(const std::string &source, Phasor::VM *vm=nullptr)
Run a script.
Definition Frontend.cpp:26
int printf(const char *fmt,...)
Definition vformat.hpp:410