<commit_before>// Dependency Graph Library in Rust

//! dglr is a Dependency Graph Library in Rust.
//! In short, you register elements and their dependencies, and then
//! ask for the dependencies of any element in an order that satisfies.
//!
//! Elements are simply &str strings.  You register them with
//! register_dependency() or register_dependencies().
//!
//! Dependenies are (currently) just a list of other elements that
//! the element in question depends on.  [In the future, we may add
//! boolean logic, but currently they are all AND-ed together].
//!
//! Then call get_ordered_dependencies_of() and the library does the
//! magic and returns an order which will work.  It is possible that
//! other orders also work, but the library's algorithm is
//! deterministic, so you'll always get the same particular one.

#![crate_name = "dglr"]
#![crate_type = "lib"]

// Required for log and rustdoc:
#![feature(phase)]
#[phase(plugin, link)]

extern crate log;

use std::collections::hashmap::{HashMap,HashSet};
use std::iter::{Iterator};
#[allow(unused_imports)]
use std::task;

/// This is the dependency graph.  You can create it yourself, or
/// use the convenience methods of new(), register_dependency() and
/// register_dependencies() to build one up (that must be mutable).
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,Vec<String>>,

    // (private) target we are trying to satisfy
    target: Option<String>,

    // (private) elements already satisfied
    satisfied: HashSet<String>,

    // (private) current path, for cycle detection
    curpath: HashSet<String>,
}

pub struct DepGraphIterator<'a> {
    depgraph: &'a mut DepGraph
}
pub struct DepGraphSatisfyingIterator<'a> {
    depgraph: &'a mut DepGraph
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            target: None,
            curpath: HashSet::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The thing does not need
    /// to pre-exist, nor do the dependency elements.  But if the
    /// thing does pre-exist, the depends_on will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                thing: &'a str,
                                depends_on: &'a str )
    {
        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            vec![String::from_str(depends_on)],
            |_,v| { v.push(String::from_str(depends_on)); }
            );
    }

    /// Add multiple dependencies of one thing to a DepGraph.  The
    /// thing does not need to pre-exist, nor do the dependency elements.
    /// But if the thing does pre-exist, the depends_on will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  thing: &'a str,
                                  depends_on: &'a[&'a str] )
    {
        let newvec: Vec<String> = depends_on.iter().map(
            |s| String::from_str(*s)).collect();

        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            newvec.clone(),
            |_,v| { v.push_all(newvec.as_slice()); }
            );
    }

    pub fn set_target<'a>( &mut self, target: &'a str )
    {
        self.target = Some(String::from_str(target));
    }

    pub fn mark_as_satisfied<'a>( &mut self,
                                   things: &'a[&'a str] )
    {
        for thing in things.iter() {
            self.satisfied.insert(String::from_str(*thing));
        }
    }

    fn get_next_dependency(&mut self, thing: &String) -> String
    {
        if self.curpath.contains(thing) {
            fail!("Circular dependency graph at {}",thing);
        }
        self.curpath.insert(thing.clone());

        let deplist = match self.dependencies.find(thing) {
            None => return thing.clone(),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            if self.satisfied.contains(n) {
                continue;
            }
            return self.get_next_dependency(n);
        }
        // things dependencies are satisfied
        thing.clone()
    }

    pub fn iter<'a>(&'a mut self) -> DepGraphIterator<'a>
    {
        DepGraphIterator {
            depgraph: self
        }
    }

    pub fn satisfying_iter<'a>(&'a mut self) -> DepGraphSatisfyingIterator<'a>
    {
        DepGraphSatisfyingIterator {
            depgraph: self
        }
    }
}

impl<'a> Iterator<String> for DepGraphIterator<'a> {
    fn next(&mut self) -> Option<String>
    {
        let thing = match self.depgraph.target {
            None => return None,
            Some(ref thing) => thing.clone()
        };
        if self.depgraph.satisfied.contains(&thing) {
            return None;
        }
        self.depgraph.curpath.clear();
        Some(self.depgraph.get_next_dependency(&thing))
    }
}

impl<'a> Iterator<String> for DepGraphSatisfyingIterator<'a> {
    fn next(&mut self) -> Option<String>
    {
        let thing = match self.depgraph.target {
            None => return None,
            Some(ref thing) => thing.clone()
        };
        if self.depgraph.satisfied.contains(&thing) {
            return None;
        }
        self.depgraph.curpath.clear();
        let next = self.depgraph.get_next_dependency(&thing);
        self.depgraph.mark_as_satisfied([next.as_slice()]);
        Some(next)
    }
}

#[test]
fn dglr_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    depgraph.set_target("a");

    let mut results: Vec<String> = Vec::new();

    loop {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let thing = match depgraph.iter().next() {
            Some(x) => x,
            None => break,
        };
        depgraph.mark_as_satisfied([thing.as_slice()]);
        results.push(thing);
    }

    assert!( results == vec![String::from_str("d"),
                             String::from_str("b"),
                             String::from_str("f"),
                             String::from_str("e"),
                             String::from_str("n"),
                             String::from_str("m"),
                             String::from_str("j"),
                             String::from_str("l"),
                             String::from_str("k"),
                             String::from_str("i"),
                             String::from_str("h"),
                             String::from_str("g"),
                             String::from_str("c"),
                             String::from_str("a")] );
    //info!("Deps of a = {}",results);
}

#[test]
fn dglr_test_satisfying() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e"]);

    depgraph.set_target("a");

    let mut results: Vec<String> = Vec::new();

    for thing in depgraph.satisfying_iter() {
        // detect infinite looping bugs
        assert!(results.len() < 30);
        results.push(thing);
    }

    assert!( results == vec![String::from_str("d"),
                             String::from_str("b"),
                             String::from_str("e"),
                             String::from_str("c"),
                             String::from_str("a")] );
    //info!("Deps of a = {}",results);
}

#[test]
fn dglr_test_circular() {

    let task_result = task::try(proc() {
        let mut depgraph: DepGraph = DepGraph::new();
        depgraph.register_dependency("a","b");
        depgraph.register_dependency("b","c");
        depgraph.register_dependency("c","a");
        depgraph.set_target("a");

        let mut results: Vec<String> = Vec::new();

        loop {
            // Detect infinite looping bugs by
            // breaking out successfully (successful
            // proc() means failed test!)
            if results.len() >= 30 { break; }

            let thing = match depgraph.iter().next() {
                Some(x) => x,
                None => break,
            };
            depgraph.mark_as_satisfied([thing.as_slice()]);
            results.push(thing);
        }
    });
    match task_result {
        Ok(_) => fail!("Should have failed at the circular dependency!"),
        Err(_) => () //info!("Successfully detected the circular dependency (ignore task failure)"),
    };
}

#[test]
fn dglr_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", []);
    depgraph.register_dependencies("owneruser", ["superconn"]);
    depgraph.register_dependencies("appuser", ["superconn"]);
    depgraph.register_dependencies("database", ["owneruser"]);
    depgraph.register_dependencies("ownerconn", ["database","owneruser"]);
    depgraph.register_dependencies("adminconn", ["database"]);
    depgraph.register_dependencies("extensions", ["database","adminconn"]);
    depgraph.register_dependencies("schema_table", ["database","ownerconn"]);
    depgraph.register_dependencies("schemas", ["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", ["database","appuser","schemas"]);

    depgraph.set_target("appconn");
    depgraph.mark_as_satisfied(["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    loop {
        assert!(results.len() < 30);

        let thing = match depgraph.iter().next() {
            Some(x) => x,
            None => break,
        };
        depgraph.mark_as_satisfied([thing.as_slice()]);
        results.push(thing);
    }
    assert!( !results.contains(&String::from_str("superconn")) );
}
<commit_msg>minor doc update<commit_after>// Dependency Graph Library in Rust

//! dglr is a Dependency Graph Library in Rust.
//! In short, you register elements and their dependencies, and then
//! ask for the dependencies of any element in an order that satisfies.
//!
//! Elements are simply &str strings.  You register them with
//! register_dependency() or register_dependencies().
//!
//! Dependenies are (currently) just a list of other elements that
//! the element in question depends on.  [In the future, we may add
//! boolean logic, but currently they are all AND-ed together].
//!
//! Then iterate over .iter() to get the ordered dependencies, and
//! the library does the magic and returns an order which will work.
//! It is possible that other orders also work, but the library's
//! algorithm is deterministic, so you'll always get the same
//! particular one.

#![crate_name = "dglr"]
#![crate_type = "lib"]

// Required for log and rustdoc:
#![feature(phase)]
#[phase(plugin, link)]

extern crate log;

use std::collections::hashmap::{HashMap,HashSet};
use std::iter::{Iterator};
#[allow(unused_imports)]
use std::task;

/// This is the dependency graph.  You can create it yourself, or
/// use the convenience methods of new(), register_dependency() and
/// register_dependencies() to build one up (that must be mutable).
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,Vec<String>>,

    // (private) target we are trying to satisfy
    target: Option<String>,

    // (private) elements already satisfied
    satisfied: HashSet<String>,

    // (private) current path, for cycle detection
    curpath: HashSet<String>,
}

pub struct DepGraphIterator<'a> {
    depgraph: &'a mut DepGraph
}
pub struct DepGraphSatisfyingIterator<'a> {
    depgraph: &'a mut DepGraph
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            target: None,
            curpath: HashSet::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The thing does not need
    /// to pre-exist, nor do the dependency elements.  But if the
    /// thing does pre-exist, the depends_on will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                thing: &'a str,
                                depends_on: &'a str )
    {
        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            vec![String::from_str(depends_on)],
            |_,v| { v.push(String::from_str(depends_on)); }
            );
    }

    /// Add multiple dependencies of one thing to a DepGraph.  The
    /// thing does not need to pre-exist, nor do the dependency elements.
    /// But if the thing does pre-exist, the depends_on will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  thing: &'a str,
                                  depends_on: &'a[&'a str] )
    {
        let newvec: Vec<String> = depends_on.iter().map(
            |s| String::from_str(*s)).collect();

        self.dependencies.insert_or_update_with(
            String::from_str(thing),
            newvec.clone(),
            |_,v| { v.push_all(newvec.as_slice()); }
            );
    }

    pub fn set_target<'a>( &mut self, target: &'a str )
    {
        self.target = Some(String::from_str(target));
    }

    pub fn mark_as_satisfied<'a>( &mut self,
                                   things: &'a[&'a str] )
    {
        for thing in things.iter() {
            self.satisfied.insert(String::from_str(*thing));
        }
    }

    fn get_next_dependency(&mut self, thing: &String) -> String
    {
        if self.curpath.contains(thing) {
            fail!("Circular dependency graph at {}",thing);
        }
        self.curpath.insert(thing.clone());

        let deplist = match self.dependencies.find(thing) {
            None => return thing.clone(),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            if self.satisfied.contains(n) {
                continue;
            }
            return self.get_next_dependency(n);
        }
        // things dependencies are satisfied
        thing.clone()
    }

    pub fn iter<'a>(&'a mut self) -> DepGraphIterator<'a>
    {
        DepGraphIterator {
            depgraph: self
        }
    }

    pub fn satisfying_iter<'a>(&'a mut self) -> DepGraphSatisfyingIterator<'a>
    {
        DepGraphSatisfyingIterator {
            depgraph: self
        }
    }
}

impl<'a> Iterator<String> for DepGraphIterator<'a> {
    fn next(&mut self) -> Option<String>
    {
        let thing = match self.depgraph.target {
            None => return None,
            Some(ref thing) => thing.clone()
        };
        if self.depgraph.satisfied.contains(&thing) {
            return None;
        }
        self.depgraph.curpath.clear();
        Some(self.depgraph.get_next_dependency(&thing))
    }
}

impl<'a> Iterator<String> for DepGraphSatisfyingIterator<'a> {
    fn next(&mut self) -> Option<String>
    {
        let thing = match self.depgraph.target {
            None => return None,
            Some(ref thing) => thing.clone()
        };
        if self.depgraph.satisfied.contains(&thing) {
            return None;
        }
        self.depgraph.curpath.clear();
        let next = self.depgraph.get_next_dependency(&thing);
        self.depgraph.mark_as_satisfied([next.as_slice()]);
        Some(next)
    }
}

#[test]
fn dglr_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    depgraph.set_target("a");

    let mut results: Vec<String> = Vec::new();

    loop {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let thing = match depgraph.iter().next() {
            Some(x) => x,
            None => break,
        };
        depgraph.mark_as_satisfied([thing.as_slice()]);
        results.push(thing);
    }

    assert!( results == vec![String::from_str("d"),
                             String::from_str("b"),
                             String::from_str("f"),
                             String::from_str("e"),
                             String::from_str("n"),
                             String::from_str("m"),
                             String::from_str("j"),
                             String::from_str("l"),
                             String::from_str("k"),
                             String::from_str("i"),
                             String::from_str("h"),
                             String::from_str("g"),
                             String::from_str("c"),
                             String::from_str("a")] );
    //info!("Deps of a = {}",results);
}

#[test]
fn dglr_test_satisfying() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e"]);

    depgraph.set_target("a");

    let mut results: Vec<String> = Vec::new();

    for thing in depgraph.satisfying_iter() {
        // detect infinite looping bugs
        assert!(results.len() < 30);
        results.push(thing);
    }

    assert!( results == vec![String::from_str("d"),
                             String::from_str("b"),
                             String::from_str("e"),
                             String::from_str("c"),
                             String::from_str("a")] );
    //info!("Deps of a = {}",results);
}

#[test]
fn dglr_test_circular() {

    let task_result = task::try(proc() {
        let mut depgraph: DepGraph = DepGraph::new();
        depgraph.register_dependency("a","b");
        depgraph.register_dependency("b","c");
        depgraph.register_dependency("c","a");
        depgraph.set_target("a");

        let mut results: Vec<String> = Vec::new();

        loop {
            // Detect infinite looping bugs by
            // breaking out successfully (successful
            // proc() means failed test!)
            if results.len() >= 30 { break; }

            let thing = match depgraph.iter().next() {
                Some(x) => x,
                None => break,
            };
            depgraph.mark_as_satisfied([thing.as_slice()]);
            results.push(thing);
        }
    });
    match task_result {
        Ok(_) => fail!("Should have failed at the circular dependency!"),
        Err(_) => () //info!("Successfully detected the circular dependency (ignore task failure)"),
    };
}

#[test]
fn dglr_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", []);
    depgraph.register_dependencies("owneruser", ["superconn"]);
    depgraph.register_dependencies("appuser", ["superconn"]);
    depgraph.register_dependencies("database", ["owneruser"]);
    depgraph.register_dependencies("ownerconn", ["database","owneruser"]);
    depgraph.register_dependencies("adminconn", ["database"]);
    depgraph.register_dependencies("extensions", ["database","adminconn"]);
    depgraph.register_dependencies("schema_table", ["database","ownerconn"]);
    depgraph.register_dependencies("schemas", ["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", ["database","appuser","schemas"]);

    depgraph.set_target("appconn");
    depgraph.mark_as_satisfied(["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    loop {
        assert!(results.len() < 30);

        let thing = match depgraph.iter().next() {
            Some(x) => x,
            None => break,
        };
        depgraph.mark_as_satisfied([thing.as_slice()]);
        results.push(thing);
    }
    assert!( !results.contains(&String::from_str("superconn")) );
}
<|endoftext|>


<commit_before>use Vertex;

use glium::{DepthTest, Display, DrawError, DrawParameters, Surface, Program, VertexBuffer};
use glium::index::{NoIndices, PrimitiveType};
use glium::uniforms::Uniforms;

pub struct DrawRequest<'a> {
    vb: VertexBuffer<Vertex>,
    indices: NoIndices,
    program: Program,
    params: DrawParameters<'a>,
}

impl<'a> DrawRequest<'a> {
    fn new(vb: VertexBuffer<Vertex>, indices: NoIndices, program: Program,
           params: DrawParameters<'a>) -> Self {
        DrawRequest { vb: vb, indices: indices, program: program, params: params }
    }
}

pub struct Grid;

impl Grid {
    pub fn create_draw_request<'a>(&self, display: &Display) -> DrawRequest<'a> {
        let vertex_shader_src = r#"
#version 140

in vec3 position;
uniform mat4 proj_mat;
uniform mat4 view_mat;

void main() {
    gl_Position = proj_mat * view_mat * vec4(position, 1.);
}"#;

        let fragment_shader_src = r#"
#version 140

out vec4 color;

void main() {
    color = vec4(1.);
}"#;

        let mut shape = Vec::new();
        for i in (-10..10) {
            let v1 = Vertex::new(i as f32 / 10., -1., 0.);
            let v2 = Vertex::new(i as f32 / 10., 1., 0.);

            let v3 = Vertex::new(-1., i as f32 / 10., 0.);
            let v4 = Vertex::new(1., i as f32 / 10., 0.);

            shape.push(v1);
            shape.push(v2);
            shape.push(v3);
            shape.push(v4);
        }

        let vb = VertexBuffer::new(display, shape);
        let indices = NoIndices(PrimitiveType::LinesList);
        let program = Program::from_source(display, vertex_shader_src,
                                           fragment_shader_src, None).unwrap();

        DrawRequest::new(vb, indices, program, Default::default())
    }
}

pub struct Cube;

impl Cube {
    pub fn create_draw_request<'a>(&self, display: &Display) -> DrawRequest<'a> {
        let vertex_shader_src = r#"
#version 140

in vec3 position;
uniform mat4 proj_mat;
uniform mat4 view_mat;

out vec3 v_coord;

void main() {
    v_coord = position;
    gl_Position = proj_mat * view_mat * vec4(position, 1.);
}"#;

        let fragment_shader_src = r#"
#version 140

in vec3 v_coord;
out vec4 color;

void main() {
    if (abs(v_coord.z) == 0.25) {
        color = vec4(0., 1., 0., 1.);
    } else if (abs(v_coord.x) == 0.25) {
        color = vec4(0., 0., 1., 1.);
    } else if (abs(v_coord.y) == 0.25) {
        color = vec4(1., 0., 0., 1.);
    }
}"#;

        let v1 = Vertex::new(0.25, 0.25, -0.25);
        let v2 = Vertex::new(-0.25, 0.25, -0.25);
        let v3 = Vertex::new(0.25, -0.25, -0.25);
        let v4 = Vertex::new(-0.25, -0.25, -0.25);
        let v5 = Vertex::new(-0.25, 0.25, 0.25);
        let v6 = Vertex::new(-0.25, -0.25, 0.25);
        let v7 = Vertex::new(0.25, -0.25, 0.25);
        let v8 = Vertex::new(0.25, 0.25, 0.25);

        let shape = vec![v1, v2, v3,
                         v2, v3, v4,
                         v2, v4, v5,
                         v4, v5, v6,
                         v4, v6, v7,
                         v3, v4, v7,
                         v5, v6, v7,
                         v5, v7, v8,
                         v3, v7, v8,
                         v1, v3, v8,
                         v1, v2, v5,
                         v1, v5, v8];

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let vb = VertexBuffer::new(display, shape);
        let indices = NoIndices(PrimitiveType::TriangleStrip);
        let program = Program::from_source(display, vertex_shader_src,
                                           fragment_shader_src, None).unwrap();

        DrawRequest::new(vb, indices, program, params)
    }
}

pub fn draw<T: Surface, U: Uniforms>(target: &mut T, draw_req: &DrawRequest, uniforms: &U)
                    -> Result<(), DrawError> {
    let &DrawRequest { ref vb, ref indices, ref program, ref params } = draw_req;

    target.draw(vb, indices, program, uniforms, params)
}
<commit_msg>Added depth test to grid, commented cube faces<commit_after>use Vertex;

use glium::{DepthTest, Display, DrawError, DrawParameters, Surface, Program, VertexBuffer};
use glium::index::{NoIndices, PrimitiveType};
use glium::uniforms::Uniforms;

pub struct DrawRequest<'a> {
    vb: VertexBuffer<Vertex>,
    indices: NoIndices,
    program: Program,
    params: DrawParameters<'a>,
}

impl<'a> DrawRequest<'a> {
    fn new(vb: VertexBuffer<Vertex>, indices: NoIndices, program: Program,
           params: DrawParameters<'a>) -> Self {
        DrawRequest { vb: vb, indices: indices, program: program, params: params }
    }
}

pub struct Grid;

impl Grid {
    pub fn create_draw_request<'a>(&self, display: &Display) -> DrawRequest<'a> {
        let vertex_shader_src = r#"
#version 140

in vec3 position;
uniform mat4 proj_mat;
uniform mat4 view_mat;

void main() {
    gl_Position = proj_mat * view_mat * vec4(position, 1.);
}"#;

        let fragment_shader_src = r#"
#version 140

out vec4 color;

void main() {
    color = vec4(1.);
}"#;

        let mut shape = Vec::new();
        for i in (-10..10) {
            let v1 = Vertex::new(i as f32 / 10., -1., 0.);
            let v2 = Vertex::new(i as f32 / 10., 1., 0.);

            let v3 = Vertex::new(-1., i as f32 / 10., 0.);
            let v4 = Vertex::new(1., i as f32 / 10., 0.);

            shape.push(v1);
            shape.push(v2);
            shape.push(v3);
            shape.push(v4);
        }

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let vb = VertexBuffer::new(display, shape);
        let indices = NoIndices(PrimitiveType::LinesList);
        let program = Program::from_source(display, vertex_shader_src,
                                           fragment_shader_src, None).unwrap();

        DrawRequest::new(vb, indices, program, params)
    }
}

pub struct Cube;

impl Cube {
    pub fn create_draw_request<'a>(&self, display: &Display) -> DrawRequest<'a> {
        let vertex_shader_src = r#"
#version 140

in vec3 position;
uniform mat4 proj_mat;
uniform mat4 view_mat;

out vec3 v_coord;

void main() {
    v_coord = position;
    gl_Position = proj_mat * view_mat * vec4(position, 1.);
}"#;

        let fragment_shader_src = r#"
#version 140

in vec3 v_coord;
out vec4 color;

void main() {
    if (abs(v_coord.z) == 0.25) {
        color = vec4(0., 1., 0., 1.);
    } else if (abs(v_coord.x) == 0.25) {
        color = vec4(0., 0., 1., 1.);
    } else if (abs(v_coord.y) == 0.25) {
        color = vec4(1., 0., 0., 1.);
    }
}"#;

        let v1 = Vertex::new(0.25, 0.25, -0.25);
        let v2 = Vertex::new(-0.25, 0.25, -0.25);
        let v3 = Vertex::new(0.25, -0.25, -0.25);
        let v4 = Vertex::new(-0.25, -0.25, -0.25);
        let v5 = Vertex::new(-0.25, 0.25, 0.25);
        let v6 = Vertex::new(-0.25, -0.25, 0.25);
        let v7 = Vertex::new(0.25, -0.25, 0.25);
        let v8 = Vertex::new(0.25, 0.25, 0.25);

        let shape = vec![
            // Back face (z = -.25)
            v1, v2, v3,
            v2, v3, v4,

            // Left face (x = -.25)
            v2, v4, v5,
            v4, v5, v6,

            // Bottom face (y = -.25)
            v4, v6, v7,
            v3, v4, v7,

            // Front face (z = .25)
            v5, v6, v7,
            v5, v7, v8,

            // Right face (x = .25)
            v3, v7, v8,
            v1, v3, v8,

            // Top face (y = .25)
            v1, v2, v5,
            v1, v5, v8,
        ];

        let params = DrawParameters {
            depth_test: DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let vb = VertexBuffer::new(display, shape);
        let indices = NoIndices(PrimitiveType::TriangleStrip);
        let program = Program::from_source(display, vertex_shader_src,
                                           fragment_shader_src, None).unwrap();

        DrawRequest::new(vb, indices, program, params)
    }
}

pub fn draw<T: Surface, U: Uniforms>(target: &mut T, draw_req: &DrawRequest, uniforms: &U)
                    -> Result<(), DrawError> {
    let &DrawRequest { ref vb, ref indices, ref program, ref params } = draw_req;

    target.draw(vb, indices, program, uniforms, params)
}
<|endoftext|>


<commit_before>use core::clock::{SecondsValue, SpeedFactor};
use frontend::input::AxisValue;
use std::f32::consts;

pub const DEFAULT_WINDOW_WIDTH: u32 = 1280;
pub const DEFAULT_WINDOW_HEIGHT: u32 = 720;
pub const VIEW_SCALE_BASE: f32 = 100.0;
pub const VIEW_ZOOM_MAX: f32 = 8.0;
pub const VIEW_ZOOM_MIN: f32 = 1. / 4.0;
pub const VIEW_ZOOM_MULTIPLIER: f32 = consts::SQRT_2;
pub const VIEW_ZOOM_DURATION: f32 = 0.25;
pub const CAMERA_IMPULSE: f32 = 5.0;
pub const CAMERA_INERTIA: f32 = 4.0;
pub const CAMERA_LIMIT: f32 = 0.5;
pub const FRAME_SMOOTH_COUNT: usize = 120;
pub const FRAME_TIME_TARGET: SecondsValue = 1. / 60.;
pub const LOG_INTERVAL: SecondsValue = 5.0;
pub const SAVE_INTERVAL: SecondsValue = 300.0;
pub const DEAD_ZONE: AxisValue = 0.3f32;
pub const TURN_SPEED: f32 = consts::PI * 200.;
pub const DEBUG_DRAW_BRAKE_SCALE: f32 = 0.05;
pub const DEBUG_DRAW_MOVE_SCALE: f32 = 0.05;
pub const MIN_FRAME_LENGTH: SecondsValue = (1.0 / 1000.0) as SecondsValue;
pub const MAX_FRAME_LENGTH: SecondsValue = (1.0 / 30.0) as SecondsValue;
pub const THRUST_POWER: f32 = 5000.;
pub const POWER_BOOST: f32 = 100.;
pub const DRAG_COEFFICIENT: f32 = 0.000001;
#[allow(unused)]
pub const COMPASS_SPRING_POWER: f32 = 1000.0;
pub const JOINT_UPPER_ANGLE: f32 = consts::PI / 6.;
pub const JOINT_LOWER_ANGLE: f32 = -consts::PI / 6.;
pub const JOINT_FREQUENCY: f32 = 5.0;
pub const JOINT_DAMPING_RATIO: f32 = 0.9;
pub const LINEAR_DAMPING_DEFAULT: f32 = 0.8;
pub const LINEAR_DAMPING_PLAYER: f32 = 2.0;
pub const ANGULAR_DAMPING: f32 = 0.9;
pub const PICK_EPS: f32 = 0.001f32;
pub const DEFAULT_RESOURCE_CHARGE: f32 = 0.8;
pub const DEFAULT_SPORE_CHARGE: f32 = 0.8;
pub const DEFAULT_MINION_CHARGE: f32 = 0.3;
pub const INITIAL_SPAWN_RADIUS_RATIO: f32 = 0.1;
pub const INITIAL_SPAWN_RADIUS_SLICES: f32 = 19.;
pub const INITIAL_SPAWN_RADIUS_INCREMENT: f32 = 0.5;
pub const MATURITY_MINION_DEFAULT: f32 = 0.5;
pub const MATURITY_DEFAULT: f32 = 1.0;
pub const GROWTH_COST_RATIO: f32 = 0.1;
pub const SPAWN_COST_THRESHOLD: f32 = 0.95;
pub const SPAWN_COST_RATIO: f32 = 0.75;
pub const COLLISION_BASE_COST: f32 = 0.5;
pub const WORLD_RADIUS: f32 = 80.;
pub const DEFAULT_CHARGE_DECAY_TIME: SecondsValue = 0.5;
pub const MINION_CHARGE_DECAY_TIME: SecondsValue = 0.25;
pub const PLAYER_CHARGE_DECAY_TIME: SecondsValue = 0.1;
pub const PLAYER_CHARGE_INITIAL_VALUE: f32 = 25.0;
pub const PLAYER_CHARGE_REST_VALUE: f32 = 0.05;
pub const EMITTER_DISTANCE: f32 = 30.;
pub const EMITTER_PERIOD: SecondsValue = 0.4;
#[allow(unused)]
pub const EMITTER_SPREAD_ANGLE: f32 = consts::PI / 12.;
pub const EMITTER_SPREAD_JITTER: f32 = 0.1;
pub const EMITTER_INTENSITY_DECAY: f32 = 1.0;
pub const BULLET_SPEED_SCALE: f32 = 100.;
pub const BULLET_FIRE_RATE_SCALE: SecondsValue = 0.5;
pub const BULLET_FULL_CHARGE: SecondsValue = 1.0;
pub const BULLET_FIRE_RATE: SecondsValue = 45.0;
pub const DENSITY_DEFAULT: f32 = 1.0;
pub const DENSITY_RESOURCE: f32 = DENSITY_DEFAULT;
pub const DENSITY_PLAYER: f32 = 1.0;
pub const DENSITY_MINION: f32 = 0.2;
pub const DENSITY_SPORE: f32 = 0.5;
pub const RESTITUTION_DEFAULT: f32 = 0.6;
pub const RESTITUTION_PLAYER: f32 = 0.1;
pub const FRICTION_DEFAULT: f32 = 0.7;
pub const FRICTION_PLAYER: f32 = 0.6;
pub const B2_LINEAR_SLOP: f32 = 0.005;
pub const DEFAULT_MINION_GENE_POOL_FILE: &'static str = "minion_gene_pool.csv";
pub const DEFAULT_MINION_GENE_POOL: &'static [&'static str] = &[
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"GzB2lQVwM00tTAm5gwajjf4wc0a5GzB2lQVwM00tTAm5gwajjf4wc0a5",
	"GzB2lQdwM10vQEu5zwaPgDhfq2v8GzB2lQdwM10vQEu5zwaPgDhfq2v8",
];

pub const COLOR_SUNSHINE: [f32; 4] = [400.0, 90.0, 1.0, 1.0];
pub const COLOR_TRANSPARENT: [f32; 4] = [0.; 4];
pub const COLOR_WHITE: [f32; 4] = [1.; 4];
#[allow(unused)]
pub const COLOR_BLACK: [f32; 4] = [0., 0., 0., 1.];

pub const DEFAULT_RESOURCE_GENE_POOL: &'static [&'static str] = &["GyA21QoQ", "M00sWS0M"];

pub const CONFIG_DIR_HOME: &'static str = ".config/rust-oids";
pub const CONFIG_DIR_SAVED_STATE: &'static str = "saved_state";
pub const CONFIG_DIR_RESOURCES: &'static str = "resources";
pub const DUMP_FILE_PATTERN_CSV: &'static str = "%Y%m%d_%H%M%S.csv";
pub const DUMP_FILE_PATTERN_JSON: &'static str = "%Y%m%d_%H%M%S.json";

pub const CAPTURE_FOLDER_TIMESTAMP_PATTERN: &'static str = "%Y%m%d_%H%M%S";
pub const CAPTURE_FOLDER: &'static str = "capture";
pub const CAPTURE_FILENAME_PREFIX: &'static str = "capture_";

pub const AMBIENT_LIGHTS: &'static [[f32; 4]] = &[
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[31.0, 31.0, 31.0, 1.0],
	[100.0, 100.0, 100.0, 1.0],
	[0.001, 0.001, 0.001, 1.0],
	[0.01, 0.01, 0.01, 1.0],
	[0.1, 0.1, 0.1, 1.0],
	[0.31, 0.31, 0.31, 0.5],
];

pub const SPEED_FACTORS: &'static [SpeedFactor] = &[1.0, 0.5, 0.2, 0.1, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0];

pub const BACKGROUNDS: &'static [[f32; 4]] = &[
	[0.05, 0.07, 0.1, 1.0],
	[0.5, 0.5, 0.5, 0.5],
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[0., 0., 0., 1.0],
	[0.01, 0.01, 0.01, 1.0],
];
<commit_msg>Increased feeding rate<commit_after>use core::clock::{SecondsValue, SpeedFactor};
use frontend::input::AxisValue;
use std::f32::consts;

pub const DEFAULT_WINDOW_WIDTH: u32 = 1280;
pub const DEFAULT_WINDOW_HEIGHT: u32 = 720;
pub const VIEW_SCALE_BASE: f32 = 100.0;
pub const VIEW_ZOOM_MAX: f32 = 8.0;
pub const VIEW_ZOOM_MIN: f32 = 1. / 4.0;
pub const VIEW_ZOOM_MULTIPLIER: f32 = consts::SQRT_2;
pub const VIEW_ZOOM_DURATION: f32 = 0.25;
pub const CAMERA_IMPULSE: f32 = 5.0;
pub const CAMERA_INERTIA: f32 = 4.0;
pub const CAMERA_LIMIT: f32 = 0.5;
pub const FRAME_SMOOTH_COUNT: usize = 120;
pub const FRAME_TIME_TARGET: SecondsValue = 1. / 60.;
pub const LOG_INTERVAL: SecondsValue = 5.0;
pub const SAVE_INTERVAL: SecondsValue = 300.0;
pub const DEAD_ZONE: AxisValue = 0.3f32;
pub const TURN_SPEED: f32 = consts::PI * 200.;
pub const DEBUG_DRAW_BRAKE_SCALE: f32 = 0.05;
pub const DEBUG_DRAW_MOVE_SCALE: f32 = 0.05;
pub const MIN_FRAME_LENGTH: SecondsValue = (1.0 / 1000.0) as SecondsValue;
pub const MAX_FRAME_LENGTH: SecondsValue = (1.0 / 30.0) as SecondsValue;
pub const THRUST_POWER: f32 = 5000.;
pub const POWER_BOOST: f32 = 100.;
pub const DRAG_COEFFICIENT: f32 = 0.000001;
#[allow(unused)]
pub const COMPASS_SPRING_POWER: f32 = 1000.0;
pub const JOINT_UPPER_ANGLE: f32 = consts::PI / 6.;
pub const JOINT_LOWER_ANGLE: f32 = -consts::PI / 6.;
pub const JOINT_FREQUENCY: f32 = 5.0;
pub const JOINT_DAMPING_RATIO: f32 = 0.9;
pub const LINEAR_DAMPING_DEFAULT: f32 = 0.8;
pub const LINEAR_DAMPING_PLAYER: f32 = 2.0;
pub const ANGULAR_DAMPING: f32 = 0.9;
pub const PICK_EPS: f32 = 0.001f32;
pub const DEFAULT_RESOURCE_CHARGE: f32 = 0.8;
pub const DEFAULT_SPORE_CHARGE: f32 = 0.8;
pub const DEFAULT_MINION_CHARGE: f32 = 0.3;
pub const INITIAL_SPAWN_RADIUS_RATIO: f32 = 0.1;
pub const INITIAL_SPAWN_RADIUS_SLICES: f32 = 19.;
pub const INITIAL_SPAWN_RADIUS_INCREMENT: f32 = 0.5;
pub const MATURITY_MINION_DEFAULT: f32 = 0.5;
pub const MATURITY_DEFAULT: f32 = 1.0;
pub const GROWTH_COST_RATIO: f32 = 0.1;
pub const SPAWN_COST_THRESHOLD: f32 = 0.95;
pub const SPAWN_COST_RATIO: f32 = 0.75;
pub const COLLISION_BASE_COST: f32 = 0.5;
pub const WORLD_RADIUS: f32 = 80.;
pub const DEFAULT_CHARGE_DECAY_TIME: SecondsValue = 0.5;
pub const MINION_CHARGE_DECAY_TIME: SecondsValue = 0.25;
pub const PLAYER_CHARGE_DECAY_TIME: SecondsValue = 0.1;
pub const PLAYER_CHARGE_INITIAL_VALUE: f32 = 25.0;
pub const PLAYER_CHARGE_REST_VALUE: f32 = 0.05;
pub const EMITTER_DISTANCE: f32 = 40.;
pub const EMITTER_PERIOD: SecondsValue = 0.2;
#[allow(unused)]
pub const EMITTER_SPREAD_ANGLE: f32 = consts::PI / 12.;
pub const EMITTER_SPREAD_JITTER: f32 = 0.1;
pub const EMITTER_INTENSITY_DECAY: f32 = 1.0;
pub const BULLET_SPEED_SCALE: f32 = 100.;
pub const BULLET_FIRE_RATE_SCALE: SecondsValue = 0.5;
pub const BULLET_FULL_CHARGE: SecondsValue = 1.0;
pub const BULLET_FIRE_RATE: SecondsValue = 45.0;
pub const DENSITY_DEFAULT: f32 = 1.0;
pub const DENSITY_RESOURCE: f32 = DENSITY_DEFAULT;
pub const DENSITY_PLAYER: f32 = 1.0;
pub const DENSITY_MINION: f32 = 0.2;
pub const DENSITY_SPORE: f32 = 0.5;
pub const RESTITUTION_DEFAULT: f32 = 0.6;
pub const RESTITUTION_PLAYER: f32 = 0.1;
pub const FRICTION_DEFAULT: f32 = 0.7;
pub const FRICTION_PLAYER: f32 = 0.6;
pub const B2_LINEAR_SLOP: f32 = 0.005;
pub const DEFAULT_MINION_GENE_POOL_FILE: &'static str = "minion_gene_pool.csv";
pub const DEFAULT_MINION_GENE_POOL: &'static [&'static str] = &[
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
	"GzB2lQVwM00tTAm5gwajjf4wc0a5GzB2lQVwM00tTAm5gwajjf4wc0a5",
	"GzB2lQdwM10vQEu5zwaPgDhfq2v8GzB2lQdwM10vQEu5zwaPgDhfq2v8",
];

pub const COLOR_SUNSHINE: [f32; 4] = [400.0, 90.0, 1.0, 1.0];
pub const COLOR_TRANSPARENT: [f32; 4] = [0.; 4];
pub const COLOR_WHITE: [f32; 4] = [1.; 4];
#[allow(unused)]
pub const COLOR_BLACK: [f32; 4] = [0., 0., 0., 1.];

pub const DEFAULT_RESOURCE_GENE_POOL: &'static [&'static str] = &["GyA21QoQ", "M00sWS0M"];

pub const CONFIG_DIR_HOME: &'static str = ".config/rust-oids";
pub const CONFIG_DIR_SAVED_STATE: &'static str = "saved_state";
pub const CONFIG_DIR_RESOURCES: &'static str = "resources";
pub const DUMP_FILE_PATTERN_CSV: &'static str = "%Y%m%d_%H%M%S.csv";
pub const DUMP_FILE_PATTERN_JSON: &'static str = "%Y%m%d_%H%M%S.json";

pub const CAPTURE_FOLDER_TIMESTAMP_PATTERN: &'static str = "%Y%m%d_%H%M%S";
pub const CAPTURE_FOLDER: &'static str = "capture";
pub const CAPTURE_FILENAME_PREFIX: &'static str = "capture_";

pub const AMBIENT_LIGHTS: &'static [[f32; 4]] = &[
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[31.0, 31.0, 31.0, 1.0],
	[100.0, 100.0, 100.0, 1.0],
	[0.001, 0.001, 0.001, 1.0],
	[0.01, 0.01, 0.01, 1.0],
	[0.1, 0.1, 0.1, 1.0],
	[0.31, 0.31, 0.31, 0.5],
];

pub const SPEED_FACTORS: &'static [SpeedFactor] = &[1.0, 0.5, 0.2, 0.1, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0];

pub const BACKGROUNDS: &'static [[f32; 4]] = &[
	[0.05, 0.07, 0.1, 1.0],
	[0.5, 0.5, 0.5, 0.5],
	[1.0, 1.0, 1.0, 1.0],
	[3.1, 3.1, 3.1, 1.0],
	[10.0, 10.0, 10.0, 1.0],
	[0., 0., 0., 1.0],
	[0.01, 0.01, 0.01, 1.0],
];
<|endoftext|>


<commit_before>//! Main evaluator loop and setting up the initial stack frame.

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc::hir::def_id::DefId;
use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking and Stacked Borrows are enabled.
    pub validate: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate),
        MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars);

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;

    if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
        throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx
        .memory
        .create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): `1`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // For Windows, construct a command string with all the aguments (before we take apart `config.args`).
        let mut cmd = String::new();
        for arg in config.args.iter() {
            if !cmd.is_empty() {
                cmd.push(' ');
            }
            cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
        }
        // Don't forget `0` terminator.
        cmd.push(std::char::from_u32(0).unwrap());
        // Collect the pointers to the individual strings.
        let mut argvs = Vec::<Pointer<Tag>>::new();
        for arg in config.args {
            // Add `0` terminator.
            let mut arg = arg.into_bytes();
            arg.push(0);
            argvs.push(
                ecx.memory
                    .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()),
            );
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout = ecx.layout_of(
            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64),
        )?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(Scalar::Ptr(arg), place.into())?;
        }
        ecx.memory
            .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the argument.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place = ecx.allocate(
                ecx.layout_of(tcx.types.isize)?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(
        ecx.layout_of(tcx.types.isize)?,
        MiriMemoryKind::Static.into(),
    );
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc, argv],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        ecx.run()?;
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            // Disable the leak test on some platforms where we do not
            // correctly implement TLS destructors.
            let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
            let ignore_leaks = target_os == "windows" || target_os == "macos";
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            return Some(return_code)
        }
        Err(mut e) => {
            // Special treatment for some error kinds
            let msg = match e.kind {
                InterpError::Exit(code) => return Some(code.into()),
                err_unsup!(NoMirFor(..)) =>
                    format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
                _ => e.to_string()
            };
            e.print_backtrace();
            if let Some(frame) = ecx.stack().last() {
                let block = &frame.body.basic_blocks()[frame.block.unwrap()];
                let span = if frame.stmt < block.statements.len() {
                    block.statements[frame.stmt].source_info.span
                } else {
                    block.terminator().source_info.span
                };

                let msg = format!("Miri evaluation error: {}", msg);
                let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
                let frames = ecx.generate_stacktrace(None);
                err.span_label(span, msg);
                // We iterate with indices because we need to look at the next frame (the caller).
                for idx in 0..frames.len() {
                    let frame_info = &frames[idx];
                    let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
                        caller_info.instance.def_id().is_local()
                    });
                    if call_site_is_local {
                        err.span_note(frame_info.call_site, &frame_info.to_string());
                    } else {
                        err.note(&frame_info.to_string());
                    }
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&msg);
            }

            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:?}", frame.return_place.map(|p| *p));
                for (i, local) in frame.locals.iter().enumerate() {
                    trace!("    local {}: {:?}", i, local.value);
                }
            }
            // Let the reported error determine the return code.
            return None;
        }
    }
}
<commit_msg>fix comment<commit_after>//! Main evaluator loop and setting up the initial stack frame.

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc::hir::def_id::DefId;
use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking and Stacked Borrows are enabled.
    pub validate: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(syntax::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate),
        MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars);

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;

    if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 {
        throw_unsup_format!("miri does not support main functions without `fn()` type signatures");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx
        .memory
        .create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // For Windows, construct a command string with all the aguments (before we take apart `config.args`).
        let mut cmd = String::new();
        for arg in config.args.iter() {
            if !cmd.is_empty() {
                cmd.push(' ');
            }
            cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
        }
        // Don't forget `0` terminator.
        cmd.push(std::char::from_u32(0).unwrap());
        // Collect the pointers to the individual strings.
        let mut argvs = Vec::<Pointer<Tag>>::new();
        for arg in config.args {
            // Add `0` terminator.
            let mut arg = arg.into_bytes();
            arg.push(0);
            argvs.push(
                ecx.memory
                    .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()),
            );
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout = ecx.layout_of(
            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64),
        )?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(Scalar::Ptr(arg), place.into())?;
        }
        ecx.memory
            .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the argument.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place = ecx.allocate(
                ecx.layout_of(tcx.types.isize)?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(
        ecx.layout_of(tcx.types.isize)?,
        MiriMemoryKind::Static.into(),
    );
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc, argv],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        ecx.run()?;
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            // Disable the leak test on some platforms where we do not
            // correctly implement TLS destructors.
            let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
            let ignore_leaks = target_os == "windows" || target_os == "macos";
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            return Some(return_code)
        }
        Err(mut e) => {
            // Special treatment for some error kinds
            let msg = match e.kind {
                InterpError::Exit(code) => return Some(code.into()),
                err_unsup!(NoMirFor(..)) =>
                    format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e),
                _ => e.to_string()
            };
            e.print_backtrace();
            if let Some(frame) = ecx.stack().last() {
                let block = &frame.body.basic_blocks()[frame.block.unwrap()];
                let span = if frame.stmt < block.statements.len() {
                    block.statements[frame.stmt].source_info.span
                } else {
                    block.terminator().source_info.span
                };

                let msg = format!("Miri evaluation error: {}", msg);
                let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
                let frames = ecx.generate_stacktrace(None);
                err.span_label(span, msg);
                // We iterate with indices because we need to look at the next frame (the caller).
                for idx in 0..frames.len() {
                    let frame_info = &frames[idx];
                    let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
                        caller_info.instance.def_id().is_local()
                    });
                    if call_site_is_local {
                        err.span_note(frame_info.call_site, &frame_info.to_string());
                    } else {
                        err.note(&frame_info.to_string());
                    }
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&msg);
            }

            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:?}", frame.return_place.map(|p| *p));
                for (i, local) in frame.locals.iter().enumerate() {
                    trace!("    local {}: {:?}", i, local.value);
                }
            }
            // Let the reported error determine the return code.
            return None;
        }
    }
}
<|endoftext|>


<commit_before>use env::Env;
use var::Var;
use source::{Src,Next};
use logic::LogicFn;
use def::DefBlock;

use std::collections::HashMap;

/// Creates a possible path from a dot-seperated string
///
/// Returns path, and final symbol
/// Eg: 'items.bag.coins' becomes -> (Some(Vec['items','bag']), 'coins')
pub fn as_path<'a> (lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
    let mut lookups: Vec<&'a str> = lookup.split_terminator('.').collect();
    let item = lookups.pop().unwrap();

    let path;
    if lookups.len() > 0 { path = Some(lookups); }
    else { path = None }

    (path,item)
}

/// Primary Evaluation trait must be implemented to run Evaluator
///
///
pub trait Eval {
    /// Get method to retrieve variable from Rust side
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var>;

    fn as_path<'a> (&self, lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
        as_path(lookup)
    }

    fn get_path (&self, lookup: &str) -> Option<Var> {
        let (path,lookup) = self.as_path(lookup);
        self.get(path, lookup)
    }

    /// Returns final ref or var, and if it is a var
    fn get_last (&self, lookup: &str) -> Option<(Var, bool)>;

    /// Expects var to be written to underlying mem/store in Rust
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var);

    fn set_path (&mut self, lookup: &str, v: Var) {
        let (path,lookup) = self.as_path(&lookup);
        self.set(path,lookup, v);
    }

    /// A custom callable function
    ///
    /// Var represents variable to mutate
    /// Fun is the function name
    /// Vars are any additional arguments
    /// Can optionally return variable back to lichen
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var>;
}

pub struct Evaluator<'e> {
    env: &'e mut Env,
    node_stack: Vec<String>,
}

impl<'e> Iterator for Evaluator<'e> {

        type Item = (Vec<Var>, Option<Next>); //here we only return node name as an option to advance
        fn next(&mut self) -> Option<Self::Item> {
            if let Some(nn) = self.node_stack.pop() {
                if let Some(r) = self.run(&nn) {
                    // reset node if necessary
                    if let Some(ref next) = r.1 {
                        match next {
                            &Next::Restart(ref nn) => {
                                if let &Some(ref nn) = nn {
                                    if let Some(b) = self.env.src.get_mut(nn) {
                                        b.idx = 0;
                                    }
                                }
                            }
                            _ => {}, // we handle the rest during Run, for convenience
                        }
                    }

                    Some(r)
                }
                else { self.next() }
            }
            else { None }
        }
    }

impl<'e> Evaluator<'e> {
    /// Evaluator by default starts on the node named 'root'
    pub fn new (env: &'e mut Env) -> Evaluator<'e> {
        Evaluator {
            env: env,
            node_stack: vec!["root".to_owned()],
        }
    }

    /// Consumes Evaluator for saving state
    ///
    /// You should save the Env state as well, as it's external to the Evaluator
    pub fn save (self) -> EvaluatorState {
        EvaluatorState {
            node_stack: self.node_stack,
        }
    }

    /// Advances Evaluator to next node
    ///
    /// If you specify a node name, Evaluator will start there on next step
    pub fn advance (&mut self, node: String) {
        self.node_stack.push(node);
    }

    pub fn resolve (s: &str, logic: &HashMap<String,LogicFn>, def: &HashMap<String,DefBlock>) -> Option<Var> {
        if let Some(ref lfn) = logic.get(s) {
            if let Some(val_) = lfn.run(&def) {
                return Some(val_.into())
            }
        }
        else if let Some((v,res)) = def.get_last(s) {
            if res { return Some(v) }
        }

        None
    }

    /// Manually run the Evaluator, starting at node specified
    pub fn run (&mut self, node_name: &str)
                -> Option<(Vec<Var>, Option<Next>)>
    {
        if let Some(b) = self.env.src.get_mut(node_name) {
            b.visited = true;

            if let Some(src) = b.src.get(b.idx) {
                self.node_stack.push(node_name.to_owned()); //more to iterate through?
                b.idx += 1;
println!("src: {:?}",src);
                match src {
                    &Src::Or(_,_) => {
                        if !b.or_valid {
                            return None
                        }
                        else { b.or_valid = false; } //reset
                    }
                    &Src::If(_,_,_) => { b.or_valid = true; }
                    // anything else resets above or-logic
                    &Src::Logic(ref name, ref logic) => {
                        // NOTE: we only add logicfn if not compiled yet!
                        if !b.logic.contains_key(name) {
                            let lfn = logic.eval();
                            b.logic.insert(name.clone(),lfn);
                        }

                        b.or_valid = false;
                    },
                    _ => { b.or_valid = false; },
                }

                let (mut vars, next) = src.eval(&b.logic, &mut self.env.def);
                let has_return = (vars.len() > 0) || next.is_some();

                // reset when if is successful
                if has_return { b.or_valid = false; }

                for var in vars.iter_mut() {
                    let mut val = None;

                    match var {
                        &mut Var::Sym(ref mut s) => { // resolve symbol refs
                            val = Evaluator::resolve(s, &b.logic, &self.env.def);
                            // NOTE: otherwise we silently fail
                        },
                        &mut Var::String(ref mut s) => { //format string
                            let mut fs = String::new();
                            let mut sym = String::new();
                            let mut in_sym = false;

                            for c in s.chars() {
                                if (c == ' ' || c == '`') && !sym.is_empty() {
                                    if let Some((v,res)) = self.env.def.get_last(&sym) {
                                        if res { fs.push_str(&v.to_string()); }
                                        else {
                                            if let Some(v) = Evaluator::resolve(&v.to_string(), &b.logic, &self.env.def) {
                                                fs.push_str(&v.to_string());
                                            }
                                        }
                                    }
                                    else if let Some(v) = Evaluator::resolve(&sym, &b.logic, &self.env.def) {
                                        fs.push_str(&v.to_string());
                                    }
                                    else {
                                        fs.push_str(&sym); //push as non-ref sym again
                                        // NOTE: we should consider failing silently (dont push)
                                    }

                                    if c == '`' { in_sym = true; }
                                    else {
                                        in_sym = false;
                                        sym.clear();
                                        fs.push(' ');
                                    }
                                }
                                else if c == '`' { in_sym = true; }
                                else {
                                    if in_sym { sym.push(c); }
                                    else { fs.push(c); }
                                }
                            }

                            if !sym.is_empty() {
                                if let Some((v,res)) = self.env.def.get_last(&sym) {
                                    if res { fs.push_str(&v.to_string()); }
                                    else if let Some(v) = Evaluator::resolve(&v.to_string(), &b.logic, &self.env.def) {
                                        fs.push_str(&v.to_string());
                                    }
                                    else {
                                        fs.push_str(&sym);
                                    }

                                }
                                else if let Some(v) = Evaluator::resolve(&sym, &b.logic, &self.env.def) {
                                    fs.push_str(&v.to_string());
                                }
                                else {
                                    fs.push_str(&sym);
                                }
                            }

                            *s = fs;
                        },
                        _ => {}
                    }

                    if let Some(val) = val {
                        *var = val;
                    }
                }

                if let Some(ref next) = next {
                    match next {
                        &Next::Now(ref nn) => { self.node_stack.push(nn.clone()); },
                        &Next::Back => { self.node_stack.pop(); },
                        &Next::Restart(ref nn) => {
                            if nn.is_none() { b.idx = 0; }
                            // NOTE: see iterator for other side of this
                        },
                        &Next::Clear => {
                            self.node_stack.clear();
                            self.node_stack.push(b.name.to_owned());
                        },
                        &Next::Exit => { self.node_stack.clear(); },
                        _ => {},
                    }
                }

                if has_return {
                    return Some((vars,next))
                }
                else {
                    return None
                }
            }
            else if b.idx > 0 { // we've been here, but node is finished?
                b.idx = 0; //reset
            }
        }

        None
    }
}

#[derive(Clone,Debug)]
pub struct EvaluatorState {
    node_stack: Vec<String>,
}

impl EvaluatorState {
    pub fn to_eval<'e> (self, env: &'e mut Env) -> Evaluator<'e> {
        Evaluator {
            env: env,
            node_stack: self.node_stack,
        }
    }

    pub fn as_eval<'e> (&self, env: &'e mut Env) -> Evaluator<'e> {
        self.clone().to_eval(env)
    }
}
<commit_msg>wip fix logic<commit_after>use env::Env;
use var::Var;
use source::{Src,Next};
use logic::LogicFn;
use def::DefBlock;

use std::collections::HashMap;

/// Creates a possible path from a dot-seperated string
///
/// Returns path, and final symbol
/// Eg: 'items.bag.coins' becomes -> (Some(Vec['items','bag']), 'coins')
pub fn as_path<'a> (lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
    let mut lookups: Vec<&'a str> = lookup.split_terminator('.').collect();
    let item = lookups.pop().unwrap();

    let path;
    if lookups.len() > 0 { path = Some(lookups); }
    else { path = None }

    (path,item)
}

/// Primary Evaluation trait must be implemented to run Evaluator
///
///
pub trait Eval {
    /// Get method to retrieve variable from Rust side
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var>;

    fn as_path<'a> (&self, lookup: &'a str) -> (Option<Vec<&'a str>>, &'a str) {
        as_path(lookup)
    }

    fn get_path (&self, lookup: &str) -> Option<Var> {
        let (path,lookup) = self.as_path(lookup);
        self.get(path, lookup)
    }

    /// Returns final ref or var, and if it is a var
    fn get_last (&self, lookup: &str) -> Option<(Var, bool)>;

    /// Expects var to be written to underlying mem/store in Rust
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var);

    fn set_path (&mut self, lookup: &str, v: Var) {
        let (path,lookup) = self.as_path(&lookup);
        self.set(path,lookup, v);
    }

    /// A custom callable function
    ///
    /// Var represents variable to mutate
    /// Fun is the function name
    /// Vars are any additional arguments
    /// Can optionally return variable back to lichen
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var>;
}

pub struct Evaluator<'e> {
    env: &'e mut Env,
    node_stack: Vec<String>,
}

impl<'e> Iterator for Evaluator<'e> {

        type Item = (Vec<Var>, Option<Next>); //here we only return node name as an option to advance
        fn next(&mut self) -> Option<Self::Item> {
            if let Some(nn) = self.node_stack.pop() {
                if let Some(r) = self.run(&nn) {
                    // reset node if necessary
                    if let Some(ref next) = r.1 {
                        match next {
                            &Next::Restart(ref nn) => {
                                if let &Some(ref nn) = nn {
                                    if let Some(b) = self.env.src.get_mut(nn) {
                                        b.idx = 0;
                                    }
                                }
                            }
                            _ => {}, // we handle the rest during Run, for convenience
                        }
                    }

                    Some(r)
                }
                else { self.next() }
            }
            else { None }
        }
    }

impl<'e> Evaluator<'e> {
    /// Evaluator by default starts on the node named 'root'
    pub fn new (env: &'e mut Env) -> Evaluator<'e> {
        Evaluator {
            env: env,
            node_stack: vec!["root".to_owned()],
        }
    }

    /// Consumes Evaluator for saving state
    ///
    /// You should save the Env state as well, as it's external to the Evaluator
    pub fn save (self) -> EvaluatorState {
        EvaluatorState {
            node_stack: self.node_stack,
        }
    }

    /// Advances Evaluator to next node
    ///
    /// If you specify a node name, Evaluator will start there on next step
    pub fn advance (&mut self, node: String) {
        self.node_stack.push(node);
    }

    pub fn resolve (s: &str, logic: &HashMap<String,LogicFn>, def: &HashMap<String,DefBlock>) -> Option<Var> {
        if let Some(ref lfn) = logic.get(s) {
            if let Some(val_) = lfn.run(&def) {
                return Some(val_.into())
            }
        }
        else if let Some((v,res)) = def.get_last(s) {
            if res { return Some(v) }
        }

        None
    }

    /// Manually run the Evaluator, starting at node specified
    pub fn run (&mut self, node_name: &str)
                -> Option<(Vec<Var>, Option<Next>)>
    {
        if let Some(b) = self.env.src.get_mut(node_name) {
            b.visited = true;

            if let Some(src) = b.src.get(b.idx) {
                self.node_stack.push(node_name.to_owned()); //more to iterate through?
                b.idx += 1;
println!("src: {:?}",src);
                match src {
                    &Src::Or(_,_) => {
                        if !b.or_valid {
                            return None
                        }
                        else { b.or_valid = false; } //reset
                    }
                    &Src::If(_,_,_) => { b.or_valid = true; }
                    // anything else resets above or-logic
                    &Src::Logic(ref name, ref logic) => {
                        // NOTE: we only add logicfn if not compiled yet!
                        if !b.logic.contains_key(name) {
                            let lfn = logic.eval();
                            b.logic.insert(name.clone(),lfn);
                        }

                        b.or_valid = false;
                    },
                    _ => { b.or_valid = false; },
                }

                let (mut vars, next) = src.eval(&b.logic, &mut self.env.def);
                let has_return = (vars.len() > 0) || next.is_some();

                // reset when if is successful
                if has_return { b.or_valid = false; }

                for var in vars.iter_mut() {
                    let mut val = None;

                    match var {
                        &mut Var::Sym(ref mut s) => { // resolve symbol refs
                            val = Evaluator::resolve(s, &b.logic, &self.env.def);
                            // NOTE: otherwise we silently fail
                        },
                        &mut Var::String(ref mut s) => { //format string
                            let mut fs = String::new();
                            let mut sym = String::new();
                            let mut in_sym = false;

                            for c in s.chars() {
                                if (c == ' ' || c == '`') && !sym.is_empty() {
                                    if let Some(v) = Evaluator::resolve(&sym, &b.logic, &self.env.def) {
                                        fs.push_str(&v.to_string());
                                    }
                                    else {
                                        fs.push_str(&sym); //push as non-ref sym again
                                        // NOTE: we should consider failing silently (dont push)
                                    }

                                    if c == '`' { in_sym = true; }
                                    else {
                                        in_sym = false;
                                        sym.clear();
                                        fs.push(' ');
                                    }
                                }
                                else if c == '`' { in_sym = true; }
                                else {
                                    if in_sym { sym.push(c); }
                                    else { fs.push(c); }
                                }
                            }

                            if !sym.is_empty() {
                                if let Some(v) = Evaluator::resolve(&sym, &b.logic, &self.env.def) {
                                    fs.push_str(&v.to_string());
                                }
                                else {
                                    fs.push_str(&sym);
                                }
                            }

                            *s = fs;
                        },
                        _ => {}
                    }

                    if let Some(val) = val {
                        *var = val;
                    }
                }

                if let Some(ref next) = next {
                    match next {
                        &Next::Now(ref nn) => { self.node_stack.push(nn.clone()); },
                        &Next::Back => { self.node_stack.pop(); },
                        &Next::Restart(ref nn) => {
                            if nn.is_none() { b.idx = 0; }
                            // NOTE: see iterator for other side of this
                        },
                        &Next::Clear => {
                            self.node_stack.clear();
                            self.node_stack.push(b.name.to_owned());
                        },
                        &Next::Exit => { self.node_stack.clear(); },
                        _ => {},
                    }
                }

                if has_return {
                    return Some((vars,next))
                }
                else {
                    return None
                }
            }
            else if b.idx > 0 { // we've been here, but node is finished?
                b.idx = 0; //reset
            }
        }

        None
    }
}

#[derive(Clone,Debug)]
pub struct EvaluatorState {
    node_stack: Vec<String>,
}

impl EvaluatorState {
    pub fn to_eval<'e> (self, env: &'e mut Env) -> Evaluator<'e> {
        Evaluator {
            env: env,
            node_stack: self.node_stack,
        }
    }

    pub fn as_eval<'e> (&self, env: &'e mut Env) -> Evaluator<'e> {
        self.clone().to_eval(env)
    }
}
<|endoftext|>