1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
//! State struct used in all visitors.

use std::io::{self, Read, Write};
use std::cell::RefCell;
use std::rc::Rc;

use sindra::Identifier;
use sindra::log::LogListener;
use sindra::scope::{MemoryScope, SymbolStore};

use Symbol;
use PType;
use value::Value;
use visitor::interp::StdFuncTable;
use psk_std::Environment;

/// State carried throughout the tree walker. Contains scope information and logger.
pub struct State {
    /// Reference to the current scope stack.
    pub scope: Rc<RefCell<MemoryScope<Symbol, Value>>>,
    /// Reference to the global scope.
    pub global: Rc<RefCell<MemoryScope<Symbol, Value>>>,
    /// Logger
    pub logger: LogListener<String, io::Stdout, io::Stderr>,
    /// Standard function table
    pub std_funcs: StdFuncTable,
    /// Standard running environment
    pub std_env: Environment,
    /// Input / output
    pub io: Io,
    /// Loop depth counter
    pub loop_depth: usize,
}
impl Default for State {
    fn default() -> State {
        let global = Rc::new(RefCell::new(MemoryScope::default()));
        let env = Environment::default();
        let std_funcs = StdFuncTable::new(&mut *global.borrow_mut());

        let mut state = State {
            scope: Rc::clone(&global),
            global: global,
            logger: LogListener::new(io::stdout(), io::stderr()),
            std_funcs: std_funcs,
            std_env: env,
            io: Io::default(),
            loop_depth: 0,
        };

        // define builtins in top-level (global) scope
        state.define_builtins();
        state
    }
}
impl State {
    /// Defines the piske built-in types and links standard library.
    pub fn define_builtins(&mut self) {
        let mut sc = self.scope.borrow_mut();
        sc.define(Identifier("int".to_string()), Symbol::builtin(Identifier("int".to_string()),
            PType::Int));
        sc.define(Identifier("float".to_string()), Symbol::builtin(Identifier("float".to_string()),
            PType::Float));
        sc.define(Identifier("bool".to_string()), Symbol::builtin(Identifier("bool".to_string()),
            PType::Boolean));
        sc.define(Identifier("complex".to_string()),
            Symbol::builtin(Identifier("complex".to_string()), PType::Boolean));
        sc.define(Identifier("string".to_string()),
            Symbol::builtin(Identifier("string".to_string()), PType::String));
    }
}

/// Input / Output handling
pub struct Io {
    /// Standard environment standard input
    stdin: Box<Read>,
    /// Standard environment standard output
    stdout: Box<Write>,
    /// Standard environment standard error
    stderr: Box<Write>,
}
impl Default for Io {
    fn default() -> Io {
        Io {
            stdin: Box::new(io::stdin()),
            stdout: Box::new(io::stdout()),
            stderr: Box::new(io::stderr()),
        }
    }
}
impl Io {
    /// Change the `Read` object used for standard input
    pub fn set_stdin<R: 'static + Read>(&mut self, input: R) {
        self.stdin = Box::new(input);
    }
    /// Change the `Write` object used for standard output
    pub fn set_stdout<W: 'static + Write>(&mut self, out: W) {
        self.stdout = Box::new(out);
    }
    /// Change the `Write` object used for standard error
    pub fn set_stderr<W: 'static + Write>(&mut self, err: W) {
        self.stderr = Box::new(err);
    }

    /// Retrieve a mutable reference to the standard input.
    pub fn stdin(&mut self) -> &mut Read { self.stdin.as_mut() }
    /// Retrieve a mutable reference to the standard output.
    pub fn stdout(&mut self) -> &mut Write { self.stdout.as_mut() }
    /// Retrieve a mutable reference to the standard error.
    pub fn stderr(&mut self) -> &mut Write { self.stderr.as_mut() }
}