add argument reading for lox

This commit is contained in:
Sebastian Hugentobler 2025-05-28 21:58:35 +02:00
parent 98dfbc8503
commit 97fdc89316
Signed by: shu
SSH key fingerprint: SHA256:ppcx6MlixdNZd5EUM1nkHOKoyQYoJwzuQKXM6J/t66M
6 changed files with 60 additions and 8 deletions

View file

@ -96,5 +96,6 @@ class Interpreter {
}
}
var interpreter = Interpreter("bf/game_of_life.bf");
var bfScript = args(0);
var interpreter = Interpreter(bfScript);
interpreter.run();

View file

@ -19,6 +19,9 @@ pub struct RunConfig {
/// Path to Lox source file.
#[arg(short, long)]
pub source: PathBuf,
/// Arguments to pass to the Lox script (must be after '--').
#[arg(last = true)]
pub script_args: Vec<String>,
}
/// Available commands for the Lox interpreter

View file

@ -60,12 +60,18 @@ pub struct Interpreter {
/// Default configuration for the interpreter, with builtin native functions.
impl Default for Interpreter {
fn default() -> Self {
Interpreter::new(Vec::new())
}
}
impl Interpreter {
pub fn new(cli_args: Vec<String>) -> Self {
let env: Rc<RefCell<Environment>> = Default::default();
{
// add all native functions to global environment
let mut env = env.borrow_mut();
for (name, fun) in native_functions::all() {
for (name, fun) in native_functions::all(cli_args) {
env.define(name, fun);
}
}
@ -76,9 +82,7 @@ impl Default for Interpreter {
locals: HashMap::new(),
}
}
}
impl Interpreter {
/// Execute a list of statements in sequence.
/// Log errors but continue execution.
pub fn run(&mut self, statements: Vec<Statement>) -> Result<(), InterpreterError> {

View file

@ -53,9 +53,9 @@ pub enum RoxError {
}
/// Read the source code in a file and scan it to tokens.
pub fn compile(source: &Path) -> Result<(), io::Error> {
pub fn compile(source: &Path, cli_args: Vec<String>) -> Result<(), io::Error> {
let input = fs::read_to_string(source)?;
let mut interpreter = Interpreter::default();
let mut interpreter = Interpreter::new(cli_args);
run(&input, &mut interpreter);

View file

@ -23,7 +23,8 @@ fn main() {
exit(1);
}
if let Err(e) = rox::compile(&compile_config.source) {
if let Err(e) = rox::compile(&compile_config.source, compile_config.script_args.clone())
{
error!(
"failed to compile {}: {}",
&compile_config.source.to_string_lossy(),

View file

@ -224,8 +224,47 @@ impl Callable for PromptAscii {
}
}
struct CliArgs {
cli_args: Vec<String>,
}
impl Callable for CliArgs {
fn name(&self) -> String {
"args".into()
}
fn arity(&self) -> usize {
1
}
fn call(
&self,
_interpreter: &mut Interpreter,
args: Vec<Value>,
) -> Result<Value, CallingError> {
if args.len() != self.arity() {
return Err(CallingError::ArgumentMismatch(self.arity(), args.len()));
}
let idx = args
.first()
.ok_or(CallingError::CallFailed("arg not readable".into()))?;
if let Value::Number(idx) = idx {
let idx: usize = idx.0 as usize;
Ok(self
.cli_args
.get(idx)
.map(|x| Value::String(x.clone()))
.unwrap_or(Value::Nil))
} else {
Err(CallingError::CallFailed(
"arg index must be a number".into(),
))
}
}
}
/// Return all native functions available to the Lox interpreter
pub fn all() -> Vec<(String, Value)> {
pub fn all(cli_args: Vec<String>) -> Vec<(String, Value)> {
vec![
(
"asciiOut".into(),
@ -247,5 +286,9 @@ pub fn all() -> Vec<(String, Value)> {
"promptAscii".into(),
Value::Callable((Rc::new(PromptAscii {}), CallableType::Function)),
),
(
"args".into(),
Value::Callable((Rc::new(CliArgs { cli_args }), CallableType::Function)),
),
]
}