use crsn::asm::data::literal::Value; use crsn::asm::error::CrsnError; use crsn::asm::instr::op::OpKind; use crsn::asm::parse::arg_parser::TokenParser; use crsn::module::{CrsnExtension, ParseRes, CrsnUniq}; use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{RunState}; use crsn::sexp::SourcePosition; use std::io::{Write}; use std::convert::TryFrom; use crsn::asm::instr::Cond; use console::Term; #[derive(Debug, Clone)] pub struct StdioOps { hdl_stdin : Value, hdl_stdout : Value, } #[derive(Debug)] struct StdioData { console: Term, } impl Default for StdioData { fn default() -> Self { Self { console : Term::stdout() } } } impl StdioOps { pub fn new() -> Box { Box::new(Self { hdl_stdin: 0, hdl_stdout: 0 }) } } impl CrsnExtension for StdioOps { fn init(&mut self, uniq: &CrsnUniq) { self.hdl_stdin = uniq.unique_handle(); self.hdl_stdout = uniq.unique_handle(); } /// Get value of an extension-provided constant. /// This constant may be an object handle, or a constant value used as argument in some other instruction. fn get_constant_value<'a>(&self, name: &str) -> Option { match name { "stdin" => Some(self.hdl_stdin), "stdout" => Some(self.hdl_stdout), _ => None } } fn name(&self) -> &'static str { "stdio" } fn parse_op<'a>(&self, _pos: &SourcePosition, _keyword: &str, args: TokenParser<'a>) -> Result, CrsnError> { Ok(ParseRes::Unknown(args)) } /// Run-time method called to read an object (using the object handle syntax) fn read_obj(&self, state: &mut RunState, handle: Value) -> Result, Fault> { if handle == self.hdl_stdin { let data = state.ext_mut::(); return Ok(Some(data.console.read_char().expect("stdin read") as u64)); } if handle == self.hdl_stdout { return Err(Fault::NotAllowed("Cannot read stdout".into())); } Ok(None) } /// Run-time method called to write an object (using the object handle syntax) fn write_obj(&self, state: &mut RunState, handle: Value, value: Value) -> Result, Fault> { state.clear_status(); if handle == self.hdl_stdout { if let Ok(a_char) = char::try_from((value & 0xFFFF_FFFF) as u32) { let data = state.ext_mut::(); let mut b = [0; 4]; data.console.write(a_char.encode_utf8(&mut b).as_bytes()).expect("stdout write"); } else { state.set_flag(Cond::Invalid, true); } return Ok(Some(())); } if handle == self.hdl_stdin { return Err(Fault::NotAllowed("Cannot write stdin".into())); } Ok(None) } }