pub mod compiler;
pub mod primitives;
#[cfg(test)]
mod tests;
use crate::types::{Cell, Entry, Instruction};
use std::collections::{HashSet, VecDeque};
use std::io::{self, Write};
use std::time::Instant;
pub(crate) const P_DUP: usize = 0;
pub(crate) const P_DROP: usize = 1;
pub(crate) const P_SWAP: usize = 2;
pub(crate) const P_OVER: usize = 3;
pub(crate) const P_ROT: usize = 4;
pub(crate) const P_FETCH: usize = 5;
pub(crate) const P_STORE: usize = 6;
pub(crate) const P_ADD: usize = 7;
pub(crate) const P_SUB: usize = 8;
pub(crate) const P_MUL: usize = 9;
pub(crate) const P_DIV: usize = 10;
pub(crate) const P_MOD: usize = 11;
pub(crate) const P_EQ: usize = 12;
pub(crate) const P_LT: usize = 13;
pub(crate) const P_GT: usize = 14;
pub(crate) const P_AND: usize = 15;
pub(crate) const P_OR: usize = 16;
pub(crate) const P_NOT: usize = 17;
pub(crate) const P_EMIT: usize = 18;
pub(crate) const P_KEY: usize = 19;
pub(crate) const P_CR: usize = 20;
pub(crate) const P_DOT: usize = 21;
pub(crate) const P_DOT_S: usize = 22;
pub(crate) const P_COLON: usize = 23;
pub(crate) const P_SEMICOLON: usize = 24;
pub(crate) const P_CREATE: usize = 25;
pub(crate) const P_DOES: usize = 26;
pub(crate) const P_VARIABLE: usize = 27;
pub(crate) const P_CONSTANT: usize = 28;
pub(crate) const P_IF: usize = 29;
pub(crate) const P_ELSE: usize = 30;
pub(crate) const P_THEN: usize = 31;
pub(crate) const P_DO: usize = 32;
pub(crate) const P_LOOP: usize = 33;
pub(crate) const P_BEGIN: usize = 34;
pub(crate) const P_UNTIL: usize = 35;
pub(crate) const P_WHILE: usize = 36;
pub(crate) const P_REPEAT: usize = 37;
pub(crate) const P_DOT_QUOTE: usize = 38;
pub(crate) const P_PAREN: usize = 39;
pub(crate) const P_BACKSLASH: usize = 40;
pub(crate) const P_WORDS: usize = 41;
pub(crate) const P_SEE: usize = 42;
pub(crate) const P_QUIT: usize = 43;
pub(crate) const P_BYE: usize = 44;
pub(crate) const P_SEND: usize = 45;
pub(crate) const P_RECV: usize = 46;
pub(crate) const P_PEERS: usize = 47;
pub(crate) const P_REPLICATE: usize = 48;
pub(crate) const P_MUTATE: usize = 49;
pub(crate) const P_RECURSE: usize = 50;
pub(crate) const P_MESH_STATUS: usize = 51;
pub(crate) const P_PROPOSE: usize = 52;
pub(crate) const P_LOAD: usize = 53;
pub(crate) const P_CAPACITY: usize = 54;
pub(crate) const P_ID: usize = 55;
pub(crate) const P_TYPE: usize = 56;
pub(crate) const P_GOAL: usize = 57;
pub(crate) const P_GOALS: usize = 58;
pub(crate) const P_TASKS: usize = 59;
pub(crate) const P_TASK_STATUS: usize = 60;
pub(crate) const P_CANCEL: usize = 61;
pub(crate) const P_STEER: usize = 62;
pub(crate) const P_REPORT: usize = 63;
pub(crate) const P_CLAIM: usize = 64;
pub(crate) const P_COMPLETE: usize = 65;
pub(crate) const P_GOAL_EXEC: usize = 66;
pub(crate) const P_EVAL: usize = 67;
pub(crate) const P_RESULT: usize = 68;
pub(crate) const P_AUTO_CLAIM: usize = 69;
pub(crate) const P_TIMEOUT: usize = 70;
pub(crate) const P_GOAL_RESULT: usize = 71;
pub(crate) const P_FILE_READ: usize = 72;
pub(crate) const P_FILE_WRITE: usize = 73;
pub(crate) const P_FILE_EXISTS: usize = 74;
pub(crate) const P_FILE_LIST: usize = 75;
pub(crate) const P_FILE_DELETE: usize = 76;
pub(crate) const P_HTTP_GET: usize = 77;
pub(crate) const P_HTTP_POST: usize = 78;
pub(crate) const P_SHELL: usize = 79;
pub(crate) const P_ENV: usize = 80;
pub(crate) const P_TIMESTAMP: usize = 81;
pub(crate) const P_SLEEP: usize = 82;
pub(crate) const P_SANDBOX_ON: usize = 83;
pub(crate) const P_SANDBOX_OFF: usize = 84;
pub(crate) const P_IO_LOG: usize = 85;
pub(crate) const P_MUTATE_RAND: usize = 86;
pub(crate) const P_MUTATE_WORD: usize = 87;
pub(crate) const P_UNDO_MUTATE: usize = 88;
pub(crate) const P_MUTATIONS: usize = 89;
pub(crate) const P_FITNESS: usize = 90;
pub(crate) const P_LEADERBOARD: usize = 91;
pub(crate) const P_RATE: usize = 92;
pub(crate) const P_EVOLVE: usize = 93;
pub(crate) const P_AUTO_EVOLVE: usize = 94;
pub(crate) const P_BENCHMARK: usize = 95;
pub(crate) const P_TRUST: usize = 96;
pub(crate) const P_TRUST_ALL: usize = 97;
pub(crate) const P_TRUST_NONE: usize = 98;
pub(crate) const P_SHELL_ENABLE: usize = 99;
pub(crate) const P_REIDENTIFY: usize = 199;
pub(crate) const P_SAVE: usize = 200;
pub(crate) const P_LOAD_STATE: usize = 201;
pub(crate) const P_AUTO_SAVE: usize = 202;
pub(crate) const P_RESET: usize = 203;
pub(crate) const P_SNAPSHOTS: usize = 204;
pub(crate) const P_SNAPSHOT: usize = 205;
pub(crate) const P_RESTORE: usize = 206;
pub(crate) const P_I: usize = 215;
pub(crate) const P_J: usize = 216;
pub(crate) const P_SPAWN: usize = 220;
pub(crate) const P_SPAWN_N: usize = 221;
pub(crate) const P_PACKAGE: usize = 222;
pub(crate) const P_PACKAGE_SIZE: usize = 223;
pub(crate) const P_CHILDREN: usize = 224;
pub(crate) const P_FAMILY: usize = 225;
pub(crate) const P_GENERATION: usize = 226;
pub(crate) const P_KILL_CHILD: usize = 227;
pub(crate) const P_REPLICATE_TO: usize = 228;
pub(crate) const P_ACCEPT_REPL: usize = 229;
pub(crate) const P_DENY_REPL: usize = 230;
pub(crate) const P_QUARANTINE: usize = 231;
pub(crate) const P_MAX_CHILDREN: usize = 232;
pub(crate) const P_SUBTASK: usize = 210;
pub(crate) const P_FORK: usize = 211;
pub(crate) const P_RESULTS: usize = 212;
pub(crate) const P_REDUCE: usize = 213;
pub(crate) const P_PROGRESS: usize = 214;
pub(crate) const P_WATCH_URL: usize = 300;
pub(crate) const P_WATCH_FILE: usize = 301;
pub(crate) const P_WATCH_PROC: usize = 302;
pub(crate) const P_WATCHES: usize = 303;
pub(crate) const P_UNWATCH: usize = 304;
pub(crate) const P_WATCH_LOG: usize = 305;
pub(crate) const P_ON_ALERT: usize = 306;
pub(crate) const P_ALERTS: usize = 307;
pub(crate) const P_ACK: usize = 308;
pub(crate) const P_ALERT_HISTORY: usize = 309;
pub(crate) const P_DASHBOARD: usize = 310;
pub(crate) const P_HEALTH: usize = 311;
pub(crate) const P_UPTIME: usize = 312;
pub(crate) const P_EVERY: usize = 313;
pub(crate) const P_SCHEDULE: usize = 314;
pub(crate) const P_UNSCHED: usize = 315;
pub(crate) const P_HEAL: usize = 316;
pub(crate) const P_HEALTH_PORT: usize = 317;
pub(crate) const P_ALERT_THRESHOLD: usize = 318;
pub(crate) const P_WS_STATUS: usize = 320;
pub(crate) const P_WS_CLIENTS: usize = 321;
pub(crate) const P_WS_PORT: usize = 322;
pub(crate) const P_WS_BROADCAST: usize = 323;
pub(crate) const P_DISCOVER: usize = 330;
pub(crate) const P_AUTO_DISCOVER: usize = 331;
pub(crate) const P_SHARE_WORD: usize = 332;
pub(crate) const P_SHARE_ALL: usize = 333;
pub(crate) const P_AUTO_SHARE: usize = 334;
pub(crate) const P_SHARED_WORDS: usize = 335;
pub(crate) const P_AUTO_SPAWN_TOGGLE: usize = 336;
pub(crate) const P_AUTO_CULL_TOGGLE: usize = 337;
pub(crate) const P_MIN_UNITS: usize = 338;
pub(crate) const P_MAX_UNITS: usize = 339;
pub(crate) const P_SWARM_STATUS: usize = 340;
pub(crate) const P_TRUST_ALL_LEVEL: usize = 350;
pub(crate) const P_TRUST_MESH: usize = 351;
pub(crate) const P_TRUST_FAMILY: usize = 352;
pub(crate) const P_TRUST_NONE_LEVEL: usize = 353;
pub(crate) const P_TRUST_LEVEL: usize = 354;
pub(crate) const P_REQUESTS: usize = 355;
pub(crate) const P_ACCEPT_REQ: usize = 356;
pub(crate) const P_DENY_REQ: usize = 357;
pub(crate) const P_DENY_ALL_REQ: usize = 358;
pub(crate) const P_REPLICATION_LOG: usize = 359;
pub(crate) const P_GOAL_COUNT: usize = 400;
pub(crate) const P_TASK_COUNT: usize = 401;
pub(crate) const P_WATCH_COUNT: usize = 402;
pub(crate) const P_ALERT_COUNT: usize = 403;
pub(crate) const P_CHILD_COUNT: usize = 404;
pub(crate) const P_MESH_AVG_FITNESS: usize = 405;
pub(crate) const P_CHECK_WATCHES: usize = 406;
pub(crate) const P_RUN_HANDLERS: usize = 407;
pub(crate) const P_RUN_BENCHMARK: usize = 408;
pub(crate) const P_MUTATE_RANDOM: usize = 409;
pub(crate) const P_UNDO_LAST_MUTATION: usize = 410;
pub(crate) const P_PEER_COUNT: usize = 411;
pub(crate) const P_SMART_MUTATE: usize = 412;
pub(crate) const P_MUTATION_REPORT: usize = 413;
pub(crate) const P_MUTATION_STATS: usize = 414;
pub(crate) const P_SEXP_EVAL: usize = 420;
pub(crate) const P_SEXP_SEND: usize = 421;
pub(crate) const P_SEXP_RECV: usize = 422;
pub(crate) const P_JSON_SNAPSHOT: usize = 430;
pub(crate) const P_JSON_RESTORE: usize = 431;
pub(crate) const P_SNAPSHOT_PATH: usize = 432;
pub(crate) const P_JSON_SNAPSHOTS: usize = 433;
pub(crate) const P_AUTO_SNAPSHOT: usize = 434;
pub(crate) const P_HIBERNATE: usize = 435;
pub(crate) const P_EXPORT_GENOME: usize = 436;
pub(crate) const P_IMPORT_GENOME: usize = 437;
pub(crate) const P_GP_EVOLVE: usize = 440;
pub(crate) const P_GP_STATUS: usize = 441;
pub(crate) const P_GP_BEST: usize = 442;
pub(crate) const P_GP_STOP: usize = 443;
pub(crate) const P_GP_RESET: usize = 444;
pub(crate) const P_DIST_GOAL: usize = 450;
pub(crate) const P_DIST_STATUS: usize = 451;
pub(crate) const P_DIST_CANCEL: usize = 452;
pub(crate) const P_MY_ADDR: usize = 460;
pub(crate) const P_PEER_TABLE: usize = 461;
pub(crate) const P_MESH_KEY: usize = 462;
pub(crate) const P_CONNECT: usize = 463;
pub(crate) const P_DISCONNECT: usize = 464;
pub(crate) const P_MESH_STATS: usize = 465;
pub(crate) const P_HERE: usize = 470;
pub(crate) const P_COMMA: usize = 471;
pub(crate) const P_ALLOT: usize = 472;
pub(crate) const P_CELLS: usize = 473;
pub(crate) const P_CHALLENGES: usize = 480;
pub(crate) const P_IMMUNE_STATUS: usize = 481;
pub(crate) const P_ANTIBODIES: usize = 482;
pub(crate) const P_ENERGY: usize = 483;
pub(crate) const P_METABOLISM: usize = 484;
pub(crate) const P_FEED: usize = 485;
pub(crate) const P_LANDSCAPE: usize = 486;
pub(crate) const P_DEPTH: usize = 487;
pub(crate) const P_GENERATORS: usize = 488;
pub(crate) const P_META_EVOLVE: usize = 489;
pub(crate) const P_SCORERS: usize = 490;
pub(crate) const P_META_DEPTH: usize = 491;
pub(crate) const P_GENERATE_CHALLENGE: usize = 492;
pub(crate) const P_EVOLUTION_STATS: usize = 493;
pub(crate) const P_MATE: usize = 494;
pub(crate) const P_MATE_STATUS: usize = 495;
pub(crate) const P_ACCEPT_MATE: usize = 496;
pub(crate) const P_DENY_MATE: usize = 497;
pub(crate) const P_OFFSPRING: usize = 498;
pub(crate) const P_NICHE: usize = 499;
pub(crate) const P_NICHE_HISTORY: usize = 500;
pub(crate) const P_ECOLOGY: usize = 501;
pub(crate) const P_DO_RT: usize = 100;
pub(crate) const P_LOOP_RT: usize = 101;
pub(crate) const P_GOAL_EXEC_RT: usize = 102;
pub(crate) const P_IO_RT: usize = 103;
pub(crate) const P_MUTATE_WORD_RT: usize = 104;
pub(crate) const P_BENCHMARK_RT: usize = 105;
pub(crate) const P_REDUCE_RT: usize = 106;
pub(crate) const P_WATCH_URL_RT: usize = 107;
pub(crate) const P_WATCH_FILE_RT: usize = 108;
pub(crate) const P_WATCH_PROC_RT: usize = 109;
pub(crate) const P_ON_ALERT_RT: usize = 110;
pub(crate) const P_EVERY_RT: usize = 111;
pub(crate) const P_ALERT_THRESHOLD_RT: usize = 112;
pub struct VM {
pub stack: Vec<Cell>,
pub rstack: Vec<Cell>,
pub dictionary: Vec<Entry>,
pub memory: Vec<Cell>,
pub here: usize,
pub primitive_names: Vec<(String, usize)>,
pub compiling: bool,
pub current_def: Option<Entry>,
pub input_buffer: String,
pub input_pos: usize,
pub running: bool,
pub silent: bool,
pub mesh: Option<crate::mesh::MeshNode>,
pub output_buffer: Option<String>,
pub deadline: Option<Instant>,
pub timed_out: bool,
pub execution_timeout: u64,
pub auto_claim: bool,
pub code_strings: Vec<String>,
pub sandbox_active: bool,
pub shell_enabled: bool,
pub trusted_peers: HashSet<[u8; 8]>,
pub io_log: VecDeque<String>,
pub mutation_history: Vec<crate::features::mutation::MutationRecord>,
pub mutation_stats: crate::features::mutation::MutationStats,
pub last_mutation_result: Option<crate::features::mutation::SmartMutationResult>,
pub rng: crate::features::mutation::SimpleRng,
pub fitness: crate::features::fitness::FitnessTracker,
pub spawn_state: crate::spawn::SpawnState,
pub monitor: crate::features::monitor::MonitorState,
pub ws_state:
Option<std::sync::Arc<std::sync::Mutex<crate::features::ws_bridge::WsBridgeState>>>,
pub ws_events: Option<std::sync::mpsc::Receiver<crate::features::ws_bridge::WsEvent>>,
pub ws_mesh_json: std::sync::Arc<std::sync::Mutex<String>>,
pub anon_depth: i32,
pub auto_save_enabled: bool,
pub auto_save_interval: u32,
pub tasks_since_save: u32,
pub node_id_cache: Option<[u8; 8]>,
pub auto_snapshot_secs: u64,
pub auto_snapshot_last: Option<std::time::Instant>,
pub kernel_word_count: usize,
pub evolution: Option<crate::evolve::EvolutionState>,
pub dist_engine: crate::distgoal::DistEngine,
pub challenge_registry: crate::challenges::ChallengeRegistry,
pub problem_detector: crate::discovery::ProblemDetector,
pub energy: crate::energy::EnergyState,
pub landscape: crate::landscape::LandscapeEngine,
pub last_solved_target: Option<i64>,
pub mate_auto_accept: bool,
pub mating_offspring: Vec<(String, String)>, pub pending_mate_request: Option<crate::reproduction::MatingRequest>,
pub niche_profile: crate::niche::NicheProfile,
}
impl Default for VM {
fn default() -> Self {
Self::new()
}
}
impl VM {
pub fn new() -> Self {
let mut vm = VM {
stack: Vec::with_capacity(256),
rstack: Vec::with_capacity(256),
dictionary: Vec::new(),
memory: vec![0; 65536],
here: 1, primitive_names: Vec::new(),
compiling: false,
current_def: None,
input_buffer: String::new(),
input_pos: 0,
running: true,
silent: false,
mesh: None,
output_buffer: None,
deadline: None,
timed_out: false,
execution_timeout: 10,
auto_claim: false,
code_strings: Vec::new(),
sandbox_active: false,
shell_enabled: false,
trusted_peers: HashSet::new(),
io_log: VecDeque::new(),
mutation_history: Vec::new(),
mutation_stats: crate::features::mutation::MutationStats::default(),
last_mutation_result: None,
rng: crate::features::mutation::SimpleRng::new(0), fitness: crate::features::fitness::FitnessTracker::new(),
spawn_state: crate::spawn::SpawnState::new(),
monitor: crate::features::monitor::MonitorState::new(),
ws_state: None,
ws_events: None,
ws_mesh_json: std::sync::Arc::new(std::sync::Mutex::new(String::new())),
anon_depth: 0,
auto_save_enabled: false,
auto_save_interval: 5,
tasks_since_save: 0,
node_id_cache: None,
auto_snapshot_secs: 0,
auto_snapshot_last: None,
kernel_word_count: 0,
evolution: None,
dist_engine: crate::distgoal::DistEngine::new(),
challenge_registry: crate::challenges::ChallengeRegistry::new(&[0; 8]),
problem_detector: crate::discovery::ProblemDetector::new(),
energy: crate::energy::EnergyState::new(),
landscape: crate::landscape::LandscapeEngine::new(),
last_solved_target: None,
mate_auto_accept: true,
mating_offspring: Vec::new(),
pending_mate_request: None,
niche_profile: crate::niche::NicheProfile::new(),
};
vm.register_primitives();
vm
}
pub(crate) fn register_primitives(&mut self) {
let prims: &[(&str, usize, bool)] = &[
("DUP", P_DUP, false),
("DROP", P_DROP, false),
("SWAP", P_SWAP, false),
("OVER", P_OVER, false),
("ROT", P_ROT, false),
("@", P_FETCH, false),
("!", P_STORE, false),
("+", P_ADD, false),
("-", P_SUB, false),
("*", P_MUL, false),
("/", P_DIV, false),
("MOD", P_MOD, false),
("=", P_EQ, false),
("<", P_LT, false),
(">", P_GT, false),
("AND", P_AND, false),
("OR", P_OR, false),
("NOT", P_NOT, false),
("EMIT", P_EMIT, false),
("KEY", P_KEY, false),
("CR", P_CR, false),
(".", P_DOT, false),
(".S", P_DOT_S, false),
(":", P_COLON, false),
(";", P_SEMICOLON, true),
("CREATE", P_CREATE, false),
("DOES>", P_DOES, true),
("VARIABLE", P_VARIABLE, false),
("CONSTANT", P_CONSTANT, false),
("IF", P_IF, true),
("ELSE", P_ELSE, true),
("THEN", P_THEN, true),
("DO", P_DO, true),
("LOOP", P_LOOP, true),
("BEGIN", P_BEGIN, true),
("UNTIL", P_UNTIL, true),
("WHILE", P_WHILE, true),
("REPEAT", P_REPEAT, true),
(".\"", P_DOT_QUOTE, true),
("(", P_PAREN, true),
("\\", P_BACKSLASH, true),
("WORDS", P_WORDS, false),
("SEE", P_SEE, false),
("QUIT", P_QUIT, false),
("BYE", P_BYE, false),
("SEND", P_SEND, false),
("RECV", P_RECV, false),
("PEERS", P_PEERS, false),
("REPLICATE", P_REPLICATE, false),
("MUTATE", P_MUTATE, false),
("RECURSE", P_RECURSE, true),
("MESH-STATUS", P_MESH_STATUS, false),
("PROPOSE", P_PROPOSE, false),
("LOAD", P_LOAD, false),
("CAPACITY", P_CAPACITY, false),
("ID", P_ID, false),
("TYPE", P_TYPE, false),
("GOAL\"", P_GOAL, true),
("GOALS", P_GOALS, false),
("TASKS", P_TASKS, false),
("TASK-STATUS", P_TASK_STATUS, false),
("CANCEL", P_CANCEL, false),
("STEER", P_STEER, false),
("REPORT", P_REPORT, false),
("CLAIM", P_CLAIM, false),
("COMPLETE", P_COMPLETE, false),
("GOAL{", P_GOAL_EXEC, true),
("EVAL\"", P_EVAL, true),
("RESULT", P_RESULT, false),
("AUTO-CLAIM", P_AUTO_CLAIM, false),
("TIMEOUT", P_TIMEOUT, false),
("GOAL-RESULT", P_GOAL_RESULT, false),
("FILE-READ\"", P_FILE_READ, true),
("FILE-WRITE\"", P_FILE_WRITE, true),
("FILE-EXISTS\"", P_FILE_EXISTS, true),
("FILE-LIST\"", P_FILE_LIST, true),
("FILE-DELETE\"", P_FILE_DELETE, true),
("HTTP-GET\"", P_HTTP_GET, true),
("HTTP-POST\"", P_HTTP_POST, true),
("SHELL\"", P_SHELL, true),
("ENV\"", P_ENV, true),
("TIMESTAMP", P_TIMESTAMP, false),
("SLEEP", P_SLEEP, false),
("SANDBOX-ON", P_SANDBOX_ON, false),
("SANDBOX-OFF", P_SANDBOX_OFF, false),
("IO-LOG", P_IO_LOG, false),
("MUTATE", P_MUTATE_RAND, false),
("MUTATE-WORD\"", P_MUTATE_WORD, true),
("UNDO-MUTATE", P_UNDO_MUTATE, false),
("MUTATIONS", P_MUTATIONS, false),
("FITNESS", P_FITNESS, false),
("LEADERBOARD", P_LEADERBOARD, false),
("RATE", P_RATE, false),
("EVOLVE", P_EVOLVE, false),
("AUTO-EVOLVE", P_AUTO_EVOLVE, false),
("BENCHMARK\"", P_BENCHMARK, true),
("TRUST", P_TRUST, false),
("TRUST-ALL", P_TRUST_ALL, false),
("TRUST-NONE", P_TRUST_NONE, false),
("SHELL-ENABLE", P_SHELL_ENABLE, false),
("REIDENTIFY", P_REIDENTIFY, false),
("SAVE", P_SAVE, false),
("LOAD-STATE", P_LOAD_STATE, false),
("AUTO-SAVE", P_AUTO_SAVE, false),
("RESET", P_RESET, false),
("SNAPSHOTS", P_SNAPSHOTS, false),
("SNAPSHOT", P_SNAPSHOT, false),
("RESTORE", P_RESTORE, false),
("I", P_I, false),
("J", P_J, false),
("SPAWN", P_SPAWN, false),
("SPAWN-N", P_SPAWN_N, false),
("PACKAGE", P_PACKAGE, false),
("PACKAGE-SIZE", P_PACKAGE_SIZE, false),
("CHILDREN", P_CHILDREN, false),
("FAMILY", P_FAMILY, false),
("GENERATION", P_GENERATION, false),
("KILL-CHILD", P_KILL_CHILD, false),
("REPLICATE-TO\"", P_REPLICATE_TO, true),
("ACCEPT-REPLICATE", P_ACCEPT_REPL, false),
("DENY-REPLICATE", P_DENY_REPL, false),
("QUARANTINE", P_QUARANTINE, false),
("MAX-CHILDREN", P_MAX_CHILDREN, false),
("WATCH\"", P_WATCH_URL, true),
("WATCH-FILE\"", P_WATCH_FILE, true),
("WATCH-PROC\"", P_WATCH_PROC, true),
("WATCHES", P_WATCHES, false),
("UNWATCH", P_UNWATCH, false),
("WATCH-LOG", P_WATCH_LOG, false),
("ON-ALERT\"", P_ON_ALERT, true),
("ALERTS", P_ALERTS, false),
("ACK", P_ACK, false),
("ALERT-HISTORY", P_ALERT_HISTORY, false),
("DASHBOARD", P_DASHBOARD, false),
("HEALTH", P_HEALTH, false),
("UPTIME", P_UPTIME, false),
("EVERY", P_EVERY, false),
("SCHEDULE", P_SCHEDULE, false),
("UNSCHED", P_UNSCHED, false),
("HEAL", P_HEAL, false),
("HEALTH-PORT", P_HEALTH_PORT, false),
("ALERT-THRESHOLD", P_ALERT_THRESHOLD, true),
("WS-STATUS", P_WS_STATUS, false),
("WS-CLIENTS", P_WS_CLIENTS, false),
("WS-PORT", P_WS_PORT, false),
("WS-BROADCAST\"", P_WS_BROADCAST, true),
("DISCOVER", P_DISCOVER, false),
("AUTO-DISCOVER", P_AUTO_DISCOVER, false),
("SHARE\"", P_SHARE_WORD, true),
("SHARE-ALL", P_SHARE_ALL, false),
("AUTO-SHARE", P_AUTO_SHARE, false),
("SHARED-WORDS", P_SHARED_WORDS, false),
("AUTO-SPAWN", P_AUTO_SPAWN_TOGGLE, false),
("AUTO-CULL", P_AUTO_CULL_TOGGLE, false),
("MIN-UNITS", P_MIN_UNITS, false),
("MAX-UNITS", P_MAX_UNITS, false),
("SWARM-STATUS", P_SWARM_STATUS, false),
("TRUST-ALL", P_TRUST_ALL_LEVEL, false),
("TRUST-MESH", P_TRUST_MESH, false),
("TRUST-FAMILY", P_TRUST_FAMILY, false),
("TRUST-NONE", P_TRUST_NONE_LEVEL, false),
("TRUST-LEVEL", P_TRUST_LEVEL, false),
("REQUESTS", P_REQUESTS, false),
("ACCEPT", P_ACCEPT_REQ, false),
("DENY", P_DENY_REQ, false),
("DENY-ALL", P_DENY_ALL_REQ, false),
("REPLICATION-LOG", P_REPLICATION_LOG, false),
("GOAL-COUNT", P_GOAL_COUNT, false),
("TASK-COUNT", P_TASK_COUNT, false),
("WATCH-COUNT", P_WATCH_COUNT, false),
("ALERT-COUNT", P_ALERT_COUNT, false),
("CHILD-COUNT", P_CHILD_COUNT, false),
("MESH-AVG-FITNESS", P_MESH_AVG_FITNESS, false),
("CHECK-WATCHES", P_CHECK_WATCHES, false),
("RUN-HANDLERS", P_RUN_HANDLERS, false),
("RUN-BENCHMARK", P_RUN_BENCHMARK, false),
("MUTATE-RANDOM", P_MUTATE_RANDOM, false),
("UNDO-LAST-MUTATION", P_UNDO_LAST_MUTATION, false),
("PEER-COUNT", P_PEER_COUNT, false),
("SMART-MUTATE", P_SMART_MUTATE, false),
("MUTATION-REPORT", P_MUTATION_REPORT, false),
("MUTATION-STATS", P_MUTATION_STATS, false),
("SEXP\"", P_SEXP_EVAL, true),
("SEXP-SEND\"", P_SEXP_SEND, true),
("SEXP-RECV", P_SEXP_RECV, false),
("JSON-SNAPSHOT", P_JSON_SNAPSHOT, false),
("JSON-RESTORE", P_JSON_RESTORE, false),
("SNAPSHOT-PATH", P_SNAPSHOT_PATH, false),
("JSON-SNAPSHOTS", P_JSON_SNAPSHOTS, false),
("AUTO-SNAPSHOT", P_AUTO_SNAPSHOT, false),
("HIBERNATE", P_HIBERNATE, false),
("EXPORT-GENOME", P_EXPORT_GENOME, false),
("IMPORT-GENOME\"", P_IMPORT_GENOME, true),
("GP-EVOLVE", P_GP_EVOLVE, false),
("GP-STATUS", P_GP_STATUS, false),
("GP-BEST", P_GP_BEST, false),
("GP-STOP", P_GP_STOP, false),
("GP-RESET", P_GP_RESET, false),
("DIST-GOAL{", P_DIST_GOAL, true),
("DIST-STATUS", P_DIST_STATUS, false),
("DIST-CANCEL", P_DIST_CANCEL, false),
("MY-ADDR", P_MY_ADDR, false),
("PEER-TABLE", P_PEER_TABLE, false),
("MESH-KEY", P_MESH_KEY, false),
("CONNECT\"", P_CONNECT, true),
("DISCONNECT\"", P_DISCONNECT, true),
("MESH-STATS", P_MESH_STATS, false),
("HERE", P_HERE, false),
(",", P_COMMA, false),
("C,", P_COMMA, false), ("ALLOT", P_ALLOT, false),
("CELLS", P_CELLS, false),
("CHALLENGES", P_CHALLENGES, false),
("IMMUNE-STATUS", P_IMMUNE_STATUS, false),
("ANTIBODIES", P_ANTIBODIES, false),
("ENERGY", P_ENERGY, false),
("METABOLISM", P_METABOLISM, false),
("FEED", P_FEED, false),
("LANDSCAPE", P_LANDSCAPE, false),
("DEPTH", P_DEPTH, false),
("GENERATORS", P_GENERATORS, false),
("META-EVOLVE", P_META_EVOLVE, false),
("SCORERS", P_SCORERS, false),
("META-DEPTH", P_META_DEPTH, false),
("GENERATE-CHALLENGE", P_GENERATE_CHALLENGE, false),
("EVOLUTION-STATS", P_EVOLUTION_STATS, false),
("MATE", P_MATE, false),
("MATE-STATUS", P_MATE_STATUS, false),
("ACCEPT-MATE", P_ACCEPT_MATE, false),
("DENY-MATE", P_DENY_MATE, false),
("OFFSPRING", P_OFFSPRING, false),
("NICHE", P_NICHE, false),
("NICHE-HISTORY", P_NICHE_HISTORY, false),
("ECOLOGY", P_ECOLOGY, false),
("SUBTASK{", P_SUBTASK, true),
("FORK", P_FORK, false),
("RESULTS", P_RESULTS, false),
("REDUCE\"", P_REDUCE, true),
("PROGRESS", P_PROGRESS, false),
];
for &(name, id, immediate) in prims {
self.primitive_names.push((name.to_string(), id));
self.dictionary.push(Entry {
name: name.to_string(),
immediate,
hidden: false,
body: vec![Instruction::Primitive(id)],
});
}
}
pub fn next_word(&mut self) -> Option<String> {
let bytes = self.input_buffer.as_bytes();
while self.input_pos < bytes.len() && (bytes[self.input_pos] as char).is_ascii_whitespace()
{
self.input_pos += 1;
}
if self.input_pos >= bytes.len() {
return None;
}
let start = self.input_pos;
while self.input_pos < bytes.len() && !(bytes[self.input_pos] as char).is_ascii_whitespace()
{
self.input_pos += 1;
}
Some(self.input_buffer[start..self.input_pos].to_string())
}
pub fn parse_until(&mut self, delim: char) -> String {
let bytes = self.input_buffer.as_bytes();
if self.input_pos < bytes.len() && bytes[self.input_pos] == b' ' {
self.input_pos += 1;
}
let start = self.input_pos;
while self.input_pos < bytes.len() && bytes[self.input_pos] as char != delim {
self.input_pos += 1;
}
let result = self.input_buffer[start..self.input_pos].to_string();
if self.input_pos < bytes.len() {
self.input_pos += 1; }
result
}
pub fn find_word(&self, name: &str) -> Option<usize> {
let upper = name.to_uppercase();
self.dictionary
.iter()
.rposition(|e| !e.hidden && e.name == upper)
}
pub fn interpret_line(&mut self, line: &str) {
self.input_buffer = line.to_string();
self.input_pos = 0;
while let Some(word) = self.next_word() {
if !self.running {
return;
}
let upper = word.to_uppercase();
if self.compiling {
self.compile_word(&upper);
} else {
self.interpret_word(&upper);
}
}
}
pub(crate) fn interpret_word(&mut self, word: &str) {
if let Some(idx) = self.find_word(word) {
self.execute_word(idx);
return;
}
if let Ok(n) = word.parse::<Cell>() {
self.stack.push(n);
return;
}
if !self.silent {
self.emit_str(&format!("error: unknown word '{}'\n", word));
}
}
pub(crate) fn compile_word(&mut self, word: &str) {
if let Some(idx) = self.find_word(word) {
if self.dictionary[idx].immediate {
self.execute_word(idx);
} else if let Some(ref mut def) = self.current_def {
def.body.push(Instruction::Call(idx));
}
return;
}
if let Ok(n) = word.parse::<Cell>() {
if let Some(ref mut def) = self.current_def {
def.body.push(Instruction::Literal(n));
}
return;
}
self.emit_str(&format!("error: unknown word '{}'\n", word));
self.compiling = false;
self.current_def = None;
}
pub(crate) fn execute_word(&mut self, dict_idx: usize) {
let body = self.dictionary[dict_idx].body.clone();
self.execute_body(&body);
}
pub(crate) fn execute_body(&mut self, body: &[Instruction]) {
let mut ip: usize = 0;
while ip < body.len() {
if self.timed_out {
return;
}
#[cfg(not(target_arch = "wasm32"))]
if let Some(deadline) = self.deadline {
if Instant::now() > deadline {
self.timed_out = true;
return;
}
}
match &body[ip] {
Instruction::Primitive(id) => match *id {
P_DO_RT => self.rt_do(),
P_LOOP_RT => self.rt_loop(),
P_GOAL_EXEC_RT => self.rt_goal_exec(),
P_IO_RT => self.rt_io(),
P_MUTATE_WORD_RT => self.rt_mutate_word(),
P_BENCHMARK_RT => self.rt_benchmark(),
P_REDUCE_RT => self.rt_reduce(),
P_WATCH_URL_RT => self.rt_watch(0),
P_WATCH_FILE_RT => self.rt_watch(1),
P_WATCH_PROC_RT => self.rt_watch(2),
P_ON_ALERT_RT => self.rt_on_alert(),
P_EVERY_RT => self.rt_every(),
P_ALERT_THRESHOLD_RT => self.rt_alert_threshold(),
_ => self.execute_primitive(*id),
},
Instruction::Literal(val) => {
self.stack.push(*val);
}
Instruction::Call(idx) => {
let callee = self.dictionary[*idx].body.clone();
self.execute_body(&callee);
}
Instruction::StringLit(s) => {
self.emit_str(s);
}
Instruction::Branch(offset) => {
ip = (ip as i64 + offset) as usize;
continue;
}
Instruction::BranchIfZero(offset) => {
let flag = self.pop();
if flag == 0 {
ip = (ip as i64 + offset) as usize;
continue;
}
}
}
ip += 1;
}
}
pub(crate) fn execute_primitive(&mut self, id: usize) {
match id {
P_DUP => self.prim_dup(),
P_DROP => self.prim_drop(),
P_SWAP => self.prim_swap(),
P_OVER => self.prim_over(),
P_ROT => self.prim_rot(),
P_FETCH => self.prim_fetch(),
P_STORE => self.prim_store(),
P_ADD => self.prim_add(),
P_SUB => self.prim_sub(),
P_MUL => self.prim_mul(),
P_DIV => self.prim_div(),
P_MOD => self.prim_mod(),
P_EQ => self.prim_eq(),
P_LT => self.prim_lt(),
P_GT => self.prim_gt(),
P_AND => self.prim_and(),
P_OR => self.prim_or(),
P_NOT => self.prim_not(),
P_EMIT => self.prim_emit(),
P_KEY => self.prim_key(),
P_CR => self.prim_cr(),
P_DOT => self.prim_dot(),
P_DOT_S => self.prim_dot_s(),
P_COLON => self.prim_colon(),
P_SEMICOLON => self.prim_semicolon(),
P_CREATE => self.prim_create(),
P_DOES => self.prim_does(),
P_VARIABLE => self.prim_variable(),
P_CONSTANT => self.prim_constant(),
P_IF => self.prim_if(),
P_ELSE => self.prim_else(),
P_THEN => self.prim_then(),
P_DO => self.prim_do(),
P_LOOP => self.prim_loop(),
P_BEGIN => self.prim_begin(),
P_UNTIL => self.prim_until(),
P_WHILE => self.prim_while(),
P_REPEAT => self.prim_repeat(),
P_DOT_QUOTE => self.prim_dot_quote(),
P_PAREN => self.prim_paren(),
P_BACKSLASH => self.prim_backslash(),
P_WORDS => self.prim_words(),
P_SEE => self.prim_see(),
P_QUIT => self.prim_quit(),
P_BYE => self.prim_bye(),
P_SEND => self.prim_send(),
P_RECV => self.prim_recv(),
P_PEERS => self.prim_peers(),
P_REPLICATE => self.prim_replicate(),
P_MUTATE => self.prim_mutate(),
P_RECURSE => self.prim_recurse(),
P_MESH_STATUS => self.prim_mesh_status(),
P_PROPOSE => self.prim_propose(),
P_LOAD => self.prim_mesh_load(),
P_CAPACITY => self.prim_mesh_capacity(),
P_ID => self.prim_id(),
P_TYPE => self.prim_type(),
P_GOAL => self.prim_goal(),
P_GOALS => self.prim_goals(),
P_TASKS => self.prim_tasks(),
P_TASK_STATUS => self.prim_task_status(),
P_CANCEL => self.prim_cancel(),
P_STEER => self.prim_steer(),
P_REPORT => self.prim_report(),
P_CLAIM => self.prim_claim(),
P_COMPLETE => self.prim_complete(),
P_GOAL_EXEC => self.prim_goal_exec(),
P_EVAL => self.prim_eval(),
P_RESULT => self.prim_result(),
P_AUTO_CLAIM => self.prim_auto_claim(),
P_TIMEOUT => self.prim_timeout(),
P_GOAL_RESULT => self.prim_goal_result(),
P_FILE_READ => self.io_immediate(0),
P_FILE_WRITE => self.io_immediate(1),
P_FILE_EXISTS => self.io_immediate(2),
P_FILE_LIST => self.io_immediate(3),
P_FILE_DELETE => self.io_immediate(4),
P_HTTP_GET => self.io_immediate(5),
P_HTTP_POST => self.io_immediate(6),
P_SHELL => self.io_immediate(7),
P_ENV => self.io_immediate(8),
P_TIMESTAMP => self.prim_timestamp(),
P_SLEEP => self.prim_sleep(),
P_SANDBOX_ON => {
self.sandbox_active = true;
self.emit_str("sandbox: ON\n");
}
P_SANDBOX_OFF => {
self.sandbox_active = false;
self.emit_str("sandbox: OFF\n");
}
P_IO_LOG => self.prim_io_log(),
P_MUTATE_RAND => self.prim_mutate_rand(),
P_MUTATE_WORD => self.prim_mutate_word(),
P_UNDO_MUTATE => self.prim_undo_mutate(),
P_MUTATIONS => self.prim_mutations(),
P_FITNESS => {
let s = self.fitness.score;
self.stack.push(s);
}
P_LEADERBOARD => self.prim_leaderboard(),
P_RATE => self.prim_rate(),
P_EVOLVE => self.prim_evolve(),
P_AUTO_EVOLVE => self.prim_auto_evolve(),
P_BENCHMARK => self.prim_benchmark(),
P_TRUST => self.prim_trust(),
P_TRUST_ALL => {
self.trusted_peers.clear();
self.emit_str("trust: ALL (cleared)\n");
}
P_TRUST_NONE => {
self.trusted_peers.clear();
self.emit_str("trust: NONE\n");
}
P_SHELL_ENABLE => {
self.shell_enabled = !self.shell_enabled;
self.emit_str(&format!(
"shell: {}\n",
if self.shell_enabled {
"ENABLED"
} else {
"DISABLED"
}
));
}
P_REIDENTIFY => self.prim_reidentify(),
P_SAVE => self.prim_save(),
P_LOAD_STATE => self.prim_load_state(),
P_AUTO_SAVE => self.prim_auto_save(),
P_RESET => self.prim_reset(),
P_SNAPSHOTS => self.prim_snapshots(),
P_SNAPSHOT => self.prim_snapshot(),
P_RESTORE => self.prim_restore(),
P_I => {
let index = self.rstack.last().copied().unwrap_or(0);
self.stack.push(index);
}
P_J => {
let len = self.rstack.len();
let index = if len >= 3 { self.rstack[len - 3] } else { 0 };
self.stack.push(index);
}
P_SPAWN => self.prim_spawn(),
P_SPAWN_N => self.prim_spawn_n(),
P_PACKAGE => self.prim_package(),
P_PACKAGE_SIZE => self.prim_package_size(),
P_CHILDREN => self.prim_children(),
P_FAMILY => self.prim_family(),
P_GENERATION => {
let g = self.spawn_state.generation as Cell;
self.stack.push(g);
}
P_KILL_CHILD => self.prim_kill_child(),
P_REPLICATE_TO => self.prim_replicate_to(),
P_ACCEPT_REPL => {
self.spawn_state.accept_replicate = true;
self.emit_str("accept-replicate: ON\n");
}
P_DENY_REPL => {
self.spawn_state.accept_replicate = false;
self.emit_str("accept-replicate: OFF\n");
}
P_QUARANTINE => {
self.spawn_state.quarantine = !self.spawn_state.quarantine;
self.emit_str(&format!(
"quarantine: {}\n",
if self.spawn_state.quarantine {
"ON"
} else {
"OFF"
}
));
}
P_MAX_CHILDREN => {
let n = self.pop() as usize;
self.spawn_state.max_children = n;
self.emit_str(&format!("max-children: {}\n", n));
}
P_WATCH_URL => self.prim_watch(0),
P_WATCH_FILE => self.prim_watch(1),
P_WATCH_PROC => self.prim_watch(2),
P_WATCHES => {
let s = self.monitor.format_watches();
self.emit_str(&s);
}
P_UNWATCH => {
let id = self.pop() as u32;
self.monitor.remove_watch(id);
self.emit_str(&format!("watch #{} removed\n", id));
}
P_WATCH_LOG => {
let id = self.pop() as u32;
let s = self.monitor.format_watch_log(id);
self.emit_str(&s);
}
P_ON_ALERT => self.prim_on_alert(),
P_ALERTS => {
let s = self.monitor.format_alerts();
self.emit_str(&s);
}
P_ACK => {
let id = self.pop() as u32;
self.monitor.ack_alert(id);
self.emit_str(&format!("alert #{} acknowledged\n", id));
}
P_ALERT_HISTORY => {
let s = self.monitor.format_alert_history();
self.emit_str(&s);
}
P_DASHBOARD => self.prim_dashboard(),
P_HEALTH => self.prim_health(),
P_UPTIME => {
let id = self.pop() as u32;
let pct = self.monitor.uptime(id);
self.emit_str(&format!("watch #{}: {:.1}% uptime\n", id, pct));
}
P_EVERY => self.prim_every(),
P_SCHEDULE => {
let s = self.monitor.format_schedules();
self.emit_str(&s);
}
P_UNSCHED => {
let id = self.pop() as u32;
self.monitor.remove_schedule(id);
self.emit_str(&format!("schedule #{} removed\n", id));
}
P_HEAL => self.prim_heal(),
P_HEALTH_PORT => {
let port = self.mesh.as_ref().map(|m| m.repl_port).unwrap_or(0);
self.stack.push(port as Cell);
}
P_ALERT_THRESHOLD => self.prim_alert_threshold(),
P_WS_STATUS => self.prim_ws_status(),
P_WS_CLIENTS => self.prim_ws_clients(),
P_WS_PORT => {
let port = self
.ws_state
.as_ref()
.map(|s| s.lock().unwrap().port as Cell)
.unwrap_or(0);
self.stack.push(port);
}
P_WS_BROADCAST => self.prim_ws_broadcast(),
P_DISCOVER => self.prim_discover(),
P_AUTO_DISCOVER => self.prim_auto_discover(),
P_SHARE_WORD => self.prim_share_word(),
P_SHARE_ALL => self.prim_share_all(),
P_AUTO_SHARE => self.prim_auto_share(),
P_SHARED_WORDS => self.prim_shared_words(),
P_AUTO_SPAWN_TOGGLE => self.prim_auto_spawn(),
P_AUTO_CULL_TOGGLE => self.prim_auto_cull(),
P_MIN_UNITS => self.prim_min_units(),
P_MAX_UNITS => self.prim_max_units(),
P_SWARM_STATUS => self.prim_swarm_status(),
P_TRUST_ALL_LEVEL => self.prim_trust_all_level(),
P_TRUST_MESH => self.prim_trust_mesh(),
P_TRUST_FAMILY => self.prim_trust_family(),
P_TRUST_NONE_LEVEL => self.prim_trust_none_level(),
P_TRUST_LEVEL => self.prim_trust_level(),
P_REQUESTS => self.prim_requests(),
P_ACCEPT_REQ => self.prim_accept_req(),
P_DENY_REQ => self.prim_deny_req(),
P_DENY_ALL_REQ => self.prim_deny_all_req(),
P_REPLICATION_LOG => self.prim_replication_log(),
P_GOAL_COUNT => self.prim_goal_count(),
P_TASK_COUNT => self.prim_task_count(),
P_WATCH_COUNT => {
let n = self.monitor.watches.len() as Cell;
self.stack.push(n);
}
P_ALERT_COUNT => {
let n = self.monitor.alerts.len() as Cell;
self.stack.push(n);
}
P_CHILD_COUNT => {
let n = self.spawn_state.children.len() as Cell;
self.stack.push(n);
}
P_MESH_AVG_FITNESS => self.prim_mesh_avg_fitness(),
P_CHECK_WATCHES => self.prim_check_watches(),
P_RUN_HANDLERS => self.prim_run_handlers(),
P_RUN_BENCHMARK => {
let s = self.run_benchmark();
self.stack.push(s);
}
P_MUTATE_RANDOM => self.prim_mutate_random_atom(),
P_UNDO_LAST_MUTATION => self.prim_undo_mutate(),
P_PEER_COUNT => {
let n = self.mesh.as_ref().map(|m| m.peer_count()).unwrap_or(0) as Cell;
self.stack.push(n);
}
P_SMART_MUTATE => self.prim_smart_mutate(),
P_MUTATION_REPORT => self.prim_mutation_report(),
P_MUTATION_STATS => {
let s = self.mutation_stats.format();
self.emit_str(&s);
self.emit_str("\n");
}
P_SEXP_EVAL => self.prim_sexp_eval(),
P_SEXP_SEND => self.prim_sexp_send(),
P_SEXP_RECV => self.prim_sexp_recv(),
P_JSON_SNAPSHOT => self.prim_json_snapshot(),
P_JSON_RESTORE => self.prim_json_restore(),
P_SNAPSHOT_PATH => self.prim_snapshot_path(),
P_JSON_SNAPSHOTS => self.prim_json_snapshots(),
P_AUTO_SNAPSHOT => self.prim_auto_snapshot(),
P_HIBERNATE => self.prim_hibernate(),
P_EXPORT_GENOME => self.prim_export_genome(),
P_IMPORT_GENOME => self.prim_import_genome(),
P_GP_EVOLVE => self.prim_gp_evolve(),
P_GP_STATUS => self.prim_gp_status(),
P_GP_BEST => self.prim_gp_best(),
P_GP_STOP => self.prim_gp_stop(),
P_GP_RESET => self.prim_gp_reset(),
P_DIST_GOAL => self.prim_dist_goal(),
P_DIST_STATUS => self.prim_dist_status(),
P_DIST_CANCEL => self.prim_dist_cancel(),
P_MY_ADDR => self.prim_my_addr(),
P_PEER_TABLE => self.prim_peer_table(),
P_MESH_KEY => self.prim_mesh_key(),
P_CONNECT => self.prim_connect(),
P_DISCONNECT => self.prim_disconnect(),
P_MESH_STATS => self.prim_mesh_stats(),
P_HERE => {
let h = self.here as Cell;
self.stack.push(h);
}
P_COMMA => {
let val = self.pop();
if self.here < self.memory.len() {
self.memory[self.here] = val;
self.here += 1;
} else {
self.emit_str("error: memory full\n");
}
}
P_ALLOT => {
let n = self.pop() as usize;
if self.here + n <= self.memory.len() {
self.here += n;
} else {
self.emit_str("error: not enough memory\n");
}
}
P_CELLS => {} P_CHALLENGES => self.prim_challenges(),
P_IMMUNE_STATUS => self.prim_immune_status(),
P_ANTIBODIES => self.prim_antibodies(),
P_ENERGY => {
let s = self.energy.format();
self.emit_str(&s);
self.emit_str("\n");
}
P_METABOLISM => self.prim_metabolism(),
P_FEED => {
let amount = self.pop().clamp(0, 500);
self.energy.earn(amount, "manual-feed");
self.emit_str(&format!("fed {} energy\n", amount));
}
P_LANDSCAPE => {
let s = self.landscape.format_landscape();
self.emit_str(&s);
}
P_DEPTH => {
let d = self.landscape.depth();
self.emit_str(&format!("evolutionary depth: {}\n", d));
}
P_GENERATORS => {
let s = self.landscape.meta.format_top(5);
self.emit_str(&s);
}
P_META_EVOLVE => {
let mut rng = crate::features::mutation::SimpleRng::new(
self.landscape.meta.generation as u64 + 1,
);
self.landscape.meta.evolve_generators(&mut rng);
self.emit_str(&format!(
"meta-evolution generation {}\n",
self.landscape.meta.generation
));
}
P_SCORERS => {
let s = self.landscape.scoring.format_top(3);
self.emit_str(&s);
}
P_META_DEPTH => {
let sol_count = self
.challenge_registry
.challenges
.values()
.filter(|c| c.solved)
.count();
let gen_count = self.landscape.meta.genomes.len();
let scorer_count = self.landscape.scoring.scorers.len();
let out = format!(
"first-order: {} solutions evolved\n\
second-order: {} generators evolved (gen {})\n\
third-order: {} scoring functions evolved (gen {})\n",
sol_count,
gen_count,
self.landscape.meta.generation,
scorer_count,
self.landscape.scoring.generation,
);
self.emit_str(&out);
}
P_GENERATE_CHALLENGE => {
if let Some(target) = self.last_solved_target {
if let Some((new_target, gen_program)) =
self.landscape.meta.generate_target(target)
{
let my_id = self.node_id_cache.unwrap_or([0; 8]);
let reward =
80 + (self.landscape.meta.best.as_ref().map_or(0.0, |b| b.fitness)
* 0.5) as i64;
let name = format!("evolved-gen{}", self.landscape.meta.generation);
let id = self.challenge_registry.register_discovered(
&name,
&format!("evolved from generator: {}", gen_program),
&format!("{} ", new_target),
None,
vec![format!("{} .", new_target)],
my_id,
reward,
);
self.landscape.evolved_count += 1;
self.landscape.challenges_generated += 1;
self.emit_str(&format!(
"generated challenge #{}: {} (target: {}, reward: {})\n\
generator: {}\n",
id, name, new_target, reward, gen_program
));
} else {
self.emit_str("no generator produced a valid challenge\n");
}
} else {
self.emit_str("solve a challenge first\n");
}
}
P_EVOLUTION_STATS => {
let depth = self.landscape.depth();
let authored = self.landscape.challenges_generated - self.landscape.evolved_count;
let evolved = self.landscape.evolved_count;
let env = self.landscape.environment.current_condition();
let top_gen = self
.landscape
.meta
.best
.as_ref()
.map(|g| format!("\"{}\" fitness={:.1}", g.program, g.fitness))
.unwrap_or_else(|| "none".to_string());
let top_scorer = self
.landscape
.scoring
.best
.as_ref()
.map(|s| format!("\"{}\" fitness={:.1}", s.program, s.fitness))
.unwrap_or_else(|| "none".to_string());
let history_size = self.landscape.scoring.history.len();
self.emit_str(&format!(
"--- evolution stats ---\n\
landscape depth: {}\n\
challenges generated: {} (authored: {}, evolved: {})\n\
environment: {}\n\
top generator: {}\n\
top scorer: {}\n\
scoring history: {} entries\n",
depth, authored + evolved, authored, evolved, env, top_gen, top_scorer, history_size
));
}
P_MATE => {
if !self.energy.can_afford(crate::energy::SPAWN_COST) {
self.emit_str(&format!(
"insufficient energy to mate (need {}, have {})\n",
crate::energy::SPAWN_COST, self.energy.energy
));
} else if let Some(ref m) = self.mesh {
let peers: Vec<(crate::mesh::NodeId, i64)> = m
.peer_fitness_list()
.iter()
.map(|p| (p.id, p.score))
.collect();
if peers.is_empty() {
self.emit_str("no peers available for mating\n");
} else {
let selected =
crate::reproduction::select_mate(&peers, &mut self.rng);
if let Some(mate_id) = selected {
let my_id = self.node_id_cache.unwrap_or([0; 8]);
let my_fitness = self.fitness.score;
let words: Vec<(String, String)> = self
.dictionary
.iter()
.filter(|e| !e.hidden && e.body.len() > 1)
.take(50)
.map(|e| (e.name.clone(), format!("{:?}", e.body)))
.collect();
let req = crate::reproduction::MatingRequest {
requester_id: my_id,
requester_fitness: my_fitness,
dictionary_words: words,
};
let sexp = crate::reproduction::sexp_mating_request(&req);
let hex = crate::mesh::id_to_hex(&mate_id);
let m_ref = self.mesh.as_ref().unwrap();
m_ref.send_sexp(&sexp);
self.emit_str(&format!(
"mating request sent to {}, awaiting response...\n",
hex
));
} else {
self.emit_str("no suitable mate found\n");
}
}
} else {
self.emit_str("mesh offline\n");
}
}
P_MATE_STATUS => {
let pending = if self.pending_mate_request.is_some() {
"pending request"
} else {
"none"
};
let offspring_count = self.mating_offspring.len();
self.emit_str(&format!(
"--- mating status ---\nauto-accept: {}\npending: {}\noffspring: {}\n",
self.mate_auto_accept, pending, offspring_count
));
let lines: Vec<String> = self.mating_offspring.iter()
.map(|(child, mate)| format!(" child {} x mate {}\n", child, mate))
.collect();
for line in &lines { self.emit_str(line); }
}
P_ACCEPT_MATE => {
self.mate_auto_accept = true;
self.emit_str("mating requests will be auto-accepted\n");
}
P_DENY_MATE => {
self.mate_auto_accept = false;
self.emit_str("mating requests will be denied\n");
}
P_OFFSPRING => {
if self.mating_offspring.is_empty() {
self.emit_str("no offspring from mating\n");
} else {
self.emit_str(&format!(
"--- {} offspring ---\n",
self.mating_offspring.len()
));
let lines: Vec<String> = self.mating_offspring.iter()
.map(|(child, mate)| format!(" child {} (mate: {})\n", child, mate))
.collect();
for line in &lines { self.emit_str(line); }
}
}
P_NICHE => {
let out = crate::niche::format_niche(&self.niche_profile);
self.emit_str(&out);
}
P_NICHE_HISTORY => {
if self.niche_profile.challenge_history.is_empty() {
self.emit_str("no challenge history\n");
} else {
let hist_len = self.niche_profile.challenge_history.len();
let start = hist_len.saturating_sub(20);
let lines: Vec<String> = self.niche_profile.challenge_history[start..].iter()
.map(|(cat, solved)| {
format!(" {} {}\n", cat, if *solved { "solved" } else { "failed" })
})
.collect();
self.emit_str("--- challenge history ---\n");
for line in &lines { self.emit_str(line); }
}
}
P_ECOLOGY => {
let dom = crate::niche::dominant_niche(&self.niche_profile);
let dom_str = dom
.map(|(name, s)| format!("{} ({:.0}%)", name, s * 100.0))
.unwrap_or_else(|| "generalist".to_string());
self.emit_str(&format!("--- ecology ---\nself niche: {}\n", dom_str));
if let Some(ref m) = self.mesh {
let peers = m.peer_table();
self.emit_str(&format!("colony size: {}\n", peers.len() + 1));
} else {
self.emit_str("colony size: 1 (solo)\n");
}
}
P_SUBTASK => self.prim_subtask(),
P_FORK => self.prim_fork(),
P_RESULTS => self.prim_results(),
P_REDUCE => self.prim_reduce(),
P_PROGRESS => self.prim_progress(),
_ => eprintln!("unknown primitive {}", id),
}
}
pub(crate) fn pop(&mut self) -> Cell {
self.stack.pop().unwrap_or_else(|| {
self.emit_str("error: stack underflow\n");
0
})
}
pub(crate) fn rpop(&mut self) -> Cell {
self.rstack.pop().unwrap_or_else(|| {
self.emit_str("error: return stack underflow\n");
0
})
}
pub(crate) fn emit_char(&mut self, ch: char) {
if let Some(ref mut buf) = self.output_buffer {
buf.push(ch);
} else {
print!("{}", ch);
let _ = io::stdout().flush();
}
}
pub(crate) fn emit_str(&mut self, s: &str) {
if let Some(ref mut buf) = self.output_buffer {
buf.push_str(s);
} else {
print!("{}", s);
let _ = io::stdout().flush();
}
}
pub fn eval(&mut self, input: &str) -> String {
self.output_buffer = Some(String::new());
for line in input.lines() {
self.interpret_line(line);
}
self.output_buffer.take().unwrap_or_default()
}
pub fn stack_top(&self) -> Option<Cell> {
self.stack.last().copied()
}
}