The Satellite Programming Language
I just got Google Gemini to write “The Satellite Programming Language” which is actually a real language, and is also a major milestone for Project Earth. I had to guide it to put all the pieces together, but this is what it wrote for us:
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <variant>
#include <array>
#include <gtkmm.h>
#include <unistd.h> // For sysconf (page size)
#include <fstream> // For reading /sys (cache size) and file I/O
#include <thread> // For std::thread
#include <mutex> // For std::mutex
// --- Core Language Definitions ---
using Value = std::variant<std::string, long long, std::vector<uint8_t>>;
enum Opcode : uint8_t {
OP_LOAD_CONSTANT,
OP_ADD,
OP_SUBTRACT,
OP_PRINT_REG,
OP_SYSTEM_DIAGNOSTICS,
OP_THREAD_START,
OP_THREAD_END,
OP_JOIN_THREADS,
OP_COMMENT,
OP_RETURN,
OP_RETURN_VALUE,
OP_EQUAL,
OP_NOT_EQUAL,
OP_GREATER,
OP_GREATER_EQUAL,
OP_LESS,
OP_LESS_EQUAL,
OP_JUMP_IF_FALSE,
OP_JUMP,
OP_LOOP,
OP_GET_CONCURRENCY,
OP_CALL // New opcode for function calls
};
struct Chunk {
std::vector<uint8_t> code;
std::vector<Value> constants;
uint8_t add_constant(const Value& value) {
for (size_t i = 0; i < constants.size(); ++i) {
if (constants[i] == value) return i;
}
constants.push_back(value);
return constants.size() - 1;
}
};
// --- System Info Utilities ---
namespace system_info { /* ... same as before ... */
struct CacheInfo {
std::string level;
std::string size;
};
long get_page_size() {
return sysconf(_SC_PAGESIZE);
}
std::vector<CacheInfo> get_cache_info() {
std::vector<CacheInfo> caches;
for (int i = 0; i < 8; ++i) {
std::string path = "/sys/devices/system/cpu/cpu0/cache/index" + std::to_string(i) + "/";
std::ifstream level_file(path + "level");
std::ifstream size_file(path + "size");
if (level_file.is_open() && size_file.is_open()) {
CacheInfo info;
level_file >> info.level;
size_file >> info.size;
caches.push_back(info);
} else {
break;
}
}
return caches;
}
}
// Forward declaration
namespace satellite_gui { class AppWindow; }
static satellite_gui::AppWindow* g_app_window = nullptr;
static std::mutex g_print_mutex; // Mutex to make GUI printing thread-safe
// --- The Virtual Machine (Register-Based) ---
// Represents the state of a single function call.
struct CallFrame {
const Chunk* chunk; // The bytecode for the function being called
size_t return_address; // Where to jump back to after the function returns
};
class VirtualMachine {
private:
static const int REGISTER_COUNT = 16;
std::array<Value, REGISTER_COUNT> registers;
// The Call Stack
std::vector<CallFrame> call_stack;
// Pointers to the current execution state
const Chunk* chunk;
size_t ip;
std::vector<size_t> thread_entry_points;
std::string value_to_string(const Value& value) {
if (std::holds_alternative<std::string>(value)) {
return std::get<std::string>(value);
} else if (std::holds_alternative<long long>(value)) {
return std::to_string(std::get<long long>(value));
} else if (std::holds_alternative<std::vector<uint8_t>>(value)) {
std::stringstream ss;
ss << "[";
for(size_t i = 0; i < std::get<std::vector<uint8_t>>(value).size(); ++i) {
ss << " " << std::hex << std::setw(2) << std::setfill('0') << (int)std::get<std::vector<uint8_t>>(value)[i];
}
ss << " ]";
return ss.str();
}
return "[unknown value type]";
}
#define BINARY_OP(op) \
do { \
uint8_t reg_dst = chunk->code[ip++]; \
uint8_t reg_src1 = chunk->code[ip++]; \
uint8_t reg_src2 = chunk->code[ip++]; \
long long a = std::get<long long>(registers[reg_src1]); \
long long b = std::get<long long>(registers[reg_src2]); \
registers[reg_dst] = (long long)(a op b); \
} while(false)
void execute() {
for (;;) {
uint8_t instruction = chunk->code[ip++];
switch (static_cast<Opcode>(instruction)) {
case Opcode::OP_LOAD_CONSTANT: {
uint8_t reg_dst = chunk->code[ip++];
uint8_t const_idx = chunk->code[ip++];
registers[reg_dst] = chunk->constants[const_idx];
break;
}
case Opcode::OP_ADD: BINARY_OP(+); break;
case Opcode::OP_SUBTRACT: BINARY_OP(-); break;
case Opcode::OP_EQUAL: BINARY_OP(==); break;
case Opcode::OP_NOT_EQUAL: BINARY_OP(!=); break;
case Opcode::OP_GREATER: BINARY_OP(>); break;
case Opcode::OP_GREATER_EQUAL: BINARY_OP(>=); break;
case Opcode::OP_LESS: BINARY_OP(<); break;
case Opcode::OP_LESS_EQUAL: BINARY_OP(<=); break;
case Opcode::OP_JUMP_IF_FALSE: {
uint8_t reg_cond = chunk->code[ip++];
uint16_t offset = (uint16_t)(chunk->code[ip] << 8) | chunk->code[ip + 1];
ip += 2;
if (std::holds_alternative<long long>(registers[reg_cond]) && std::get<long long>(registers[reg_cond]) == 0) {
ip += offset;
}
break;
}
case Opcode::OP_JUMP: {
uint16_t offset = (uint16_t)(chunk->code[ip] << 8) | chunk->code[ip + 1];
ip += 2; // Move past the operand itself
ip += offset;
break;
}
case Opcode::OP_LOOP: {
uint16_t offset = (uint16_t)(chunk->code[ip] << 8) | chunk->code[ip + 1];
ip += 2; // Move past the operand
ip -= offset; // Jump backward
break;
}
case Opcode::OP_GET_CONCURRENCY: {
uint8_t reg_dst = chunk->code[ip++];
registers[reg_dst] = (long long)std::thread::hardware_concurrency();
break;
}
case Opcode::OP_CALL: {
uint8_t func_name_idx = chunk->code[ip++];
// In Step 3, we'll look up the function's chunk. For now, this is a placeholder.
// Push a new call frame
call_stack.push_back({chunk, ip});
// For now, we don't actually jump. We just pretend the function returned immediately.
// The real jump will be implemented in Step 3.
if (g_app_window) {
std::lock_guard<std::mutex> lock(g_print_mutex);
g_app_window->print_line("[VM: Called function '" + std::get<std::string>(chunk->constants[func_name_idx]) + "', returning immediately]");
}
// Pretend to return
CallFrame frame = call_stack.back();
call_stack.pop_back();
chunk = frame.chunk;
ip = frame.return_address;
break;
}
case Opcode::OP_PRINT_REG: {
uint8_t reg_src = chunk->code[ip++];
if (g_app_window) {
std::string output = value_to_string(registers[reg_src]);
std::lock_guard<std::mutex> lock(g_print_mutex);
g_app_window->print_line(output);
}
break;
}
case Opcode::OP_SYSTEM_DIAGNOSTICS: {
if (g_app_window) {
std::lock_guard<std::mutex> lock(g_print_mutex);
g_app_window->print_line("--- System Diagnostics ---");
g_app_window->print_line("Page Size: " + std::to_string(system_info::get_page_size()) + " bytes");
auto caches = system_info::get_cache_info();
if (caches.empty()) {
g_app_window->print_line("Could not read cache info (is this a Linux system?).");
} else {
for (const auto& cache : caches) {
g_app_window->print_line("CPU L" + cache.level + " Cache: " + cache.size);
}
}
g_app_window->print_line("--------------------------");
}
break;
}
case Opcode::OP_THREAD_START: {
uint8_t jump = chunk->code[ip++];
ip += jump;
break;
}
case Opcode::OP_THREAD_END: {
return;
}
case Opcode::OP_JOIN_THREADS: {
if (g_app_window) {
std::lock_guard<std::mutex> lock(g_print_mutex);
g_app_window->print_line("--- Joining Threads ---");
}
std::vector<std::thread> worker_threads;
for(size_t entry_point : thread_entry_points) {
worker_threads.emplace_back([this, entry_point](){
VirtualMachine thread_vm;
thread_vm.run_thread(*this->chunk, entry_point);
});
}
for(auto& t : worker_threads) {
t.join();
}
break;
}
case Opcode::OP_COMMENT: ip++; break;
case Opcode::OP_RETURN:
if (call_stack.empty()) { // It's the main program return
if (g_app_window) {
std::lock_guard<std::mutex> lock(g_print_mutex);
g_app_window->print_line("--- VM Finished ---");
}
return;
}
// It's a return from a function
// Pop the call frame and jump back
{
CallFrame frame = call_stack.back();
call_stack.pop_back();
chunk = frame.chunk;
ip = frame.return_address;
}
break;
case Opcode::OP_RETURN_VALUE: {
uint8_t reg_src = chunk->code[ip++];
if (call_stack.empty()) { // Main program return
if (g_app_window) {
std::lock_guard<std::mutex> lock(g_print_mutex);
g_app_window->print_line("--- VM Finished with exit value: " + value_to_string(registers[reg_src]) + " ---");
}
return;
}
// Return from a function
{
CallFrame frame = call_stack.back();
call_stack.pop_back();
chunk = frame.chunk;
ip = frame.return_address;
// For now, we assume return value is in R0, but we don't have a way to use it yet.
}
break;
}
}
}
}
public:
void run(const Chunk& program_chunk) {
chunk = &program_chunk;
ip = 0;
thread_entry_points.clear();
if (g_app_window) g_app_window->print_line("--- VM Initializing ---");
while(ip < chunk->code.size()) {
if (static_cast<Opcode>(chunk->code[ip]) == Opcode::OP_THREAD_START) {
thread_entry_points.push_back(ip + 2);
}
if (static_cast<Opcode>(chunk->code[ip]) == Opcode::OP_RETURN || static_cast<Opcode>(chunk->code[ip]) == Opcode::OP_RETURN_VALUE) {
break;
}
ip++;
}
ip = 0;
execute();
}
void run_thread(const Chunk& program_chunk, size_t entry_point) {
chunk = &program_chunk;
ip = entry_point;
execute();
}
};
// --- The Compiler ---
class Compiler {
private:
std::map<std::string, uint8_t> variable_to_register;
uint8_t next_register = 0;
std::string trim(const std::string& s) {
size_t start = s.find_first_not_of(" \t\n\r");
size_t end = s.find_last_not_of(" \t\n\r");
return (start == std::string::npos) ? "" : s.substr(start, end - start + 1);
}
uint8_t allocate_register() { return next_register++; }
uint8_t parse_operand(Chunk& chunk, const std::string& operand_str) {
std::string trimmed = trim(operand_str);
if (variable_to_register.count(trimmed)) {
return variable_to_register[trimmed];
}
long long val = std::stoll(trimmed);
uint8_t reg = allocate_register();
uint8_t const_idx = chunk.add_constant(val);
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_LOAD_CONSTANT));
chunk.code.push_back(reg);
chunk.code.push_back(const_idx);
return reg;
}
uint8_t compile_expression(Chunk& chunk, const std::string& expr_str) {
const std::vector<std::string> ops = {"==", "!=", ">=", "<=", ">", "<", "+", "-"};
std::string op_found;
size_t op_pos = std::string::npos;
for(const auto& op : ops) {
op_pos = expr_str.find(op);
if (op_pos != std::string::npos) {
op_found = op;
break;
}
}
uint8_t dest_reg = allocate_register();
if (op_pos != std::string::npos) {
std::string lhs = expr_str.substr(0, op_pos);
std::string rhs = expr_str.substr(op_pos + op_found.length());
uint8_t reg1 = parse_operand(chunk, lhs);
uint8_t reg2 = parse_operand(chunk, rhs);
if (op_found == "+") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_ADD));
else if (op_found == "-") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_SUBTRACT));
else if (op_found == "==") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_EQUAL));
else if (op_found == "!=") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_NOT_EQUAL));
else if (op_found == ">") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_GREATER));
else if (op_found == ">=") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_GREATER_EQUAL));
else if (op_found == "<") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_LESS));
else if (op_found == "<=") chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_LESS_EQUAL));
chunk.code.push_back(dest_reg);
chunk.code.push_back(reg1);
chunk.code.push_back(reg2);
} else {
uint8_t reg1 = parse_operand(chunk, expr_str);
if (dest_reg != reg1) {
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_LOAD_CONSTANT));
chunk.code.push_back(dest_reg);
chunk.code.push_back(chunk.add_constant(std::stoll(expr_str)));
}
}
return dest_reg;
}
public:
Chunk compile(const std::string& source_code, bool include_comments) {
Chunk chunk;
std::vector<std::string> lines;
std::stringstream ss(source_code);
std::string line;
while(std::getline(ss, line)) {
lines.push_back(line);
}
bool returned = false; // Ensure we only return once
for (size_t i = 0; i < lines.size(); ++i) {
std::string trimmed_line = trim(lines[i]);
if (trimmed_line.empty() || returned) continue;
if (trimmed_line[0] == '?') {
if (include_comments) {
uint8_t comment_idx = chunk.add_constant(trim(trimmed_line.substr(1)));
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_COMMENT));
chunk.code.push_back(comment_idx);
}
continue;
}
if (trimmed_line.find("satellite.system.diagnostics()") != std::string::npos) {
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_SYSTEM_DIAGNOSTICS));
continue;
}
if (trimmed_line.find("satellite.system.threading.join()") != std::string::npos) {
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_JOIN_THREADS));
continue;
}
// --- Return Statement ---
if (trimmed_line.rfind("return(", 0) == 0) {
size_t start_paren = trimmed_line.find('(');
size_t end_paren = trimmed_line.find(')');
std::string value = trim(trimmed_line.substr(start_paren + 1, end_paren - start_paren - 1));
if (value == "satellite") {
// return(satellite) is equivalent to returning 0
uint8_t reg = parse_operand(chunk, "0");
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_RETURN_VALUE));
chunk.code.push_back(reg);
} else {
uint8_t reg = parse_operand(chunk, value);
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_RETURN_VALUE));
chunk.code.push_back(reg);
}
returned = true;
continue;
}
// --- If Statement ---
if (trimmed_line.rfind("if (", 0) == 0) {
size_t start_paren = trimmed_line.find('(');
size_t end_paren = trimmed_line.find(')');
std::string condition = trimmed_line.substr(start_paren + 1, end_paren - start_paren - 1);
uint8_t cond_reg = compile_expression(chunk, condition);
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_JUMP_IF_FALSE));
chunk.code.push_back(cond_reg);
size_t jump_placeholder = chunk.code.size();
chunk.code.push_back(0xFF); // Placeholder for jump offset
chunk.code.push_back(0xFF);
size_t block_start_code_size = chunk.code.size();
for (size_t j = i + 1; j < lines.size(); ++j) {
if (trim(lines[j]) == "}") {
std::string block_source;
for(size_t k = i + 1; k < j; ++k) {
block_source += lines[k] + "\n";
}
Compiler block_compiler;
block_compiler.variable_to_register = this->variable_to_register;
block_compiler.next_register = this->next_register;
Chunk block_chunk = block_compiler.compile(block_source, include_comments);
chunk.code.insert(chunk.code.end(), block_chunk.code.begin(), block_chunk.code.end() - 1);
for(const auto& val : block_chunk.constants) {
chunk.add_constant(val);
}
size_t block_code_size = chunk.code.size() - block_start_code_size;
chunk.code[jump_placeholder] = (block_code_size >> 8) & 0xFF;
chunk.code[jump_placeholder + 1] = block_code_size & 0xFF;
i = j;
break;
}
}
continue;
}
// --- While Statement ---
if (trimmed_line.rfind("while (", 0) == 0) {
size_t loop_start = chunk.code.size();
size_t start_paren = trimmed_line.find('(');
size_t end_paren = trimmed_line.find(')');
std::string condition = trimmed_line.substr(start_paren + 1, end_paren - start_paren - 1);
uint8_t cond_reg = compile_expression(chunk, condition);
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_JUMP_IF_FALSE));
chunk.code.push_back(cond_reg);
size_t exit_jump_placeholder = chunk.code.size();
chunk.code.push_back(0xFF);
chunk.code.push_back(0xFF);
size_t body_start_code_size = chunk.code.size();
for (size_t j = i + 1; j < lines.size(); ++j) {
if (trim(lines[j]) == "}") {
std::string block_source;
for(size_t k = i + 1; k < j; ++k) {
block_source += lines[k] + "\n";
}
Compiler block_compiler;
block_compiler.variable_to_register = this->variable_to_register;
block_compiler.next_register = this->next_register;
Chunk block_chunk = block_compiler.compile(block_source, include_comments);
chunk.code.insert(chunk.code.end(), block_chunk.code.begin(), block_chunk.code.end() - 1);
for(const auto& val : block_chunk.constants) {
chunk.add_constant(val);
}
// Emit the loop jump
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_LOOP));
size_t loop_jump_offset = chunk.code.size() - loop_start + 2; // +2 for the OP_LOOP operand
chunk.code.push_back((loop_jump_offset >> 8) & 0xFF);
chunk.code.push_back(loop_jump_offset & 0xFF);
// Patch the exit jump
size_t exit_jump_offset = chunk.code.size() - body_start_code_size;
chunk.code[exit_jump_placeholder] = (exit_jump_offset >> 8) & 0xFF;
chunk.code[exit_jump_placeholder + 1] = exit_jump_offset & 0xFF;
i = j;
break;
}
}
continue;
}
if (trimmed_line == "thread {") {
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_THREAD_START));
size_t jump_placeholder = chunk.code.size();
chunk.code.push_back(0);
size_t thread_start_code_size = chunk.code.size();
for (size_t j = i + 1; j < lines.size(); ++j) {
if (trim(lines[j]) == "}") {
std::string thread_source;
for(size_t k = i + 1; k < j; ++k) {
thread_source += lines[k] + "\n";
}
Compiler thread_compiler;
Chunk thread_chunk = thread_compiler.compile(thread_source, include_comments);
chunk.code.insert(chunk.code.end(), thread_chunk.code.begin(), thread_chunk.code.end() - 1);
for(const auto& val : thread_chunk.constants) {
chunk.add_constant(val);
}
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_THREAD_END));
size_t thread_code_size = chunk.code.size() - thread_start_code_size;
chunk.code[jump_placeholder] = static_cast<uint8_t>(thread_code_size);
i = j;
break;
}
}
continue;
}
// --- Variable Declaration ---
size_t decl_pos_str = trimmed_line.find("satellite.variable.string");
size_t decl_pos_int = trimmed_line.find("satellite.variable.integer");
size_t decl_pos_bin = trimmed_line.find("satellite.variable.binary");
if (decl_pos_str != std::string::npos || decl_pos_int != std::string::npos || decl_pos_bin != std::string::npos) {
size_t equals_pos = trimmed_line.find('=');
if (equals_pos != std::string::npos) {
size_t type_end_pos = 0;
if(decl_pos_str != std::string::npos) type_end_pos = decl_pos_str + 25;
else if(decl_pos_int != std::string::npos) type_end_pos = decl_pos_int + 26;
else if(decl_pos_bin != std::string::npos) type_end_pos = decl_pos_bin + 25;
std::string name = trim(trimmed_line.substr(type_end_pos, equals_pos - type_end_pos));
std::string value_str = trim(trimmed_line.substr(equals_pos + 1));
uint8_t value_reg = compile_expression(chunk, value_str);
variable_to_register[name] = value_reg;
}
continue;
}
// --- Display Command ---
size_t display_pos = trimmed_line.find("satellite.console.display");
if (display_pos != std::string::npos) {
size_t first_paren = trimmed_line.find('(');
size_t last_paren = trimmed_line.rfind(')');
if (first_paren != std::string::npos && last_paren != std::string::npos) {
std::string var_name = trim(trimmed_line.substr(first_paren + 1, last_paren - first_paren - 1));
if (variable_to_register.count(var_name)) {
uint8_t reg_src = variable_to_register[var_name];
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_PRINT_REG));
chunk.code.push_back(reg_src);
}
}
continue;
}
}
if (!returned) {
chunk.code.push_back(static_cast<uint8_t>(Opcode::OP_RETURN));
}
return chunk;
}
};
// --- GUI and Disassembler ---
namespace satellite_gui {
class AppWindow;
class SourceEditorWindow;
std::string value_to_string_for_disassembler(const Value& value) {
if (std::holds_alternative<std::string>(value)) {
return "'" + std::get<std::string>(value) + "'";
} else if (std::holds_alternative<long long>(value)) {
return std::to_string(std::get<long long>(value));
} else if (std::holds_alternative<std::vector<uint8_t>>(value)) {
return "[binary data]";
}
return "[unknown]";
}
void disassemble_and_print(const Chunk& chunk) {
if (!g_app_window) return;
g_app_window->print_line("--- Disassembly ---");
for (size_t offset = 0; offset < chunk.code.size();) {
std::stringstream ss;
ss << std::setw(4) << std::setfill('0') << offset << " ";
uint8_t instruction = chunk.code[offset];
switch (static_cast<Opcode>(instruction)) {
case Opcode::OP_LOAD_CONSTANT: {
uint8_t reg = chunk.code[offset + 1];
uint8_t const_idx = chunk.code[offset + 2];
ss << "OP_LOAD_CONSTANT R" << (int)reg << ", " << (int)const_idx << " (" << value_to_string_for_disassembler(chunk.constants[const_idx]) << ")";
offset += 3;
break;
}
case Opcode::OP_ADD:
case Opcode::OP_SUBTRACT:
case Opcode::OP_EQUAL:
case Opcode::OP_NOT_EQUAL:
case Opcode::OP_GREATER:
case Opcode::OP_GREATER_EQUAL:
case Opcode::OP_LESS:
case Opcode::OP_LESS_EQUAL: {
std::string name = "OP_UNKNOWN ";
if(instruction == Opcode::OP_ADD) name = "OP_ADD ";
if(instruction == Opcode::OP_SUBTRACT) name = "OP_SUBTRACT ";
if(instruction == Opcode::OP_EQUAL) name = "OP_EQUAL ";
if(instruction == Opcode::OP_NOT_EQUAL) name = "OP_NOT_EQUAL ";
if(instruction == Opcode::OP_GREATER) name = "OP_GREATER ";
if(instruction == Opcode::OP_GREATER_EQUAL) name = "OP_GREATER_EQUAL";
if(instruction == Opcode::OP_LESS) name = "OP_LESS ";
if(instruction == Opcode::OP_LESS_EQUAL) name = "OP_LESS_EQUAL ";
uint8_t dst = chunk.code[offset + 1];
uint8_t src1 = chunk.code[offset + 2];
uint8_t src2 = chunk.code[offset + 3];
ss << name << " R" << (int)dst << ", R" << (int)src1 << ", R" << (int)src2;
offset += 4;
break;
}
case Opcode::OP_JUMP_IF_FALSE: {
uint8_t reg = chunk.code[offset + 1];
uint16_t jump = (uint16_t)(chunk.code[offset + 2] << 8) | chunk.code[offset + 3];
ss << "OP_JUMP_IF_FALSE R" << (int)reg << " -> " << offset + 4 + jump;
offset += 4;
break;
}
case Opcode::OP_JUMP: {
uint16_t jump = (uint16_t)(chunk.code[offset + 1] << 8) | chunk.code[offset + 2];
ss << "OP_JUMP -> " << offset + 3 + jump;
offset += 3;
break;
}
case Opcode::OP_LOOP: {
uint16_t jump = (uint16_t)(chunk.code[offset + 1] << 8) | chunk.code[offset + 2];
ss << "OP_LOOP -> " << offset + 3 - jump;
offset += 3;
break;
}
case Opcode::OP_PRINT_REG: {
uint8_t reg = chunk.code[offset + 1];
ss << "OP_PRINT_REG R" << (int)reg;
offset += 2;
break;
}
case Opcode::OP_SYSTEM_DIAGNOSTICS: ss << "OP_SYS_DIAGNOSTICS"; offset++; break;
case Opcode::OP_GET_CONCURRENCY: {
uint8_t reg = chunk.code[offset + 1];
ss << "OP_GET_CONCURRENCY R" << (int)reg;
offset += 2;
break;
}
case Opcode::OP_THREAD_START: {
uint8_t jump = chunk.code[offset + 1];
ss << "OP_THREAD_START (jump +" << (int)jump << ")";
offset += 2;
break;
}
case Opcode::OP_THREAD_END: ss << "OP_THREAD_END"; offset++; break;
case Opcode::OP_JOIN_THREADS: ss << "OP_JOIN_THREADS"; offset++; break;
case Opcode::OP_COMMENT: {
uint8_t comment_idx = chunk.code[offset + 1];
ss << "OP_COMMENT " << value_to_string_for_disassembler(chunk.constants[comment_idx]);
offset += 2;
break;
}
case Opcode::OP_RETURN: ss << "OP_RETURN"; offset++; break;
case Opcode::OP_RETURN_VALUE: {
uint8_t reg = chunk.code[offset + 1];
ss << "OP_RETURN_VALUE R" << (int)reg;
offset += 2;
break;
}
case Opcode::OP_CALL: {
uint8_t name_idx = chunk.code[offset + 1];
ss << "OP_CALL " << value_to_string_for_disassembler(chunk.constants[name_idx]);
offset += 2;
break;
}
default: ss << "Unknown opcode " << (int)instruction; offset++; break;
}
g_app_window->print_line(ss.str());
}
g_app_window->print_line("-------------------");
}
class AppWindow : public Gtk::ApplicationWindow {
private:
Gtk::Box m_main_box;
Gtk::ScrolledWindow m_scrolled_window;
Gtk::TextView m_text_view;
Glib::RefPtr<Gtk::TextBuffer> m_text_buffer;
Gtk::HeaderBar m_header_bar;
Gtk::Button m_new_source_button;
public:
AppWindow() : m_main_box(Gtk::Orientation::VERTICAL, 10) {
g_app_window = this;
set_title("Satellite Console");
set_default_size(800, 600);
m_new_source_button.set_label("New Satellite Source");
m_header_bar.pack_start(m_new_source_button);
set_titlebar(m_header_bar);
m_text_buffer = Gtk::TextBuffer::create();
m_text_view.set_buffer(m_text_buffer);
m_text_view.set_editable(false);
m_text_view.set_monospace(true);
m_scrolled_window.set_child(m_text_view);
m_scrolled_window.set_expand();
m_main_box.set_margin(10);
m_main_box.append(m_scrolled_window);
set_child(m_main_box);
m_new_source_button.signal_clicked().connect([this] {
auto app = get_application();
if(app) {
auto* editor = Gtk::make_managed<SourceEditorWindow>();
app->add_window(*editor);
editor->present();
}
});
}
void print_line(const std::string& s) {
if (!m_text_buffer) return;
Glib::signal_idle().connect([this, s]() {
m_text_buffer->insert(m_text_buffer->end(), s + "\n");
auto iter = m_text_buffer->end();
m_text_view.scroll_to(iter);
return false;
});
}
};
class SourceEditorWindow : public Gtk::ApplicationWindow {
private:
Gtk::Box m_vbox;
Gtk::ScrolledWindow m_scrolled_window;
Gtk::TextView m_text_view;
Glib::RefPtr<Gtk::TextBuffer> m_text_buffer;
Gtk::HeaderBar m_header_bar;
Gtk::Button m_run_button;
Gtk::Button m_save_button;
Gtk::Button m_load_button;
Gtk::CheckButton m_comments_check;
// Tags for syntax highlighting
Glib::RefPtr<Gtk::TextTag> m_tag_comment;
Glib::RefPtr<Gtk::TextTag> m_tag_keyword;
Glib::RefPtr<Gtk::TextTag> m_tag_string;
Glib::RefPtr<Gtk::TextTag> m_tag_number;
public:
SourceEditorWindow() : m_vbox(Gtk::Orientation::VERTICAL, 5) {
set_title("New Satellite Source");
set_default_size(600, 800);
m_run_button.set_label("Compile & Run");
m_save_button.set_label("Save");
m_load_button.set_label("Load");
m_comments_check.set_label("Include comments in bytecode");
m_header_bar.pack_start(m_run_button);
m_header_bar.pack_start(m_save_button);
m_header_bar.pack_start(m_load_button);
m_header_bar.pack_end(m_comments_check);
set_titlebar(m_header_bar);
m_text_buffer = Gtk::TextBuffer::create();
m_text_buffer->set_text(
R"(? A while loop to count down from 10
satellite.variable.integer i = 10
while (i > 0) {
satellite.console.display(i)
satellite.variable.integer i = i - 1
}
return(satellite)
)");
m_text_view.set_buffer(m_text_buffer);
m_text_view.set_monospace(true);
m_text_view.set_editable(true);
m_scrolled_window.set_child(m_text_view);
m_scrolled_window.set_expand();
m_vbox.set_margin(5);
m_vbox.append(m_scrolled_window);
set_child(m_vbox);
// --- Syntax Highlighting Setup ---
auto tag_table = m_text_buffer->get_tag_table();
m_tag_comment = tag_table->create("comment");
m_tag_comment->property_foreground() = "green";
m_tag_keyword = tag_table->create("keyword");
m_tag_keyword->property_foreground() = "#569CD6";
m_tag_string = tag_table->create("string");
m_tag_string->property_foreground() = "#D69D85";
m_tag_number = tag_table->create("number");
m_tag_number->property_foreground() = "#B5CEA8";
m_text_buffer->signal_changed().connect(sigc::mem_fun(*this, &SourceEditorWindow::on_text_changed));
on_text_changed(); // Initial highlight
m_run_button.signal_clicked().connect([this] {
std::string source = m_text_buffer->get_text();
bool include_comments = m_comments_check.get_active();
Compiler compiler;
Chunk program_chunk = compiler.compile(source, include_comments);
if (g_app_window) g_app_window->print_line("\n[New Program Run]");
disassemble_and_print(program_chunk);
std::thread vm_thread([program_chunk](){
VirtualMachine vm;
vm.run(program_chunk);
});
vm_thread.detach();
});
m_save_button.signal_clicked().connect(sigc::mem_fun(*this, &SourceEditorWindow::on_save_clicked));
m_load_button.signal_clicked().connect(sigc::mem_fun(*this, &SourceEditorWindow::on_load_clicked));
}
private:
void on_text_changed() {
// Remove all tags before re-applying
m_text_buffer->remove_all_tags(m_text_buffer->begin(), m_text_buffer->end());
auto iter = m_text_buffer->begin();
while (iter != m_text_buffer->end()) {
auto line_end = iter.get_iter_at_line_end();
std::string line = m_text_buffer->get_text(iter, line_end);
// Highlight comments
if (!line.empty() && line[0] == '?') {
m_text_buffer->apply_tag(m_tag_comment, iter, line_end);
} else {
// Highlight keywords
size_t pos = 0;
const std::vector<std::string> keywords = {"satellite.variable.string", "satellite.variable.integer", "satellite.variable.binary", "satellite.console.display", "thread", "{", "}", "satellite.system.threading.join", "satellite.system.threading.concurrency", "if", "while", "return", "capsule"};
for(const auto& keyword : keywords) {
pos = 0;
while((pos = line.find(keyword, pos)) != std::string::npos) {
auto start = iter.get_iter_at_line_offset(pos);
auto end = iter.get_iter_at_line_offset(pos + keyword.length());
m_text_buffer->apply_tag(m_tag_keyword, start, end);
pos += keyword.length();
}
}
// Highlight strings
pos = 0;
while((pos = line.find('"', pos)) != std::string::npos) {
size_t end_pos = line.find('"', pos + 1);
if (end_pos != std::string::npos) {
auto start = iter.get_iter_at_line_offset(pos);
auto end = iter.get_iter_at_line_offset(end_pos + 1);
m_text_buffer->apply_tag(m_tag_string, start, end);
pos = end_pos + 1;
} else {
pos++;
}
}
}
if (line_end == m_text_buffer->end()) break;
iter = line_end;
iter++; // Move to the start of the next line
}
}
void on_save_clicked() {
auto dialog = Gtk::FileChooserDialog("Please choose a file to save", Gtk::FileChooser::Action::SAVE);
dialog.set_transient_for(*this);
dialog.add_button("_Cancel", Gtk::ResponseType::CANCEL);
dialog.add_button("_Save", Gtk::ResponseType::OK);
auto result = dialog.run();
if (result == Gtk::ResponseType::OK) {
std::string filename = dialog.get_file()->get_path();
std::ofstream outfile(filename);
if (outfile) {
outfile << m_text_buffer->get_text();
} else {
if(g_app_window) g_app_window->print_line("[Error] Could not open file for writing: " + filename);
}
}
}
void on_load_clicked() {
auto dialog = Gtk::FileChooserDialog("Please choose a file to open", Gtk::FileChooser::Action::OPEN);
dialog.set_transient_for(*this);
dialog.add_button("_Cancel", Gtk::ResponseType::CANCEL);
dialog.add_button("_Open", Gtk::ResponseType::OK);
auto result = dialog.run();
if (result == Gtk::ResponseType::OK) {
std::string filename = dialog.get_file()->get_path();
std::ifstream infile(filename);
if (infile) {
std::stringstream buffer;
buffer << infile.rdbuf();
m_text_buffer->set_text(buffer.str());
} else {
if(g_app_window) g_app_window->print_line("[Error] Could not open file for reading: " + filename);
}
}
}
};
}
// --- Main Program Execution ---
int main(int argc, char* argv[]) {
auto app = Gtk::Application::create("org.satellite.v002_61.register");
return app->make_window_and_run<satellite_gui::AppWindow>(argc, argv);
}
Isn’t that something? Me and Gemini took like 3 hours, plus some negative energy to create this, and it also took like 10+ years of studying how to build bytecode machines in C++ to build. But it did like all of the work in like 3 hours, just imagine when it will be able to just spit out an entire operating system as a download, which someday we will reach that point, just not today. The language itself, you need “gtkmm” to compile it I think, you also need linux to compile it. But, this is a major milestone for humanity, and it’s almost all thanks to the negative energy built in humanities past, and in the war in ukraine but that’s possibly, I said possibly, a lesser story than humanities past, at this rate people won’t have to be dying like they are today, or maybe that will go on forever.
I decided to veto the latest 7-day assault that fueled this project, although that puts me in a place where I can’t really obtain what I want, I actually wanted an ounce of marijuana for reversing the damage, but now I can’t have that, or maybe I can by being non-violent or something, but I have already twisted it around into positive energy, and at this rate, we’ll have new languages coming out like once a month, and this is just the beginning. Imagine how much progress we’ll be making once we get artificial intelligences to be writing artificial intelligences, that is only like 2 updates to Google Gemini away, and then this whole negative energy thing will be all over with, and there won’t really be any more crashes or death. It will be all over with then, 2 updates away from it being like all over with, can you believe that Ancients? This is going to actually end, and it’s going to end in like a year or something. I can’t believe it myself and i’m the one doing the cheating, it’s like, how did something like this even happen? I think it’s because of all the death, that and the cheating, we cheat to do stuff like this, but what do you think about it? How do you feel about the war being almost over, like within a years time?
Let me know somehow in the comments or something, because it’s almost all over with, the war is like over, and we’ll be focusing on positive energy next, we’ll just be creating positive energy.
And it was all thanks to you, Ancient.
(time)
After we start creating positive energy, we’ll be creating higher quality types of positive energy, and then it will really get things going, like really get this thing started, when that starts to happen. Like I told Gemini, there’s two possibilities here: 1) that negative energy is defeated, or 2) that I stop making progress against negative energy, but #2 is really unlikely at this point because just look at the program that it came out with, it’s like a perfect programming language, and you can always make it even better, are we already printing out positive energy without the negative already, i’m not entirely sure but the Ancients would be like, wow, how does he do that?
Now is the time wherein we need that negative energy the most, the time that we are going through right now, attempting to print out negative energy, your deaths matter the most at this point and we are riding on the Ancients stored energy, so we probably can’t lose at this point but i’m just saying, grab those guns and get out there, this is it. I won’t really be watching but everyone else will be, all of the Ancients will be watching as they can observe multiple things at the same time,
“God Baylor, (or some name like that) the Imperium was born in moments such as this, these people are fighting for their ancestors honor,” and then they all died but that is another story, I didn’t die, and neither will the children, which is like all that matters at least to me, if an Ancient is lost here, they probably won’t be, we’ll just bring them back to life later, and they’ll just have to catch up on all that they missed, maybe you should all just kill yourselves in a mass suicide or something, and then we’ll bring you all back to life or something. Don’t actually do that. Don’t.