rewrite the stdio module to be less broken. also add sehbang support

This commit is contained in:
2020-10-10 18:46:32 +02:00
parent 982ba27ed3
commit ace92a6411
21 changed files with 357 additions and 171 deletions
+9 -9
View File
@@ -144,7 +144,7 @@ fn atom_of_string(s: String) -> Atom {
// returns the char it found, and the new pos if you wish to consume that char
fn peek(s: &str, pos: usize) -> ERes<(char, usize)> {
trace!("peek {}", pos);
//trace!("peek {}", pos);
if pos == s.len() { return err("unexpected eof", s, pos); }
if s.is_char_boundary(pos) {
let ch = s[pos..].chars().next().unwrap();
@@ -158,7 +158,7 @@ fn peek(s: &str, pos: usize) -> ERes<(char, usize)> {
// returns the char it found, and the new pos if you wish to consume that char
fn peekn(s: &str, nth: usize, pos: usize) -> Option<(char, usize)> {
trace!("peekn {}", pos);
//trace!("peekn {}", pos);
if nth == 0 {
panic!("peekn with nth=0");
}
@@ -183,7 +183,7 @@ fn peekn(s: &str, nth: usize, pos: usize) -> Option<(char, usize)> {
}
fn expect(s: &str, pos: &mut usize, c: char) -> ERes<()> {
trace!("expect {}", pos);
//trace!("expect {}", pos);
let (ch, next) = peek(s, *pos)?;
*pos = next;
if ch == c {
@@ -208,7 +208,7 @@ fn consume_until_newline(s: &str, pos: &mut usize) -> ERes<()> {
// zero or more spaces
fn zspace(s: &str, pos: &mut usize) -> ERes<()> {
trace!("zspace {}", pos);
//trace!("zspace {}", pos);
loop {
if *pos == s.len() {
return Ok(());
@@ -226,7 +226,7 @@ fn zspace(s: &str, pos: &mut usize) -> ERes<()> {
}
fn parse_quoted_atom(s: &str, quote: char, pos: &mut usize) -> ERes<Atom> {
trace!("parse_quoted_atom {}", pos);
//trace!("parse_quoted_atom {}", pos);
let pos0 = *pos;
let mut cs: String = String::new();
@@ -266,7 +266,7 @@ fn parse_quoted_atom(s: &str, quote: char, pos: &mut usize) -> ERes<Atom> {
}
fn parse_unquoted_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
trace!("parse_unquoted_atom {}", pos);
//trace!("parse_unquoted_atom {}", pos);
let mut cs: String = String::new();
loop {
@@ -288,7 +288,7 @@ fn parse_unquoted_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
}
fn parse_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
trace!("parse_atom {}", pos);
//trace!("parse_atom {}", pos);
let (ch, _) = peek(s, *pos)?;
if ch == '"' {
@@ -309,7 +309,7 @@ fn parse_atom(s: &str, pos: &mut usize) -> ERes<Atom> {
}
fn parse_list(s: &str, pos: &mut usize) -> ERes<Vec<Sexp>> {
trace!("parse_list {}", pos);
//trace!("parse_list {}", pos);
zspace(s, pos)?;
expect(s, pos, '(')?;
@@ -331,7 +331,7 @@ fn parse_list(s: &str, pos: &mut usize) -> ERes<Vec<Sexp>> {
}
fn parse_sexp(s: &str, pos: &mut usize) -> ERes<Sexp> {
trace!("parse_sexp {}", pos);
//trace!("parse_sexp {}", pos);
zspace(s, pos)?;
let (c, _) = peek(s, *pos)?;
let r = if c == '(' {
+67
View File
@@ -5,6 +5,55 @@ use sexp::SourcePosition;
use crate::asm::error::CrsnError;
/// Condition flag
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Flag {
/// Equality
Equal,
/// Equal to zero
Zero,
/// A < B
Lower,
/// A > B
Greater,
/// A > 0
Positive,
/// A < 0
Negative,
/// Arithmetic operation caused an integer operand to overflow
Overflow,
/// Arithmetic (or other) operation was invalid.
/// Example: division by zero
Invalid,
/// Arithmetic carry
Carry,
// Full
Full,
// Empty
Empty,
// Empty
Eof,
}
impl From<Flag> for Cond {
fn from(flag: Flag) -> Self {
match flag {
Flag::Equal => Cond::Equal,
Flag::Zero => Cond::Zero,
Flag::Lower => Cond::Lower,
Flag::Greater => Cond::Greater,
Flag::Positive => Cond::Positive,
Flag::Negative => Cond::Negative,
Flag::Overflow => Cond::Overflow,
Flag::Invalid => Cond::Invalid,
Flag::Carry => Cond::Carry,
Flag::Full => Cond::Full,
Flag::Empty => Cond::Empty,
Flag::Eof => Cond::Eof,
}
}
}
/// Condition flag
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Cond {
@@ -53,6 +102,10 @@ pub enum Cond {
Empty,
/// Not empty
NotEmpty,
// Empty
Eof,
/// Not empty
NotEof,
}
pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
@@ -77,6 +130,8 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
"nf" | "nfull" => Cond::NotFull,
"ok" | "val" | "valid" => Cond::Valid,
"inval" | "invalid" | "nval" | "nok" => Cond::Invalid,
"eof" => Cond::Eof,
"neof" => Cond::NotEof,
"ov" => Cond::Overflow,
"nov" => Cond::NotOverflow,
_ => {
@@ -85,6 +140,13 @@ pub fn parse_cond(text: &str, pos: &SourcePosition) -> Result<Cond, CrsnError> {
})
}
impl Display for Flag {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let cond : Cond = (*self).into();
write!(f, "{}", cond)
}
}
impl Display for Cond {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(match self {
@@ -110,6 +172,8 @@ impl Display for Cond {
Cond::NotCarry => "nc",
Cond::Invalid => "inval",
Cond::Valid => "valid",
Cond::Eof => "eof",
Cond::NotEof => "neof",
})
}
}
@@ -147,6 +211,9 @@ impl Not for Cond {
Cond::Invalid => Cond::Valid,
Cond::Valid => Cond::Invalid,
Cond::NotEof => Cond::Eof,
Cond::Eof => Cond::NotEof,
}
}
}
+2
View File
@@ -39,6 +39,8 @@ impl Flatten for InstrWithBranches {
let parent_pos = self.pos;
if let Some(branches) = self.branches {
// trace!("Branches {:?}", branches);
let labels = HashMap::<Cond, u32>::new();
let branch_count = branches.len();
let end_lbl = Label::unique(label_num);
+11
View File
@@ -23,6 +23,17 @@ pub fn assemble(source: &str, uniq : &CrsnUniq, mut parsers: Vec<Box<dyn CrsnExt
p.init(uniq);
}
// remove first line if it looks like a shebang
let source = if source.starts_with("#!") {
if let Some(nl) = source.find('\n') {
&source[nl + 1..]
} else {
source
}
} else {
source
};
let pcx = ParserContext {
parsers: &parsers,
state: RefCell::new(ParserState {
+1
View File
@@ -7,6 +7,7 @@ use crate::asm::parse::ParserContext;
use crate::asm::parse::sexp_expect::expect_string_atom;
/// Utility for argument parsing
#[derive(Debug)]
pub struct TokenParser<'a> {
orig_len: usize,
args: Vec<Sexp>,
+2 -1
View File
@@ -20,6 +20,7 @@ pub mod parse_op;
pub mod arg_parser;
pub mod parse_routine;
#[derive(Debug)]
pub struct ParserContext<'a> {
/// Extension modules
pub parsers: &'a [Box<dyn CrsnExtension>],
@@ -27,7 +28,7 @@ pub struct ParserContext<'a> {
pub state: RefCell<ParserState>,
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct ParserState {
/// Register aliases within the routine
pub reg_aliases: HashMap<RegisterAlias, Register>,
+2 -1
View File
@@ -63,10 +63,11 @@ pub fn parse_instructions(items: impl Iterator<Item=Sexp>, pos: &SourcePosition,
.collect::<Vec<_>>();
let arg_tokens = TokenParser::new(toki.take(token_count - branch_tokens.len()).collect(), &listpos, pcx);
// debug!("branch_tokens: {:#?}", branch_tokens);
let branches = {
let mut branches = vec![];
for t in branch_tokens {
for t in branch_tokens.into_iter().rev() {
branches.push(parse_cond_branch(t, pcx)?);
}
if branches.is_empty() {
+2 -2
View File
@@ -4,12 +4,12 @@ use sexp::Sexp;
use crate::asm::data::{Rd, RdData};
use crate::asm::data::literal::Addr;
use crate::asm::instr::Cond;
use crate::builtin::defs::{Barrier, BuiltinOp};
use crate::module::{EvalRes, OpTrait};
use crate::runtime::fault::Fault;
use crate::runtime::frame::StackFrame;
use crate::runtime::run_thread::{state::RunState, ThreadInfo};
use crate::asm::instr::cond::Flag;
impl OpTrait for BuiltinOp {
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
@@ -138,7 +138,7 @@ impl OpTrait for BuiltinOp {
}
if !dropped {
warn!("Object {:#x} to del does not exist!", x);
state.set_flag(Cond::Invalid, true);
state.set_flag(Flag::Invalid, true);
}
}
}
+35 -28
View File
@@ -3,6 +3,7 @@ use std::fmt;
use crate::asm::data::literal::{is_negative, is_positive, Value};
use crate::asm::instr::Cond;
use crate::asm::instr::cond::Flag;
#[derive(Default, Clone, Debug)]
pub struct StatusFlags {
@@ -28,6 +29,8 @@ pub struct StatusFlags {
pub full: bool,
/// Buffer empty
pub empty: bool,
/// Stream ended
pub eof: bool,
}
impl StatusFlags {
@@ -49,6 +52,7 @@ impl StatusFlags {
if self.carry { val |= 0x100; }
if self.full { val |= 0x200; }
if self.empty { val |= 0x400; }
if self.eof { val |= 0x800; }
val
}
@@ -64,6 +68,7 @@ impl StatusFlags {
if val & 0x100 != 0 { self.carry = true; }
if val & 0x200 != 0 { self.full = true; }
if val & 0x400 != 0 { self.empty = true; }
if val & 0x800 != 0 { self.eof = true; }
}
#[inline(always)]
@@ -98,50 +103,49 @@ impl StatusFlags {
Cond::NotFull => !self.full,
Cond::Empty => self.empty,
Cond::NotEmpty => !self.empty,
Cond::Eof => self.eof,
Cond::NotEof => !self.eof,
}
}
#[inline(always)]
pub fn set(&mut self, cond: Cond) {
pub fn set(&mut self, cond: Flag, val : bool) {
match cond {
Cond::Equal => {
self.equal = true;
Flag::Equal => {
self.equal = val;
}
Cond::Zero => {
self.zero = true;
Flag::Zero => {
self.zero = val;
}
Cond::Lower => {
self.lower = true;
Flag::Lower => {
self.lower = val;
}
Cond::Greater => {
self.lower = false;
self.equal = false;
self.greater = true;
Flag::Greater => {
self.greater = val;
}
Cond::Positive => {
self.positive = true;
Flag::Positive => {
self.positive = val;
}
Cond::Negative => {
self.negative = true;
Flag::Negative => {
self.negative = val;
}
Cond::Overflow => {
self.overflow = true;
Flag::Overflow => {
self.overflow = val;
}
Cond::Invalid => {
self.invalid = true;
Flag::Invalid => {
self.invalid = val;
}
Cond::Carry => {
self.carry = true;
Flag::Carry => {
self.carry = val;
}
Cond::Empty => {
self.empty = true;
Flag::Empty => {
self.empty = val;
}
Cond::Full => {
self.full = true;
Flag::Full => {
self.full = val;
}
other => {
error!("Cannot set cond by {:?}", other);
// ...and do nothing. Don't panic, we don't want to crash the runtime!
Flag::Eof => {
self.eof = val;
}
}
}
@@ -183,6 +187,9 @@ impl Display for StatusFlags {
if self.empty {
f.write_str(" Emp")?;
}
if self.eof {
f.write_str(" Eof")?;
}
f.write_str(" ]")?;
Ok(())
+4 -4
View File
@@ -9,6 +9,7 @@ use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame};
use std::sync::Arc;
use crate::runtime::run_thread::ThreadInfo;
use nudge::{likely};
use crate::asm::instr::cond::Flag;
pub struct RunState {
pub thread_info: Arc<ThreadInfo>,
@@ -51,10 +52,9 @@ impl RunState {
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
#[inline(always)]
pub fn set_flag(&mut self, cond: Cond, set: bool) {
if set {
self.frame.status.set(cond);
}
pub fn set_flag(&mut self, flag: Flag, set: bool) {
trace!("Flag {} = {:?}", flag, set);
self.frame.status.set(flag, set);
}
/// Check status flags for a condition