repl keeps its state

This commit is contained in:
Shautvast 2025-11-13 10:49:28 +01:00
parent bcd81677bb
commit d2106ccf96
4 changed files with 34 additions and 14 deletions

View file

@ -15,6 +15,7 @@ use crate::vm::{
}; };
use crate::{Registry, SymbolTable}; use crate::{Registry, SymbolTable};
use std::collections::HashMap; use std::collections::HashMap;
use std::mem;
pub fn compile( pub fn compile(
qualified_name: Option<&str>, qualified_name: Option<&str>,
@ -39,7 +40,7 @@ pub(crate) fn compile_function(
compiler.vars.insert(name, var_index); compiler.vars.insert(name, var_index);
} }
let mut chunk = compiler.compile(&function.body, symbols, registry, namespace)?.chunk; let mut chunk = compiler.compile(&function.body, symbols, registry, namespace)?;
chunk.function_parameters = function.parameters.to_vec(); chunk.function_parameters = function.parameters.to_vec();
Ok(chunk) Ok(chunk)
} }
@ -51,8 +52,8 @@ pub(crate) fn compile_in_namespace(
registry: &mut Registry, registry: &mut Registry,
) -> Result<(), CompilerErrorAtLine> { ) -> Result<(), CompilerErrorAtLine> {
let name = namespace.unwrap_or("main"); let name = namespace.unwrap_or("main");
let compiler = Compiler::new(name); let mut compiler = Compiler::new(name);
let chunk = compiler.compile(ast, symbols, registry, name)?.chunk; let chunk = compiler.compile(ast, symbols, registry, name)?;
let qname = if let Some(namespace) = namespace { let qname = if let Some(namespace) = namespace {
format!("{}/{}", namespace, "main") format!("{}/{}", namespace, "main")
} else { } else {
@ -80,18 +81,20 @@ impl Compiler {
} }
pub(crate) fn compile( pub(crate) fn compile(
mut self, &mut self,
ast: &Vec<Statement>, ast: &Vec<Statement>,
symbols: &SymbolTable, symbols: &SymbolTable,
registry: &mut Registry, registry: &mut Registry,
namespace: &str, namespace: &str,
) -> Result<Self, CompilerErrorAtLine> { ) -> Result<Chunk, CompilerErrorAtLine> {
for statement in ast { for statement in ast {
self.compile_statement(statement, symbols, registry, namespace)?; self.compile_statement(statement, symbols, registry, namespace)?;
} }
self.emit_byte(OP_RETURN); self.emit_byte(OP_RETURN);
Ok(self) let chunk = self.chunk.clone();
self.chunk.code.clear(); // in case the compiler is reused, clear it for the next compilation. This is for the REPL
Ok(chunk)
} }
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine { fn raise(&self, error: CompilerError) -> CompilerErrorAtLine {

View file

@ -20,6 +20,12 @@ pub struct Chunk {
pub vars: Vec<(TokenType, String)>, pub vars: Vec<(TokenType, String)>,
} }
impl Default for Chunk {
fn default() -> Self {
Chunk::new("")
}
}
impl Chunk { impl Chunk {
pub(crate) fn find_constant(&self, p0: &String) -> Option<usize> { pub(crate) fn find_constant(&self, p0: &String) -> Option<usize> {
for (i, constant) in self.constants.iter().enumerate() { for (i, constant) in self.constants.iter().enumerate() {

View file

@ -1,7 +1,8 @@
use crate::chunk::Chunk; use crate::chunk::Chunk;
use crate::errors::CrudLangError; use crate::errors::CrudLangError;
use crate::vm::interpret; use crate::scanner::scan;
use crate::{map_underlying, recompile}; use crate::vm::{Vm, interpret};
use crate::{ast_compiler, bytecode_compiler, map_underlying, recompile, symbol_builder};
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use std::collections::HashMap; use std::collections::HashMap;
use std::io; use std::io;
@ -12,6 +13,9 @@ use std::sync::Arc;
pub fn start(registry: Arc<ArcSwap<HashMap<String, Chunk>>>) -> Result<(), CrudLangError> { pub fn start(registry: Arc<ArcSwap<HashMap<String, Chunk>>>) -> Result<(), CrudLangError> {
println!("REPL started -- Type ctrl-c to exit (both the repl and the server)"); println!("REPL started -- Type ctrl-c to exit (both the repl and the server)");
println!(":h for help"); println!(":h for help");
let mut symbol_table = HashMap::new();
let mut vm = Vm::new(&registry.load());
let mut bytecode_compiler = bytecode_compiler::Compiler::new("main");
loop { loop {
print!(">"); print!(">");
io::stdout().flush().map_err(map_underlying())?; io::stdout().flush().map_err(map_underlying())?;
@ -27,21 +31,27 @@ pub fn start(registry: Arc<ArcSwap<HashMap<String, Chunk>>>) -> Result<(), CrudL
_ => { _ => {
let registry_copy = registry.load().clone(); let registry_copy = registry.load().clone();
let mut registry_copy = registry_copy.deref().clone(); let mut registry_copy = registry_copy.deref().clone();
match recompile(input, &mut registry_copy){
Ok(_)=> { let tokens = scan(input)?;
let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?;
symbol_builder::build("", &ast, &mut symbol_table);
match bytecode_compiler.compile(&ast, &symbol_table, &mut registry_copy, "") {
Ok(chunk) => {
registry_copy.insert("main".to_string(), chunk);
registry.store(Arc::new(registry_copy)); registry.store(Arc::new(registry_copy));
let result = match interpret(registry.load(), "main") { let result = match vm.run("main", registry.load().get("main").unwrap()) {
Ok(value) => value.to_string(), Ok(value) => value.to_string(),
Err(e) => e.to_string(), Err(e) => e.to_string(),
}; };
println!("{}", result); println!("{}", result);
}, }
Err(e) => { Err(e) => {
println!("{}", e); println!("{}", e);
} }
} }
} }
} }
// println!("[{}]",input); // println!("[{}]",input);

View file

@ -81,6 +81,7 @@ impl Vm {
} }
pub(crate) fn run(&mut self, context: &str, chunk: &Chunk) -> Result<Value, RuntimeError> { pub(crate) fn run(&mut self, context: &str, chunk: &Chunk) -> Result<Value, RuntimeError> {
self.ip = 0;
loop { loop {
if self.error_occurred { if self.error_occurred {
return Err(Something); return Err(Something);