Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
Frontend.cpp
Go to the documentation of this file.
6
7#include <fstream>
8#include <print>
9#include <sstream>
10#include <string>
11#include <version.h>
12#include <sscanf.h>
13
14#include "Frontend.hpp"
15#include <nativeerror.h>
16
17int Phasor::Frontend::runScript(const std::string &source, VM *vm, const std::filesystem::path &path, bool verbose)
18{
19 int status = 0;
20 bool ownVM = false;
21 CodeGenerator codegen;
22 Lexer lexer(source);
23 Parser parser(lexer.tokenize());
24 if (!path.empty() && std::filesystem::exists(path))
25 {
26 parser.setSourcePath(path);
27 }
28
29 auto program = parser.parse();
30#ifndef TRACING
31 if (verbose)
32 {
33#else
34 (void)verbose;
35#endif
36 std::println("AST:");
37 program->print();
38 std::println("");
39#ifndef TRACING
40 }
41#endif
42 auto bytecode = codegen.generate(*program);
43
44 if (vm == nullptr)
45 {
46 ownVM = true;
47 vm = new VM();
49 }
50
51#if defined(_WIN32)
52 vm->initFFI("plugins");
53#elif defined(__APPLE__)
54 vm->initFFI("/Library/Application Support/org.Phasor.Phasor/plugins");
55#elif defined(__linux__)
56 vm->initFFI("/usr/lib/phasor/plugins/");
57#endif
58
59 vm->setImportHandler([vm](const std::filesystem::path &path) {
60 std::ifstream file(path);
61 if (!file.is_open())
62 {
63 throw std::runtime_error("Could not open imported file: " + path.string());
64 }
65 std::stringstream buffer;
66 buffer << file.rdbuf();
67 runScript(buffer.str(), vm, path);
68 });
69
70 try
71 {
72 status = vm->run(bytecode);
73
74 if (status != 0)
75 {
76 if (!ownVM)
77 {
78 vm->resetStatus();
79 vm->reset(true, false, false);
80 }
81 }
82 }
83 catch (...)
84 {
85 if (ownVM)
86 delete vm;
87 throw;
88 }
89
90 if (ownVM)
91 delete vm;
92
93 return status;
94}
95
96int Phasor::Frontend::runRepl(VM *vm, bool verbose)
97{
98 int status = 0;
99 bool ownVM = false;
100 CodeGenerator codegen;
101
102 if (vm == nullptr)
103 {
104 ownVM = true;
105 vm = new VM();
107 }
108
109#if defined(_WIN32)
110 vm->initFFI("plugins");
111#elif defined(__APPLE__)
112 vm->initFFI("/Library/Application Support/org.Phasor.Phasor/plugins");
113#elif defined(__linux__)
114 vm->initFFI("/usr/lib/phasor/plugins/");
115#endif
116
117 vm->setImportHandler([vm](const std::filesystem::path &path) {
118 std::ifstream file(path);
119 if (!file.is_open())
120 {
121 throw std::runtime_error("Could not open imported file: " + path.string());
122 }
123 std::stringstream buffer;
124 buffer << file.rdbuf();
125 runScript(buffer.str(), vm, path);
126 });
127
128 if (status != 0)
129 {
130 if (ownVM)
131 delete vm;
132 std::println(std::cerr, "Failed to create FFI handler!");
133 return status;
134 }
135
136 std::unordered_map<std::string, int> globalVars;
137 int nextVarIdx = 0;
138 std::string line;
139 bool cleanExit = false;
140
141 std::println("Phasor REPL (using Phasor VM v{})\n"
142 "(C) 2026 Daniel McGuire - Licensed under Apache 2.0\n\n"
143 "Type 'exit();' to quit. Function declarations will not work.",
144 PHASOR_VERSION_STRING);
145
146 while (true)
147 {
148 try
149 {
150 std::print("\n> ");
151 if (!std::getline(std::cin, line))
152 break;
153
154 if (line.starts_with("exit"))
155 {
156 cleanExit = true;
157 break;
158 }
159 if (line.empty())
160 {
161 std::println(std::cerr, "Empty line");
162 continue;
163 }
164
165 Lexer lexer(line);
166 Parser parser(lexer.tokenize());
167
168 auto program = parser.parse();
169#ifndef TRACING
170 if (verbose)
171 {
172#else
173 (void)verbose;
174#endif
175 std::println("AST:");
176 program->print();
177 std::println("");
178#ifndef TRACING
179 }
180#endif
181 auto bytecode = codegen.generate(*program, globalVars, nextVarIdx, true);
182
183 globalVars = bytecode.variables;
184 nextVarIdx = bytecode.nextVarIndex;
185
186 status = vm->run(bytecode);
187 }
188 catch (const std::exception &e)
189 {
190 error(std::format("{}\n", e.what()));
191 }
192 }
193
194 if (ownVM)
195 delete vm;
196
197 if (cleanExit)
198 return 0;
199
200 return status;
201}
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
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 setImportHandler(const ImportHandler &handler)
Set the import handler for importing modules.
Definition Utility.cpp:153
void resetStatus()
Definition Utility.cpp:42
int run(const Bytecode &bytecode, const size_t startPC=0)
Run the virtual machine Exits -1 on uncaught exception.
Definition Utility.cpp:88
void initFFI(const std::filesystem::path &path)
Initialize the FFI plugins.
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:181
int runRepl(VM *vm=nullptr, bool verbose=false)
Run an REPL.
Definition Frontend.cpp:96
int runScript(const std::string &source, VM *vm, const std::filesystem::path &path="", bool verbose=false)
Run a script.
Definition Frontend.cpp:17
#define error(msg)
Definition nativeerror.h:8