Made interpreter state json serializable in Rust port

This commit is contained in:
Kyler Olsen 2025-12-04 23:06:42 -07:00
parent 7b57807fc7
commit dc5d75cf75
5 changed files with 151 additions and 12 deletions

View File

@ -6,6 +6,8 @@ edition = "2021"
[dependencies]
bitflags = "2.4"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[build-dependencies]
rustc_version = "0.4"

View File

@ -1,4 +1,10 @@
use crate::interpreter::{InterpreterState, StackValue, FunctionItem};
use crate::interpreter::{
InterpreterState,
StackValue,
FunctionItem,
BuiltinFunction,
BuiltinFn,
};
use crate::lexer::{Token, Identifier};
use std::collections::HashMap;
@ -1005,13 +1011,73 @@ pub fn builtin_type_of(state: &mut InterpreterState) -> bool {
true
}
pub fn lookup_builtin(name: &str) -> Option<BuiltinFn> {
if name == "+" { Some(builtin_addition) }
else if name == "-" { Some(builtin_subtraction) }
else if name == "*" { Some(builtin_multiplication) }
else if name == "/" { Some(builtin_division) }
else if name == "%" { Some(builtin_modulus) }
else if name == "^" { Some(builtin_exponential) }
else if name == ">" { Some(builtin_greater_than) }
else if name == ">=" { Some(builtin_greater_than_or_equal_to) }
else if name == "<" { Some(builtin_less_than) }
else if name == "<=" { Some(builtin_less_than_or_equal_to) }
else if name == "==" { Some(builtin_equal_to) }
else if name == "!=" { Some(builtin_not_equal_to) }
else if name == "abs" { Some(builtin_abs) }
else if name == "acos" { Some(builtin_acos) }
else if name == "asin" { Some(builtin_asin) }
else if name == "atan" { Some(builtin_atan) }
else if name == "atan2" { Some(builtin_atan2) }
else if name == "ceil" { Some(builtin_ceil) }
else if name == "floor" { Some(builtin_floor) }
else if name == "round" { Some(builtin_round) }
else if name == "sqrt" { Some(builtin_sqrt) }
else if name == "sin" { Some(builtin_sin) }
else if name == "cos" { Some(builtin_cos) }
else if name == "tan" { Some(builtin_tan) }
else if name == "ln" { Some(builtin_ln) }
else if name == "log" { Some(builtin_log) }
else if name == "and" { Some(builtin_and) }
else if name == "or" { Some(builtin_or) }
else if name == "not" { Some(builtin_not) }
else if name == "bitand" { Some(builtin_bitand) }
else if name == "bitnot" { Some(builtin_bitnot) }
else if name == "bitor" { Some(builtin_bitor) }
else if name == "bitxor" { Some(builtin_bitxor) }
else if name == "shl" { Some(builtin_shl) }
else if name == "shr" { Some(builtin_shr) }
else if name == "depth" { Some(builtin_depth) }
else if name == "drop" { Some(builtin_drop) }
else if name == "dup" { Some(builtin_dup) }
else if name == "swap" { Some(builtin_swap) }
else if name == "pick" { Some(builtin_pick) }
else if name == "roll" { Some(builtin_roll) }
else if name == "if" { Some(builtin_if) }
else if name == "while" { Some(builtin_while) }
else if name == "for" { Some(builtin_for) }
else if name == "lambda" { Some(builtin_lambda) }
else if name == "eval" { Some(builtin_eval) }
else if name == "const" { Some(builtin_const) }
else if name == "type_of" { Some(builtin_type_of) }
else if name == "rand" { Some(builtin_rand) }
else if name == "seed" { Some(builtin_seed) }
else { None }
}
// Helper to add builtin to function table
fn register_builtin(
functions: &mut HashMap<String, FunctionItem>,
name: &str,
func: fn(&mut InterpreterState) -> bool,
) {
functions.insert(name.to_string(), FunctionItem::Builtin(func));
functions.insert(name.to_string(), FunctionItem::Builtin(BuiltinFunction {
name: name.to_string(),
function: match lookup_builtin(name) {
Some(func) => func,
None => panic!("Builtin Not Found!"),
}
}));
}
pub fn load_builtins(state: &mut InterpreterState) -> bool {

View File

@ -1,11 +1,12 @@
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use crate::lexer::*; // Identifier, Token, TokenString, etc.
use crate::builtin::load_builtins;
use crate::builtin::{lookup_builtin, load_builtins};
pub type BuiltinFn = fn(&mut InterpreterState) -> bool;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StackValue {
Identifier(Identifier),
@ -31,12 +32,47 @@ pub enum StackValue {
}
#[derive(Debug, Clone)]
pub enum FunctionItem {
TokenString(TokenString),
Builtin(BuiltinFn),
pub struct BuiltinFunction {
pub name: String,
pub function: BuiltinFn,
}
#[derive(Debug)]
impl BuiltinFunction {
fn call(&self, interpreter: &mut InterpreterState) -> bool {
(self.function)(interpreter)
}
}
impl Serialize for BuiltinFunction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.name)
}
}
impl<'de> Deserialize<'de> for BuiltinFunction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let name = String::deserialize(deserializer)?;
let function = lookup_builtin(&name)
.ok_or_else(|| serde::de::Error::custom(format!("Unknown builtin: {}", name)))?;
Ok(BuiltinFunction { name, function })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FunctionItem {
TokenString(TokenString),
Builtin(BuiltinFunction),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct InterpreterState {
pub stack: Vec<StackValue>,
pub functions: HashMap<String, FunctionItem>,
@ -96,7 +132,7 @@ impl InterpreterState {
};
match item {
FunctionItem::Builtin(f) => f(self),
FunctionItem::Builtin(f) => f.call(self),
FunctionItem::TokenString(ts) => self.execute_token_string(&ts),
}
}

View File

@ -1,3 +1,5 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone)]
pub struct LexerInfo {
pub filename: String,
@ -60,7 +62,7 @@ impl LexerInfo {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Identifier {
pub name: String,
pub is_literal: bool,
@ -93,7 +95,7 @@ pub struct ShapedArray {
pub _shape: Vec<usize>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenString {
pub tokens: Vec<Token>,
}
@ -121,7 +123,7 @@ pub enum StructValue {
_Token(Token),
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Token {
Eof,
Identifier(Identifier),
@ -136,10 +138,13 @@ pub enum Token {
Float(f32),
Double(f64),
Character(u8),
#[serde(skip)]
StringLiteral(String),
Boolean(bool),
#[serde(skip)]
Array(ShapedArray),
TokenString(TokenString),
#[serde(skip)]
TypeTuple(TypeTuple),
}

View File

@ -1,4 +1,6 @@
use std::io::{self, Write};
use std::fs;
use serde_json;
use crate::lexer::{LexerInfo, LexResult, lexical_analysis};
use crate::print_version;
@ -62,6 +64,34 @@ pub fn repl() -> i32 {
return 0;
}
if let Some(file) = buf.trim_end().strip_prefix("#save ") {
match serde_json::to_string(&interpreter) {
Ok(json) => {
if let Err(err) = fs::write(file, json) {
eprintln!("Failed to save state: {}", err);
} else {
println!("State saved to {}", file);
}
}
Err(err) => eprintln!("Serialization error: {}", err),
}
continue;
}
if let Some(file) = buf.trim_end().strip_prefix("#load ") {
match fs::read_to_string(file) {
Ok(json) => match serde_json::from_str(&json) {
Ok(state) => {
interpreter = state;
println!("State restored from {}", file);
}
Err(err) => eprintln!("Deserialization error: {}", err),
},
Err(err) => eprintln!("Failed to read file: {}", err),
}
continue;
}
let code = buf.clone();
let mut lexer_info = LexerInfo::new(REPL_FILE_NAME, code.clone());
let result = lexical_analysis(&mut lexer_info);