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