add stdio module
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "crsn_stdio"
|
||||
version = "0.1.0"
|
||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crsn = { path = "../crsn" }
|
||||
console = "0.12.0"
|
||||
@@ -0,0 +1,107 @@
|
||||
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, ThreadInfo};
|
||||
use crsn::sexp::SourcePosition;
|
||||
use crsn::asm::data::Mask;
|
||||
use std::io::{Read, stdin, stdout, 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<dyn CrsnExtension> {
|
||||
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<Value>
|
||||
{
|
||||
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<ParseRes<'a, OpKind>, 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, _mask: Mask)
|
||||
-> Result<Option<Value>, Fault>
|
||||
{
|
||||
if handle == self.hdl_stdin {
|
||||
let data = state.ext_mut::<StdioData>();
|
||||
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, _mask: Mask, value: Value) -> Result<Option<()>, 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::<StdioData>();
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user