From 1dc9c9c7dcc7bbcc042fd554c621cfbda5b1e3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vid=20Drobni=C4=8D?= Date: Sat, 15 Jun 2024 20:11:37 +0200 Subject: [PATCH] feat: stdio builtin functions --- runtime/src/builtin.rs | 51 +++++++++++++++++++++++++++++++- runtime/src/error.rs | 2 ++ runtime/src/test_input/README.md | 6 ++++ runtime/src/test_input/fibs.aoc | 12 ++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 runtime/src/test_input/README.md create mode 100644 runtime/src/test_input/fibs.aoc diff --git a/runtime/src/builtin.rs b/runtime/src/builtin.rs index 4f2e5ab..6c2bdbf 100644 --- a/runtime/src/builtin.rs +++ b/runtime/src/builtin.rs @@ -1,4 +1,4 @@ -use std::{fmt::Display, rc::Rc}; +use std::{fmt::Display, io, rc::Rc}; use crate::{ error::ErrorKind, @@ -26,6 +26,9 @@ pub enum Builtin { Push, Pop, + + Print, + Input, } impl Display for Builtin { @@ -45,6 +48,8 @@ impl Display for Builtin { Builtin::Split => write!(f, "split"), Builtin::Push => write!(f, "push"), Builtin::Pop => write!(f, "pop"), + Builtin::Print => write!(f, "print"), + Builtin::Input => write!(f, "input"), } } } @@ -66,6 +71,8 @@ impl Builtin { "split" => Self::Split, "push" => Self::Push, "pop" => Self::Pop, + "print" => Self::Print, + "input" => Self::Input, _ => return None, }; @@ -95,6 +102,9 @@ impl Builtin { Builtin::Push => call_push(args), Builtin::Pop => call_pop(args), + + Builtin::Print => call_print(args), + Builtin::Input => call_input(args), } } } @@ -309,3 +319,42 @@ fn call_pop(args: &[Object]) -> Result { None => Ok(Object::Null), } } + +fn call_print(args: &[Object]) -> Result { + validate_args_len(args, 1)?; + + match &args[0] { + Object::Null => println!("null"), + Object::Integer(val) => println!("{val}"), + Object::Float(val) => println!("{val}"), + Object::Boolean(val) => println!("{val}"), + Object::String(val) => println!("{val}"), + + obj => { + return Err(ErrorKind::InvalidBuiltinArg { + builtin: Builtin::Print, + data_type: obj.into(), + }) + } + } + + Ok(Object::Null) +} + +fn call_input(args: &[Object]) -> Result { + validate_args_len(args, 0)?; + + let mut line = String::new(); + let read = io::stdin() + .read_line(&mut line) + .map_err(|_| ErrorKind::InputError)?; + + if read == 0 { + // Handle eof + Ok(Object::Null) + } else { + // Remove \n that is always read + line.pop(); + Ok(Object::String(Rc::new(line))) + } +} diff --git a/runtime/src/error.rs b/runtime/src/error.rs index e8e3eb0..360d02b 100644 --- a/runtime/src/error.rs +++ b/runtime/src/error.rs @@ -53,6 +53,7 @@ pub enum ErrorKind { builtin: Builtin, data_type: DataType, }, + InputError, } #[derive(Debug, Error, PartialEq)] @@ -135,6 +136,7 @@ impl Display for ErrorKind { ErrorKind::InvalidNrOfArgs { expected, got } => write!(f, "Invalid number of arguments, expected: {expected}, got: {got}"), ErrorKind::InvalidBuiltinArg { builtin, data_type } => write!(f, "Can't call {builtin} on {data_type}."), + ErrorKind::InputError => write!(f, "Could not read from stdin"), } } } diff --git a/runtime/src/test_input/README.md b/runtime/src/test_input/README.md new file mode 100644 index 0000000..8c1cb4f --- /dev/null +++ b/runtime/src/test_input/README.md @@ -0,0 +1,6 @@ +## Test Input + +This folder contains some files to test input and ouput. +These tests are not automated, because I didn't feel like dealing +with passing around reader and writer instead of calling stdin and stdout +directly. diff --git a/runtime/src/test_input/fibs.aoc b/runtime/src/test_input/fibs.aoc new file mode 100644 index 0000000..3d18b0c --- /dev/null +++ b/runtime/src/test_input/fibs.aoc @@ -0,0 +1,12 @@ +fib = fn(n) { + if (n <= 2) { + 1 + } else { + fib(n-1) + fib(n-2) + } +} + +for (n = input(); n; n = input()) { + print(fib(int(n))) +} +