<commit_before>use std;
import io::{writer_util, reader_util};
import std::map;
import map::hashmap;
import result;

export rowreader, rowaccess, rowiter,
       new_reader, new_reader_readlen,
       hashmap_iter, hashmap_iter_full;

enum state {
    fieldstart(bool),
    infield(uint, uint),
    inquotedfield(uint, uint),
    inquote(uint, uint)
}

type rowreader = {
    readlen: uint,
    delim: char,
    quote: char,
    f : io::reader,
    mutable offset : uint,
    mutable buffers : [@[char]],
    mutable state : state,
    mutable trailing_nl : bool,
    mutable terminating : bool
};

type row = {
    fields : [ fieldtype ]
};

type bufferdescr = {
    escaped: bool,
    buffers: [@[char]],
    start: uint,
    end: uint
};

enum fieldtype {
    emptyfield(),
    bufferfield(bufferdescr)
}

iface rowiter {
    fn readrow() -> result::result<row, str>;
}

iface rowaccess {
    fn len() -> uint;
    fn getchars(uint) -> [char];
    fn getstr(uint) -> str;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    {
        readlen: 1024u,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false),
        mutable trailing_nl : false,
        mutable terminating: false
    }
}

fn new_reader_readlen(+f: io::reader, +delim: char, +quote: char, rl: uint) -> rowreader {
    {
        readlen: rl,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false),
        mutable trailing_nl : false,
        mutable terminating: false
    }
}

impl of rowaccess for row {
    fn len() -> uint {
        vec::len(self.fields)
    }
    fn getchars(field: uint) -> [char] {
        fn unescape(escaped: [char]) -> [char] {
            let mut r : [char] = [];
            vec::reserve(r, vec::len(escaped));
            let mut in_q = false;
            for c in escaped {
                if in_q {
                    assert(c == '"');
                    in_q = false;
                } else {
                    in_q = c == '"';
                    r += [c];
                }
            }
            ret r;
        }
        alt self.fields[field] {
            emptyfield() { ret []; }
            bufferfield(desc) {
                let mut buf = [];
                {
                    let mut i = 0u;
                    while i < vec::len(desc.buffers) {
                        let from = if (i == 0u)
                            { desc.start } else { 0u };
                        let to = if (i == vec::len(desc.buffers) - 1u)
                            { desc.end } else { vec::len(*desc.buffers[i]) };
                        buf += vec::slice(*desc.buffers[i], from, to);
                        i = i + 1u;
                    }
                }
                if field == self.len() - 1u {
                    // there may be a trailing \r on the last field; we should strip it
                    // if so. bodgy here but seems the most efficient place to deal with this
                    if vec::len(buf) > 0u {
                        if buf[vec::len(buf)-1u] == '\r' {
                            buf = vec::slice(buf, 0u, vec::len(buf)-1u);
                        }
                    }
                }
                if desc.escaped {
                    buf = unescape(buf);
                }
                ret buf;
            }
        };
    }
    fn getstr(field: uint) -> str {
        ret str::from_chars(self.getchars(field));
    }
    fn getall() -> [str] {
        let mut a = [];
        self.map() { |s|
            a += [s];
        }
        ret a;
    }
    fn map(f: fn(s: str)) {
        let mut i = 0u;
        let len = self.len();
        while i < len {
            f(self.getstr(i));
            i += 1u;
        }
    }
}

impl of rowiter for rowreader {
    fn readrow() -> result::result<row, str> {
        fn statestr(state: state) -> str {
            alt state {
                fieldstart(after_delim) {
                    #fmt("fieldstart : after_delim %b", after_delim)
                }
                infield(b,o) {
                    #fmt("field : %u %u", b, o)
                }
                inquotedfield(b, o) {
                    #fmt("inquotedfield : %u %u", b, o)
                }
                inquote(b, o) {
                    #fmt("inquote : %u %u", b, o)
                }
            }
        }
        fn row_from_buf(self: rowreader, &fields: [fieldtype]) -> bool {
            fn new_bufferfield(self: rowreader, escaped: bool, sb: uint, so: uint, eo: uint) -> fieldtype {
                let mut eb = vec::len(self.buffers) - 1u;
                let mut sb = sb, so = so, eo = eo;
                //#debug("sb %u so %u eb %u eo %u", sb, so, eb, eo);
                //log(debug, vec::map(self.buffers) { |t| str::from_chars(*t) } );
                //log(debug, vec::map(self.buffers) { |t| vec::len(*t) });
                if escaped {
                    so += 1u;
                    if so > vec::len(*self.buffers[sb]) {
                        sb += 1u;
                        so = vec::len(*self.buffers[sb]) - 1u;
                    }
                    if eo > 0u {
                        eo -= 1u;
                    } else {
                        eb -= 1u;
                        eo = vec::len(*self.buffers[eb]) - 1u;
                    }
                }
                //#debug("sb %u so %u eb %u eo %u", sb, so, eb, eo);
                bufferfield({ escaped: escaped, buffers: vec::slice(self.buffers, sb, eb+1u), start: so, end: eo })
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf: @[char] = self.buffers[cbuffer];
            while self.offset < vec::len(*buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                #debug("got '%c' | %s", c, statestr(self.state));
                self.offset += 1u;
                alt self.state {
                    fieldstart(after_delim) {
                        #debug("fieldstart : after_delim %b", after_delim);
                        if c == self.quote {
                            self.state = inquotedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                fields += [emptyfield];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [emptyfield];
                        } else {
                            self.state = infield(cbuffer, coffset);
                        }
                    }
                    infield(b,o) {
                        #debug("field : %u %u", b, o);
                        if c == '\n' {
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                        }
                    }
                    inquotedfield(b, o) {
                        #debug("inquotedfield : %u %u", b, o);
                        if c == self.quote {
                            self.state = inquote(b, o);
                        }
                    }
                    inquote(b, o) {
                        #debug("inquote : %u %u", b, o);
                        if c == '\n' {
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                            ret true;
                        } else if c == self.quote {
                            self.state = inquotedfield(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
                #debug("now %s", statestr(self.state));
            }
            ret false;
        }

        self.state = fieldstart(false);
        let mut do_read = vec::len(self.buffers) == 0u;
        let mut fields = [];

        while !self.terminating {
            if do_read {
                let mut data: @[char] = @self.f.read_chars(self.readlen);
                if vec::len(*data) == 0u {
                    if !self.trailing_nl {
                        self.terminating = true;
                        data = @['\n'];
                    } else {
                        ret result::err("EOF");
                    }
                } else {
                    self.trailing_nl = data[vec::len(*data) - 1u] == '\n';
                }
                self.buffers += [data];
                self.offset = 0u;
            }

            if row_from_buf(self, fields) {
                let r: row = { fields: fields };
                fields = [];
                if vec::len(self.buffers) > 1u {
                    self.buffers = vec::slice(self.buffers, vec::len(self.buffers) - 1u, vec::len(self.buffers));
                }
                ret result::ok(r);
            }
            do_read = true;
        }
        ret result::err("unreachable");
    }
}

fn hashmap_iter_cols(r: rowreader, cols: [str], f: fn(map::hashmap<str, str>)) {
    loop {
        let res = r.readrow();
        if result::failure(res) {
            break;
        }
        let m : map::hashmap<str, str> = map::str_hash();
        let mut col = 0u;
        let row = result::get(res);
        if row.len() != vec::len(cols) {
            cont; // FIXME: how to flag that we dropped a crazy row?
        }
        result::get(res).map() { |s|
            m.insert(cols[col], s);
            col += 1u;
        };
        f(m);
    }
}

// reads the first row as a header, to derive keys for a hashmap
// emitted for each subsequent row
fn hashmap_iter(r: rowreader, f: fn(map::hashmap<str, str>)) {
    let res = r.readrow();
    alt res {
        result::ok(row) {
            hashmap_iter_cols(r, result::get(res).getall(), f);
        }
        result::err(_) { }
    }
}

// as hashmap_iter, but first apply 'hc' to each header; allows
// cleaning up headers; also allows verification that heads are
// satisfactory
fn hashmap_iter_full(r: rowreader, hmap: fn(&&h: str) -> str, hver: fn(cols: [str]) -> bool, f: fn(map::hashmap<str, str>)) {
    let res = r.readrow();
    alt res {
        result::ok(row) {
            let cols : [str] = vec::map(result::get(res).getall(), hmap);
            if !hver(cols) {
                ret;
            }
            hashmap_iter_cols(r, cols, f);
        }
        result::err(_) { }
    }
}

#[cfg(test)]
mod test {
    fn rowmatch(testdata: str, expected: [[str]]) {
        let chk = fn@(mk: fn(io::reader) -> rowreader) {
            let f = io::str_reader(testdata);
            let r = mk(f);
            let mut i = 0u;
            loop {
                let res = r.readrow();
                if result::failure(res) {
                    break;
                }
                let row = result::get(res);
                let expect = expected[i];

                assert(row.len() == vec::len(expect));
                let mut j = 0u;
                while j < row.len() {
                    assert(row.getstr(j) == expect[j]);
                    j += 1u;
                }
                i += 1u;
            }
            assert(i == vec::len(expected));
        };
        let runchecks = fn@(testdata: str) {
            // test default reader params
            chk() { |inp|
                new_reader_readlen(inp, ',', '"', 2u)
            };
            // test default constructor
            chk() { |inp|
                new_reader(inp, ',', '"')
            };
            // test continuations over read buffers
            let mut j = 1u;
            while j < str::len(testdata) {
                chk() { |inp|
                    new_reader_readlen(inp, ',', '"', j)
                };
                j += 1u;
            }
            ret;
        };
        // so we can test trailing newline case, testdata
        // must not end in \n - leave off the last newline
        runchecks(testdata);
        runchecks(testdata+"\n");
        runchecks(str::replace(testdata, "\n", "\r\n"));
    }

    #[test]
    fn test_simple() {
        rowmatch("a,b,c,d\n1,2,3,4",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4"]]);
    }

    #[test]
    fn test_trailing_comma() {
        rowmatch("a,b,c,d\n1,2,3,4,",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4", ""]]);
    }

    #[test]
    fn test_leading_comma() {
        rowmatch("a,b,c,d\n,1,2,3,4",
                 [["a", "b", "c", "d"], ["", "1", "2", "3", "4"]]);
    }

    #[test]
    fn test_quote_simple() {
        rowmatch("\"Hello\",\"There\"\na,b,\"c\",d",
                 [["Hello", "There"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_quote_nested() {
        rowmatch("\"Hello\",\"There is a \"\"fly\"\" in my soup\"\na,b,\"c\",d",
                 [["Hello", "There is a \"fly\" in my soup"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_quote_with_comma() {
        rowmatch("\"1,2\"",
                 [["1,2"]])
    }

    #[test]
    fn test_quote_with_other_comma() {
        rowmatch("1,2,3,\"a,b,c\"",
                 [["1", "2", "3", "a,b,c"]])
    }

    #[test]
    fn test_blank_line() {
        rowmatch("\n\n", [[], []]);
    }
}

<commit_msg>fix test, change interface significantly<commit_after>use std;
import io::{writer_util, reader_util};
import std::map;
import map::hashmap;
import result;

export rowreader, rowiter,
       new_reader, new_reader_readlen,
       hashmap_iter, hashmap_iter_full;

enum state {
    fieldstart(bool),
    infield(uint, uint),
    inquotedfield(uint, uint),
    inquote(uint, uint)
}

type rowreader = {
    readlen: uint,
    delim: char,
    quote: char,
    f : io::reader,
    mutable offset : uint,
    mutable buffers : [[char]],
    mutable state : state,
    mutable trailing_nl : bool,
    mutable terminating : bool
};

type row = {
    fields : [ fieldtype ]
};

type bufferdescr = {
    escaped: bool,
    sb: uint,
    eb: uint,
    start: uint,
    end: uint
};

enum fieldtype {
    emptyfield(),
    bufferfield(bufferdescr)
}

iface rowiter {
    fn readrow(&row: [str]) -> bool;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    {
        new_reader_readlen(f, delim, quote, 1024u)
    }
}

fn new_reader_readlen(+f: io::reader, +delim: char, +quote: char, rl: uint) -> rowreader {
    {
        readlen: rl,
        delim: delim,
        quote: quote,
        f: f,
        mutable offset : 0u,
        mutable buffers : [],
        mutable state : fieldstart(false),
        mutable trailing_nl : false,
        mutable terminating: false
    }
}

impl of rowiter for rowreader {
    fn readrow(&row: [str]) -> bool {
        fn statestr(state: state) -> str {
            alt state {
                fieldstart(after_delim) {
                    #fmt("fieldstart : after_delim %b", after_delim)
                }
                infield(b,o) {
                    #fmt("field : %u %u", b, o)
                }
                inquotedfield(b, o) {
                    #fmt("inquotedfield : %u %u", b, o)
                }
                inquote(b, o) {
                    #fmt("inquote : %u %u", b, o)
                }
            }
        }
        fn row_from_buf(self: rowreader, &fields: [fieldtype]) -> bool {
            fn new_bufferfield(self: rowreader, escaped: bool, sb: uint, so: uint, eo: uint) -> fieldtype {
                let mut eb = vec::len(self.buffers) - 1u;
                let mut sb = sb, so = so, eo = eo;
                if escaped {
                    so += 1u;
                    if so > vec::len(self.buffers[sb]) {
                        sb += 1u;
                        so = vec::len(self.buffers[sb]) - 1u;
                    }
                    if eo > 0u {
                        eo -= 1u;
                    } else {
                        eb -= 1u;
                        eo = vec::len(self.buffers[eb]) - 1u;
                    }
                }
                bufferfield({ escaped: escaped, sb: sb, eb: eb, start: so, end: eo })
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf = self.buffers[cbuffer];
            while self.offset < vec::len(buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                #debug("got '%c' | %s", c, statestr(self.state));
                self.offset += 1u;
                alt self.state {
                    fieldstart(after_delim) {
                        #debug("fieldstart : after_delim %b", after_delim);
                        if c == self.quote {
                            self.state = inquotedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                fields += [emptyfield];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [emptyfield];
                        } else {
                            self.state = infield(cbuffer, coffset);
                        }
                    }
                    infield(b,o) {
                        #debug("field : %u %u", b, o);
                        if c == '\n' {
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, false, b, o, coffset)];
                        }
                    }
                    inquotedfield(b, o) {
                        #debug("inquotedfield : %u %u", b, o);
                        if c == self.quote {
                            self.state = inquote(b, o);
                        }
                    }
                    inquote(b, o) {
                        #debug("inquote : %u %u", b, o);
                        if c == '\n' {
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                            ret true;
                        } else if c == self.quote {
                            self.state = inquotedfield(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [new_bufferfield(self, true, b, o, coffset)];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
                #debug("now %s", statestr(self.state));
            }
            ret false;
        }
        self.state = fieldstart(false);
        let mut do_read = vec::len(self.buffers) == 0u;
        let mut fields = [];

        while !self.terminating {
            if do_read {
                let mut data = self.f.read_chars(self.readlen);
                //log(error, ("aa", str::from_chars(data)));
                if vec::len(data) == 0u {
                    if !self.trailing_nl {
                        self.terminating = true;
                        data = ['\n'];
                    } else {
                        ret false;
                    }
                }
                // this is horrible, but it avoids the whole parser needing
                // to know about \r.
                data = vec::filter(data) { |c| c != '\r' };
                let data_len = vec::len(data);
                if data_len == 0u {
                    cont;
                }
                //log(error, ("here", str::from_chars(data)));
                self.trailing_nl = data[data_len - 1u] == '\n';
                self.buffers += [data];
                self.offset = 0u;
            }

            if row_from_buf(self, fields) {
                let l = vec::len(fields);
                vec::reserve(row, l);
                row = vec::map(fields) { |field|
                    fn unescape(escaped: [char]) -> [char] {
                        let mut r : [char] = [];
                        vec::reserve(r, vec::len(escaped));
                        let mut in_q = false;
                        for c in escaped {
                            if in_q {
                                assert(c == '"');
                                in_q = false;
                            } else {
                                in_q = c == '"';
                                r += [c];
                            }
                        }
                        ret r;
                    }
                    alt field {
                        emptyfield() { ret ""; }
                        bufferfield(desc) {
                            let mut buf = [];
                            {
                                let mut i = desc.sb;
                                while i <= desc.eb {
                                    let from = if (i == desc.sb)
                                        { desc.start } else { 0u };
                                    let to = if (i == desc.eb)
                                        { desc.end } else { vec::len(self.buffers[i]) };
                                    buf += vec::slice(self.buffers[i], from, to);
                                    i = i + 1u;
                                }
                            }
                            if desc.escaped {
                                buf = unescape(buf);
                            }
                            ret str::from_chars(buf);
                        }
                    };
                };
                if vec::len(self.buffers) > 1u {
                    self.buffers = vec::slice(self.buffers, vec::len(self.buffers) - 1u, vec::len(self.buffers));
                }
                fields = [];
                ret true;
            }
            do_read = true;
        }
        ret false;
    }
}

fn hashmap_iter_cols(r: rowreader, cols: [str], f: fn(map::hashmap<str, str>)) {
    let mut fields : [str] = [];
    while r.readrow(fields) {
        let m : map::hashmap<str, str> = map::str_hash();
        let mut col = 0u;
        if vec::len(fields) != vec::len(cols) {
            cont; // FIXME: how to flag that we dropped a crazy row?
        }
        vec::iter(fields) { |s|
            m.insert(cols[col], s);
            col += 1u;
        };
        f(m);
    }
}

// reads the first row as a header, to derive keys for a hashmap
// emitted for each subsequent row
fn hashmap_iter(r: rowreader, f: fn(map::hashmap<str, str>)) {
    let mut row: [str] = [];
    if r.readrow(row) {
        hashmap_iter_cols(r, row, f);
    }
}

// as hashmap_iter, but first apply 'hc' to each header; allows
// cleaning up headers; also allows verification that heads are
// satisfactory
fn hashmap_iter_full(r: rowreader, hmap: fn(&&h: str) -> str, hver: fn(cols: [str]) -> bool, f: fn(map::hashmap<str, str>)) {
    let mut row: [str] = [];
    if r.readrow(row) {
        let cols : [str] = vec::map(row, hmap);
        if !hver(cols) {
            ret;
        }
        hashmap_iter_cols(r, cols, f);
    }
}

#[cfg(test)]
mod test {
    fn rowmatch(testdata: str, expected: [[str]]) {
        let chk = fn@(s: str, mk: fn(io::reader) -> rowreader) {
            let f = io::str_reader(s);
            let r = mk(f);
            let mut i = 0u;
            loop {
                let mut row: [str] = [];
                if !r.readrow(row) {
                    break;
                }
                let expect = expected[i];
                assert(vec::len(row) == vec::len(expect));
                let mut j = 0u;
                while j < row.len() {
                    assert(row[j] == expect[j]);
                    j += 1u;
                }
                i += 1u;
            }
            assert(i == vec::len(expected));
        };
        let runchecks = fn@(s: str) {
            // test default reader params
            chk(s) { |inp|
                new_reader_readlen(inp, ',', '"', 2u)
            };
            // test default constructor
            chk(s) { |inp|
                new_reader(inp, ',', '"')
            };
            // test continuations over read buffers
            let mut j = 1u;
            while j < str::len(s) {
                chk(s) { |inp|
                    new_reader_readlen(inp, ',', '"', j)
                };
                j += 1u;
            }
            ret;
        };
        // so we can test trailing newline case, testdata
        // must not end in \n - leave off the last newline
        runchecks(testdata);
        runchecks(str::replace(testdata, "\n", "\r\n"));
        if !str::ends_with(testdata, "\n") {
            runchecks(testdata+"\n");
            runchecks(str::replace(testdata+"\n", "\n", "\r\n"));
        }
    }

    #[test]
    fn test_simple() {
        rowmatch("a,b,c,d\n1,2,3,4",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4"]]);
    }

    #[test]
    fn test_trailing_comma() {
        rowmatch("a,b,c,d\n1,2,3,4,",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4", ""]]);
    }

    #[test]
    fn test_leading_comma() {
        rowmatch("a,b,c,d\n,1,2,3,4",
                 [["a", "b", "c", "d"], ["", "1", "2", "3", "4"]]);
    }

    #[test]
    fn test_quote_simple() {
        rowmatch("\"Hello\",\"There\"\na,b,\"c\",d",
                 [["Hello", "There"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_quote_nested() {
        rowmatch("\"Hello\",\"There is a \"\"fly\"\" in my soup\"\na,b,\"c\",d",
                 [["Hello", "There is a \"fly\" in my soup"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn test_quote_with_comma() {
        rowmatch("\"1,2\"",
                 [["1,2"]])
    }

    #[test]
    fn test_quote_with_other_comma() {
        rowmatch("1,2,3,\"a,b,c\"",
                 [["1", "2", "3", "a,b,c"]])
    }

    #[test]
    fn test_blank_line() {
        rowmatch("\n\n", [[], []]);
    }
}

<|endoftext|>


<commit_before>import std::ivec;
import std::uint;
import std::str;
import std::termivec;
import std::ioivec;
import std::option;
import std::option::some;
import std::option::none;

type filename = str;

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */
type filemap = @rec(filename name, uint start_pos, mutable uint[] lines);

type codemap = @rec(mutable filemap[] files);

type loc = rec(filename filename, uint line, uint col);

fn new_codemap() -> codemap {
    let filemap[] files = ~[];
    ret @rec(mutable files=files);
}

fn new_filemap(filename filename, uint start_pos) -> filemap {
    ret @rec(name=filename, start_pos=start_pos, mutable lines=~[0u]);
}

fn next_line(filemap file, uint pos) { file.lines += ~[pos]; }

fn lookup_pos(codemap map, uint pos) -> loc {
    auto a = 0u;
    auto b = ivec::len[filemap](map.files);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (map.files.(m).start_pos > pos) { b = m; } else { a = m; }
    }
    auto f = map.files.(a);
    a = 0u;
    b = ivec::len[uint](f.lines);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (f.lines.(m) > pos) { b = m; } else { a = m; }
    }
    ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
}

type span = rec(uint lo, uint hi);

fn span_to_str(&span sp, &codemap cm) -> str {
    auto lo = lookup_pos(cm, sp.lo);
    auto hi = lookup_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
}

fn emit_diagnostic(&option::t[span] sp, &str msg, &str kind, u8 color,
                   &codemap cm) {
    auto ss = "<input>:0:0:0:0";
    let option::t[@file_lines] maybe_lines = none;
    alt (sp) {
        case (some(?ssp)) {
            ss = span_to_str(ssp, cm);
            maybe_lines = some(span_to_lines(ssp, cm));
        }
        case (none) { }
    }
    ioivec::stdout().write_str(ss + ": ");
    if (termivec::color_supported()) {
        termivec::fg(ioivec::stdout().get_buf_writer(), color);
    }
    ioivec::stdout().write_str(#fmt("%s:", kind));
    if (termivec::color_supported()) {
        termivec::reset(ioivec::stdout().get_buf_writer());
    }
    ioivec::stdout().write_str(#fmt(" %s\n", msg));
    alt (maybe_lines) {
        case (some(?lines)) {
            // FIXME: reading in the entire file is the worst possible way to
            //        get access to the necessary lines.
            auto rdr = ioivec::file_reader(lines.name);
            auto file = str::unsafe_from_bytes_ivec(rdr.read_whole_stream());
            auto fm = get_filemap(cm, lines.name);

            // arbitrarily only print up to six lines of the error
            auto max_lines = 6u;
            auto elided = false;
            auto display_lines = lines.lines;
            if (ivec::len(display_lines) > max_lines) {
                display_lines = ivec::slice(display_lines, 0u, max_lines);
                elided = true;
            }
            // Print the offending lines
            for (uint line in display_lines) {
                ioivec::stdout().write_str(#fmt("%s:%u ", fm.name,
                                                line + 1u));
                auto s = get_line(fm, line as int, file);
                if (!str::ends_with(s, "\n")) {
                    s += "\n";
                }
                ioivec::stdout().write_str(s);
            }
            if (elided) {
                auto last_line = display_lines.(ivec::len(display_lines) -
                                                1u);
                auto s = #fmt("%s:%u ", fm.name, last_line + 1u);
                auto indent = str::char_len(s);
                auto out = "";
                while (indent > 0u) { out += " "; indent -= 1u; }
                out += "...\n";
                ioivec::stdout().write_str(out);
            }

            // If there's one line at fault we can easily point to the problem
            if (ivec::len(lines.lines) == 1u) {
                auto lo = codemap::lookup_pos(cm, option::get(sp).lo);
                auto lo = lookup_pos(cm, option::get(sp).lo);
                auto digits = 0u;
                auto num = lines.lines.(0) / 10u;

                // how many digits must be indent past?
                while (num > 0u) { num /= 10u; digits += 1u; }

                // indent past |name:## | and the 0-offset column location
                auto left = str::char_len(fm.name) + digits + lo.col + 3u;
                auto s = "";
                while (left > 0u) { str::push_char(s, ' '); left -= 1u; }

                s += "^";
                auto hi = lookup_pos(cm, option::get(sp).hi);
                if (hi.col != lo.col) {
                    // the ^ already takes up one space
                    auto width = hi.col - lo.col - 1u;
                    while (width > 0u) {
                        str::push_char(s, '~');
                        width -= 1u;
                    }
                }
                ioivec::stdout().write_str(s + "\n");
            }
        }
        case (_) {}
    }
}

fn emit_warning(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "warning", 11u8, cm);
}
fn emit_error(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "error", 9u8, cm);
}
fn emit_note(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "note", 10u8, cm);
}

type file_lines = rec(str name, uint[] lines);

fn span_to_lines(span sp, codemap::codemap cm) -> @file_lines {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    auto lines = ~[];
    for each (uint i in uint::range(lo.line - 1u, hi.line as uint)) {
        lines += ~[i];
    }
    ret @rec(name=lo.filename, lines=lines);
}

fn get_line(filemap fm, int line, &str file) -> str {
    let uint begin = fm.lines.(line) - fm.start_pos;
    let uint end;
    if ((line as uint) + 1u >= ivec::len(fm.lines)) {
        end = str::byte_len(file);
    } else {
        end = fm.lines.(line + 1) - fm.start_pos;
    }
    ret str::slice(file, begin, end);
}

fn get_filemap(codemap cm, str filename) -> filemap {
    for (filemap fm in cm.files) {
        if (fm.name == filename) {
            ret fm;
        }
    }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail;// ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Fix pre-existing problem with filemap line positions always starting at 0. Fix error line output to only retrieve up to the nearest newline.<commit_after>import std::ivec;
import std::uint;
import std::str;
import std::termivec;
import std::ioivec;
import std::option;
import std::option::some;
import std::option::none;

type filename = str;

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */
type filemap = @rec(filename name, uint start_pos, mutable uint[] lines);

type codemap = @rec(mutable filemap[] files);

type loc = rec(filename filename, uint line, uint col);

fn new_codemap() -> codemap {
    let filemap[] files = ~[];
    ret @rec(mutable files=files);
}

fn new_filemap(filename filename, uint start_pos) -> filemap {
    ret @rec(name=filename, start_pos=start_pos, mutable lines=[start_pos]);
}

fn next_line(filemap file, uint pos) { file.lines += ~[pos]; }

fn lookup_pos(codemap map, uint pos) -> loc {
    auto a = 0u;
    auto b = ivec::len[filemap](map.files);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (map.files.(m).start_pos > pos) { b = m; } else { a = m; }
    }
    auto f = map.files.(a);
    a = 0u;
    b = ivec::len[uint](f.lines);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (f.lines.(m) > pos) { b = m; } else { a = m; }
    }
    ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
}

type span = rec(uint lo, uint hi);

fn span_to_str(&span sp, &codemap cm) -> str {
    auto lo = lookup_pos(cm, sp.lo);
    auto hi = lookup_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
}

fn emit_diagnostic(&option::t[span] sp, &str msg, &str kind, u8 color,
                   &codemap cm) {
    auto ss = "<input>:0:0:0:0";
    let option::t[@file_lines] maybe_lines = none;
    alt (sp) {
        case (some(?ssp)) {
            ss = span_to_str(ssp, cm);
            maybe_lines = some(span_to_lines(ssp, cm));
        }
        case (none) { }
    }
    ioivec::stdout().write_str(ss + ": ");
    if (termivec::color_supported()) {
        termivec::fg(ioivec::stdout().get_buf_writer(), color);
    }
    ioivec::stdout().write_str(#fmt("%s:", kind));
    if (termivec::color_supported()) {
        termivec::reset(ioivec::stdout().get_buf_writer());
    }
    ioivec::stdout().write_str(#fmt(" %s\n", msg));
    alt (maybe_lines) {
        case (some(?lines)) {
            // FIXME: reading in the entire file is the worst possible way to
            //        get access to the necessary lines.
            auto rdr = ioivec::file_reader(lines.name);
            auto file = str::unsafe_from_bytes_ivec(rdr.read_whole_stream());
            auto fm = get_filemap(cm, lines.name);

            // arbitrarily only print up to six lines of the error
            auto max_lines = 6u;
            auto elided = false;
            auto display_lines = lines.lines;
            if (ivec::len(display_lines) > max_lines) {
                display_lines = ivec::slice(display_lines, 0u, max_lines);
                elided = true;
            }
            // Print the offending lines
            for (uint line in display_lines) {
                ioivec::stdout().write_str(#fmt("%s:%u ", fm.name,
                                                line + 1u));
                auto s = get_line(fm, line as int, file);
                if (!str::ends_with(s, "\n")) {
                    s += "\n";
                }
                ioivec::stdout().write_str(s);
            }
            if (elided) {
                auto last_line = display_lines.(ivec::len(display_lines) -
                                                1u);
                auto s = #fmt("%s:%u ", fm.name, last_line + 1u);
                auto indent = str::char_len(s);
                auto out = "";
                while (indent > 0u) { out += " "; indent -= 1u; }
                out += "...\n";
                ioivec::stdout().write_str(out);
            }

            // If there's one line at fault we can easily point to the problem
            if (ivec::len(lines.lines) == 1u) {
                auto lo = codemap::lookup_pos(cm, option::get(sp).lo);
                auto lo = lookup_pos(cm, option::get(sp).lo);
                auto digits = 0u;
                auto num = lines.lines.(0) / 10u;

                // how many digits must be indent past?
                while (num > 0u) { num /= 10u; digits += 1u; }

                // indent past |name:## | and the 0-offset column location
                auto left = str::char_len(fm.name) + digits + lo.col + 3u;
                auto s = "";
                while (left > 0u) { str::push_char(s, ' '); left -= 1u; }

                s += "^";
                auto hi = lookup_pos(cm, option::get(sp).hi);
                if (hi.col != lo.col) {
                    // the ^ already takes up one space
                    auto width = hi.col - lo.col - 1u;
                    while (width > 0u) {
                        str::push_char(s, '~');
                        width -= 1u;
                    }
                }
                ioivec::stdout().write_str(s + "\n");
            }
        }
        case (_) {}
    }
}

fn emit_warning(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "warning", 11u8, cm);
}
fn emit_error(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "error", 9u8, cm);
}
fn emit_note(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "note", 10u8, cm);
}

type file_lines = rec(str name, uint[] lines);

fn span_to_lines(span sp, codemap::codemap cm) -> @file_lines {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    auto lines = ~[];
    for each (uint i in uint::range(lo.line - 1u, hi.line as uint)) {
        lines += ~[i];
    }
    ret @rec(name=lo.filename, lines=lines);
}

fn get_line(filemap fm, int line, &str file) -> str {
    let uint begin = fm.lines.(line) - fm.start_pos;
    let uint end;
    if (line as uint < ivec::len(fm.lines) - 1u) {
        end = fm.lines.(line + 1) - fm.start_pos;
    } else {
        // If we're not done parsing the file, we're at the limit of what's
        // parsed. If we just slice the rest of the string, we'll print out
        // the remainder of the file, which is undesirable.
        end = str::byte_len(file);
        auto rest = str::slice(file, begin, end);
        auto newline = str::index(rest, '\n' as u8);
        if (newline != -1) {
            end = begin + (newline as uint);
        }
    }
    ret str::slice(file, begin, end);
}

fn get_filemap(codemap cm, str filename) -> filemap {
    for (filemap fm in cm.files) {
        if (fm.name == filename) {
            ret fm;
        }
    }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail;// ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::cell::Cell;

use math::vector::Vector3;
use math::matrix::Matrix4;
use math::point::Point;

use ecs::{Entity, System, ComponentManager};
use scene::{Scene, ManagerHandle};

pub struct TransformManager {
    transforms: Vec<Vec<Transform>>,
    entities: Vec<Vec<Entity>>,

    /// A map between the entity owning the transform and the location of the transform.
    ///
    /// The first value of the mapped tuple is the row containing the transform, the
    /// second is the index of the transform within that row.
    indices: HashMap<Entity, (usize, usize)>,
}

impl TransformManager {
    pub fn new() -> TransformManager {
        let mut transform_manager = TransformManager {
            transforms: Vec::new(),
            entities: Vec::new(),
            indices: HashMap::new(),
        };

        transform_manager.transforms.push(Vec::new());
        transform_manager.entities.push(Vec::new());
        transform_manager
    }

    pub fn create(&mut self, entity: Entity) -> &mut Transform {
        let index = self.transforms[0].len();
        self.transforms[0].push(Transform::new());
        self.entities[0].push(entity);

        assert!(self.transforms[0].len() == self.entities[0].len());

        self.indices.insert(entity, (0, index));
        &mut self.transforms[0][index]
    }

    pub fn get(&self, entity: Entity) -> &Transform {
        let (row, index) = *self.indices.get(&entity).expect("Transform manager does not contain a transform for the given entity.");
        &self.transforms[row][index]
    }

    pub fn get_mut(&mut self, entity: Entity) -> &mut Transform {
        let (row, index) = *self.indices.get(&entity).expect("Transform manager does not contain a transform for the given entity.");
        &mut self.transforms[row][index]
    }

    pub fn set_child(&mut self, parent: Entity, child: Entity) {
        // Remove old transform component.
        let mut transform = self.remove(child);

        // Get the indices of the parent.
        let (parent_row, _) = *self.indices.get(&parent).unwrap();
        let child_row = parent_row + 1;

        // Ensure that there are enough rows for the child.
        while self.transforms.len() < child_row + 1 {
            self.transforms.push(Vec::new());
            self.entities.push(Vec::new());
        }
        // Add the child to the correct row.
        transform.parent = Some(parent);
        let child_index = self.transforms[child_row].len();
        self.transforms[child_row].push(transform);
        self.entities[child_row].push(child);

        // Update the index map.
        self.indices.insert(child, (child_row, child_index));
    }

    fn remove(&mut self, entity: Entity) -> Transform {
        // Retrieve indices of removed entity and the one it's swapped with.
        let (row, index) = *self.indices.get(&entity)
            .expect("Transform manager does not contain a transform for the given entity.");
        assert!(self.transforms[row].len() == self.entities[row].len());

        // Remove transform and the associate entity.
        let transform = self.transforms[row].swap_remove(index);
        let removed_entity = self.entities[row].swap_remove(index);
        assert!(removed_entity == entity);
        // Remove mapping for the removed component.
        self.indices.remove(&entity);

        // Update the index mapping for the moved entity, but only if the one we removed
        // wasn't the only one in the row.
        if index != self.entities[row].len() {
            let moved_entity = self.entities[row][index];
            self.indices.insert(moved_entity, (row, index));
        }

        transform
    }
}

impl ComponentManager for TransformManager {
}

#[derive(Debug)]
pub struct Transform {
    position:         Point,
    rotation:         Matrix4,
    scale:            Vector3,
    local_matrix:     Cell<Matrix4>,
    position_derived: Cell<Point>,
    rotation_derived: Cell<Matrix4>,
    matrix_derived:   Cell<Matrix4>,
    parent:           Option<Entity>,
    out_of_date:      Cell<bool>,
}

impl Transform {
    pub fn new() -> Transform {
        Transform {
            position:         Point::origin(),
            rotation:         Matrix4::identity(),
            scale:            Vector3::one(),
            local_matrix:     Cell::new(Matrix4::identity()),
            position_derived: Cell::new(Point::origin()),
            rotation_derived: Cell::new(Matrix4::identity()),
            matrix_derived:   Cell::new(Matrix4::identity()),
            parent:           None,
            out_of_date:      Cell::new(false),
        }
    }

    pub fn position(&self) -> Point {
        self.position
    }

    pub fn set_position(&mut self, new_position: Point) {
        self.position = new_position;
        self.out_of_date.set(true);
    }

    pub fn rotation(&self) -> Matrix4 {
        self.rotation
    }

    pub fn set_rotation(&mut self, new_rotation: Matrix4) {
        self.rotation = new_rotation;
        self.out_of_date.set(true);
    }

    pub fn scale(&self) -> Vector3 {
        self.scale
    }

    pub fn set_scale(&mut self, new_scale: Vector3) {
        self.scale = new_scale;
        self.out_of_date.set(true);
    }

    /// Retrieves the derived position of the transform.
    ///
    /// In debug builds this method asserts if the transform is out of date.
    pub fn position_derived(&self) -> Point {
        assert!(!self.out_of_date.get());

        self.position_derived.get()
    }

    /// Retrieves the derived rotation of the transform.
    ///
    /// In debug builds this method asserts if the transform is out of date.
    pub fn rotation_derived(&self) -> Matrix4 {
        assert!(!self.out_of_date.get());

        self.rotation_derived.get()
    }

    pub fn local_matrix(&self) -> Matrix4 {
        if self.out_of_date.get() {
            let local_matrix =
                Matrix4::from_point(self.position)
                * (self.rotation * Matrix4::scale(self.scale.x, self.scale.y, self.scale.z));
            self.local_matrix.set(local_matrix);
        }

        self.local_matrix.get()
    }

    pub fn derived_matrix(&self) -> Matrix4 {
        assert!(!self.out_of_date.get());

        self.matrix_derived.get()
    }

    pub fn normal_matrix(&self) -> Matrix4 {
        let inverse =
            Matrix4::scale(1.0 / self.scale.x, 1.0 / self.scale.y, 1.0 / self.scale.z)
          * (self.rotation.transpose()
          *  Matrix4::translation(-self.position.x, -self.position.y, -self.position.z));

        inverse.transpose()
    }

    pub fn rotation_matrix(&self) -> Matrix4 {
        self.rotation
    }

    pub fn look_at(&mut self, interest: Point, up: Vector3) {
        let forward = interest - self.position;
        let forward = forward.normalized();
        let up = up.normalized();

        let right = Vector3::cross(forward, up);
        let up = Vector3::cross(right, forward);

        let mut look_matrix = Matrix4::identity();

        look_matrix[(0, 0)] = right.x;
        look_matrix[(1, 0)] = right.y;
        look_matrix[(2, 0)] = right.z;

        look_matrix[(0, 1)] = up.x;
        look_matrix[(1, 1)] = up.y;
        look_matrix[(2, 1)] = up.z;

        look_matrix[(0, 2)] = -forward.x;
        look_matrix[(1, 2)] = -forward.y;
        look_matrix[(2, 2)] = -forward.z;

        self.rotation = look_matrix;
    }

    /// Updates the local and derived matrices for the transform.
    fn update(&self, parent_matrix: Matrix4, parent_rotation: Matrix4) {
        let local_matrix = self.local_matrix();

        let derived_matrix = parent_matrix * local_matrix;
        self.matrix_derived.set(derived_matrix);

        self.position_derived.set(derived_matrix.translation_part());
        self.rotation_derived.set(parent_rotation * self.rotation);

        self.out_of_date.set(false);
    }

    /// Used to update the matrices for a single transform.
    ///
    /// This is less efficient than letting the TransformUpdateSystem to update all
    /// transforms at once, so try to limit usage as much as possible.
    fn update_self(&self, transform_handle: ManagerHandle<TransformManager>) {
        // TODO: Actually update the derived transform.
    }
}

pub struct TransformUpdateSystem;

impl System for TransformUpdateSystem {
    fn update(&mut self, scene: &mut Scene, _: f32) {
        let mut transform_handle = scene.get_manager::<TransformManager>();
        let transform_manager = transform_handle.get();

        for row in transform_manager.transforms.iter() {
            for transform in row.iter() {
                // Retrieve the parent's transformation matrix, using the identity
                // matrix if the transform has no parent.
                let (parent_matrix, parent_rotation) = {
                    match transform.parent {
                        None => {
                            (Matrix4::identity(), Matrix4::identity())
                        },
                        Some(parent) => {
                            let (parent_row, parent_index) = *transform_manager.indices.get(&parent).unwrap();
                            let ref parent_transform = transform_manager.transforms[parent_row][parent_index];
                            let parent_matrix = parent_transform.derived_matrix();
                            let parent_rotation = parent_transform.rotation_derived();

                            (parent_matrix, parent_rotation)
                        }
                    }
                };

                transform.update(parent_matrix, parent_rotation);
            }
        }
    }
}
<commit_msg>Update Single Transform<commit_after>use std::collections::HashMap;
use std::cell::Cell;

use math::vector::Vector3;
use math::matrix::Matrix4;
use math::point::Point;

use ecs::{Entity, System, ComponentManager};
use scene::{Scene, ManagerHandle};

pub struct TransformManager {
    transforms: Vec<Vec<Transform>>,
    entities: Vec<Vec<Entity>>,

    /// A map between the entity owning the transform and the location of the transform.
    ///
    /// The first value of the mapped tuple is the row containing the transform, the
    /// second is the index of the transform within that row.
    indices: HashMap<Entity, (usize, usize)>,
}

impl TransformManager {
    pub fn new() -> TransformManager {
        let mut transform_manager = TransformManager {
            transforms: Vec::new(),
            entities: Vec::new(),
            indices: HashMap::new(),
        };

        transform_manager.transforms.push(Vec::new());
        transform_manager.entities.push(Vec::new());
        transform_manager
    }

    pub fn create(&mut self, entity: Entity) -> &mut Transform {
        let index = self.transforms[0].len();
        self.transforms[0].push(Transform::new());
        self.entities[0].push(entity);

        assert!(self.transforms[0].len() == self.entities[0].len());

        self.indices.insert(entity, (0, index));
        &mut self.transforms[0][index]
    }

    pub fn get(&self, entity: Entity) -> &Transform {
        let (row, index) = *self.indices.get(&entity).expect("Transform manager does not contain a transform for the given entity.");
        &self.transforms[row][index]
    }

    pub fn get_mut(&mut self, entity: Entity) -> &mut Transform {
        let (row, index) = *self.indices.get(&entity).expect("Transform manager does not contain a transform for the given entity.");
        &mut self.transforms[row][index]
    }

    pub fn set_child(&mut self, parent: Entity, child: Entity) {
        // Remove old transform component.
        let mut transform = self.remove(child);

        // Get the indices of the parent.
        let (parent_row, _) = *self.indices.get(&parent).unwrap();
        let child_row = parent_row + 1;

        // Ensure that there are enough rows for the child.
        while self.transforms.len() < child_row + 1 {
            self.transforms.push(Vec::new());
            self.entities.push(Vec::new());
        }
        // Add the child to the correct row.
        transform.parent = Some(parent);
        let child_index = self.transforms[child_row].len();
        self.transforms[child_row].push(transform);
        self.entities[child_row].push(child);

        // Update the index map.
        self.indices.insert(child, (child_row, child_index));
    }

    pub fn update_single(&self, entity: Entity) {
        let transform = self.get(entity);
        self.update_transform(transform);
    }

    pub fn update_transform(&self, transform: &Transform) {
        let (parent_matrix, parent_rotation) = match transform.parent {
            None => {
                (Matrix4::identity(), Matrix4::identity())
            },
            Some(parent) => {
                let parent_transform = self.get(parent);

                if parent_transform.out_of_date.get() {
                    self.update_transform(parent_transform);
                }

                let parent_matrix = parent_transform.derived_matrix();
                let parent_rotation = parent_transform.rotation_derived();

                (parent_matrix, parent_rotation)
            }
        };

        transform.update(parent_matrix, parent_rotation);
    }

    fn remove(&mut self, entity: Entity) -> Transform {
        // Retrieve indices of removed entity and the one it's swapped with.
        let (row, index) = *self.indices.get(&entity)
            .expect("Transform manager does not contain a transform for the given entity.");
        assert!(self.transforms[row].len() == self.entities[row].len());

        // Remove transform and the associate entity.
        let transform = self.transforms[row].swap_remove(index);
        let removed_entity = self.entities[row].swap_remove(index);
        assert!(removed_entity == entity);
        // Remove mapping for the removed component.
        self.indices.remove(&entity);

        // Update the index mapping for the moved entity, but only if the one we removed
        // wasn't the only one in the row.
        if index != self.entities[row].len() {
            let moved_entity = self.entities[row][index];
            self.indices.insert(moved_entity, (row, index));
        }

        transform
    }
}

impl ComponentManager for TransformManager {
}

#[derive(Debug)]
pub struct Transform {
    position:         Point,
    rotation:         Matrix4,
    scale:            Vector3,
    local_matrix:     Cell<Matrix4>,
    position_derived: Cell<Point>,
    rotation_derived: Cell<Matrix4>,
    matrix_derived:   Cell<Matrix4>,
    parent:           Option<Entity>,
    out_of_date:      Cell<bool>,
}

impl Transform {
    pub fn new() -> Transform {
        Transform {
            position:         Point::origin(),
            rotation:         Matrix4::identity(),
            scale:            Vector3::one(),
            local_matrix:     Cell::new(Matrix4::identity()),
            position_derived: Cell::new(Point::origin()),
            rotation_derived: Cell::new(Matrix4::identity()),
            matrix_derived:   Cell::new(Matrix4::identity()),
            parent:           None,
            out_of_date:      Cell::new(false),
        }
    }

    pub fn position(&self) -> Point {
        self.position
    }

    pub fn set_position(&mut self, new_position: Point) {
        self.position = new_position;
        self.out_of_date.set(true);
    }

    pub fn rotation(&self) -> Matrix4 {
        self.rotation
    }

    pub fn set_rotation(&mut self, new_rotation: Matrix4) {
        self.rotation = new_rotation;
        self.out_of_date.set(true);
    }

    pub fn scale(&self) -> Vector3 {
        self.scale
    }

    pub fn set_scale(&mut self, new_scale: Vector3) {
        self.scale = new_scale;
        self.out_of_date.set(true);
    }

    /// Retrieves the derived position of the transform.
    ///
    /// In debug builds this method asserts if the transform is out of date.
    pub fn position_derived(&self) -> Point {
        assert!(!self.out_of_date.get());

        self.position_derived.get()
    }

    /// Retrieves the derived rotation of the transform.
    ///
    /// In debug builds this method asserts if the transform is out of date.
    pub fn rotation_derived(&self) -> Matrix4 {
        assert!(!self.out_of_date.get());

        self.rotation_derived.get()
    }

    pub fn local_matrix(&self) -> Matrix4 {
        if self.out_of_date.get() {
            let local_matrix =
                Matrix4::from_point(self.position)
                * (self.rotation * Matrix4::scale(self.scale.x, self.scale.y, self.scale.z));
            self.local_matrix.set(local_matrix);
        }

        self.local_matrix.get()
    }

    pub fn derived_matrix(&self) -> Matrix4 {
        assert!(!self.out_of_date.get());

        self.matrix_derived.get()
    }

    pub fn normal_matrix(&self) -> Matrix4 {
        let inverse =
            Matrix4::scale(1.0 / self.scale.x, 1.0 / self.scale.y, 1.0 / self.scale.z)
          * (self.rotation.transpose()
          *  Matrix4::translation(-self.position.x, -self.position.y, -self.position.z));

        inverse.transpose()
    }

    pub fn rotation_matrix(&self) -> Matrix4 {
        self.rotation
    }

    pub fn look_at(&mut self, interest: Point, up: Vector3) {
        let forward = interest - self.position;
        let forward = forward.normalized();
        let up = up.normalized();

        let right = Vector3::cross(forward, up);
        let up = Vector3::cross(right, forward);

        let mut look_matrix = Matrix4::identity();

        look_matrix[(0, 0)] = right.x;
        look_matrix[(1, 0)] = right.y;
        look_matrix[(2, 0)] = right.z;

        look_matrix[(0, 1)] = up.x;
        look_matrix[(1, 1)] = up.y;
        look_matrix[(2, 1)] = up.z;

        look_matrix[(0, 2)] = -forward.x;
        look_matrix[(1, 2)] = -forward.y;
        look_matrix[(2, 2)] = -forward.z;

        self.rotation = look_matrix;
    }

    /// Updates the local and derived matrices for the transform.
    fn update(&self, parent_matrix: Matrix4, parent_rotation: Matrix4) {
        let local_matrix = self.local_matrix();

        let derived_matrix = parent_matrix * local_matrix;
        self.matrix_derived.set(derived_matrix);

        self.position_derived.set(derived_matrix.translation_part());
        self.rotation_derived.set(parent_rotation * self.rotation);

        self.out_of_date.set(false);
    }
}

pub struct TransformUpdateSystem;

impl System for TransformUpdateSystem {
    fn update(&mut self, scene: &mut Scene, _: f32) {
        let mut transform_handle = scene.get_manager::<TransformManager>();
        let transform_manager = transform_handle.get();

        for row in transform_manager.transforms.iter() {
            for transform in row.iter() {
                // Retrieve the parent's transformation matrix, using the identity
                // matrix if the transform has no parent.
                let (parent_matrix, parent_rotation) = match transform.parent {
                    None => {
                        (Matrix4::identity(), Matrix4::identity())
                    },
                    Some(parent) => {
                        let parent_transform = transform_manager.get(parent);

                        let parent_matrix = parent_transform.derived_matrix();
                        let parent_rotation = parent_transform.rotation_derived();

                        (parent_matrix, parent_rotation)
                    }
                };

                transform.update(parent_matrix, parent_rotation);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[repr(i32)]
pub enum SubpixelOrder {
  Default = 0,
  RGB = 1,
  BGR = 2,
  VRGB = 3,
  VBGR = 4
}

<commit_msg>Copied documentation from Cairo for subpixel_order<commit_after>//! Describe font subpixel order

///  The subpixel order specifies the order of color elements within each pixel on the display device when rendering with an antialiasing mode of CAIRO_ANTIALIAS_SUBPIXEL.
///
/// Since 1.0
#[repr(i32)]
pub enum SubpixelOrder {
  /// Use the default subpixel order for for the target device, since 1.0
  Default = 0,
  /// Subpixel elements are arranged horizontally with red at the left, since 1.0
  RGB = 1,
  /// Subpixel elements are arranged horizontally with blue at the left, since 1.0
  BGR = 2,
  /// Subpixel elements are arranged vertically with red at the top, since 1.0
  VRGB = 3,
  /// Subpixel elements are arranged vertically with blue at the top, since 1.0
  VBGR = 4
}

<|endoftext|>


<commit_before>use super::super::request::Request;
use super::super::response::Response;
use super::super::ingot::{Ingot, Continue, Unwind};
use super::super::alloy::Alloy;

use super::Furnace;

/// The default `Furnace` used by `Iron`.
/// `IronFurnace` just runs each request through all `Ingots` in its stack,
/// then, when it hits an `Ingot` which returns `Unwind`, it will
/// pass the request back up through all `Ingots` it has hit
/// so far.
pub struct IronFurnace<Rq, Rs> {
    /// The storage used by `IronFurnace` to hold all Ingots
    /// that have been smelted on to it.
    stack: Vec<Box<Ingot<Rq, Rs>: Send>>
}

impl<Rq: Request, Rs: Response> Clone for IronFurnace<Rq, Rs> {
    fn clone(&self) -> IronFurnace<Rq, Rs> { IronFurnace { stack: self.stack.clone() } }
}

/// `IronFurnace` is a `Furnace`
impl<Rq: Request, Rs: Response> Furnace<Rq, Rs> for IronFurnace<Rq, Rs> {
    fn forge(&mut self, request: &mut Rq, response: &mut Rs, opt_alloy: Option<&mut Alloy>) {
        // Create a placeholder alloy.
        let mut alloy = &mut Alloy::new();

        // See if we were passed one.
        match opt_alloy {
            // If so, forget about our placeholder.
            Some(a) => alloy = a,
            // Else just use our new Alloy.
            None => ()
        };

        // The exit_stack will hold all Ingots that are passed through
        // in the enter loop. This is so we know to take exactly the same
        // path through ingots in reverse order that we did on the way in.
        let mut exit_stack = vec![];

        'enter: for ingot in self.stack.mut_iter() {
            match ingot.enter(request, response, alloy) {
                Unwind   => break 'enter,
                // Mark the ingot for traversal on exit.
                Continue => exit_stack.push(ingot)
            }
        }

        // Reverse the stack so we go through in the reverse order.
        // i.e. LIFO.
        exit_stack.reverse();
        // Call each ingots exit handler.
        'exit: for ingot in exit_stack.mut_iter() {
            let _ = ingot.exit(request, response, alloy);
        }
    }
    /// Add an `Ingot` to the `Furnace`.
    fn smelt<I: Ingot<Rq, Rs>>(&mut self, ingot: I) {
        self.stack.push(box ingot);
    }

    /// Create a new instance of `IronFurnace`.
    fn new() -> IronFurnace<Rq, Rs> {
        IronFurnace {
            stack: vec![]
        }
    }
}
<commit_msg>(fix) Fixed an upstream change of : -> + for trait bounds.<commit_after>use super::super::request::Request;
use super::super::response::Response;
use super::super::ingot::{Ingot, Continue, Unwind};
use super::super::alloy::Alloy;

use super::Furnace;

/// The default `Furnace` used by `Iron`.
/// `IronFurnace` just runs each request through all `Ingots` in its stack,
/// then, when it hits an `Ingot` which returns `Unwind`, it will
/// pass the request back up through all `Ingots` it has hit
/// so far.
pub struct IronFurnace<Rq, Rs> {
    /// The storage used by `IronFurnace` to hold all Ingots
    /// that have been smelted on to it.
    stack: Vec<Box<Ingot<Rq, Rs> + Send>>
}

impl<Rq: Request, Rs: Response> Clone for IronFurnace<Rq, Rs> {
    fn clone(&self) -> IronFurnace<Rq, Rs> { IronFurnace { stack: self.stack.clone() } }
}

/// `IronFurnace` is a `Furnace`
impl<Rq: Request, Rs: Response> Furnace<Rq, Rs> for IronFurnace<Rq, Rs> {
    fn forge(&mut self, request: &mut Rq, response: &mut Rs, opt_alloy: Option<&mut Alloy>) {
        // Create a placeholder alloy.
        let mut alloy = &mut Alloy::new();

        // See if we were passed one.
        match opt_alloy {
            // If so, forget about our placeholder.
            Some(a) => alloy = a,
            // Else just use our new Alloy.
            None => ()
        };

        // The exit_stack will hold all Ingots that are passed through
        // in the enter loop. This is so we know to take exactly the same
        // path through ingots in reverse order that we did on the way in.
        let mut exit_stack = vec![];

        'enter: for ingot in self.stack.mut_iter() {
            match ingot.enter(request, response, alloy) {
                Unwind   => break 'enter,
                // Mark the ingot for traversal on exit.
                Continue => exit_stack.push(ingot)
            }
        }

        // Reverse the stack so we go through in the reverse order.
        // i.e. LIFO.
        exit_stack.reverse();
        // Call each ingots exit handler.
        'exit: for ingot in exit_stack.mut_iter() {
            let _ = ingot.exit(request, response, alloy);
        }
    }
    /// Add an `Ingot` to the `Furnace`.
    fn smelt<I: Ingot<Rq, Rs>>(&mut self, ingot: I) {
        self.stack.push(box ingot);
    }

    /// Create a new instance of `IronFurnace`.
    fn new() -> IronFurnace<Rq, Rs> {
        IronFurnace {
            stack: vec![]
        }
    }
}
<|endoftext|>


<commit_before>//!-----------------------------------------------------------------------------------------------
//!`src/arch/x86_64/memory/paging/mod.rs`
//!
//!Paging management
//!-----------------------------------------------------------------------------------------------

use memory::{frame_alloc, PAGE_SIZE};

const ENTRY_COUNT: usize = 512;

pub const P4: *mut Table = 0xffffffff_fffff000 as *mut _;

///An entry in a page table
pub struct PageEntry(u64);

bitflags! {
	flags EntryFlags: u64 {
		const PRESENT = 1 << 0,
		const WRITABLE = 1 << 1,
		const USER_ACCESSIBLE = 1 << 2,
		const WRITE_THROUGH_CACHING = 1 << 3,
		const DISABLE_CACHE = 1 << 4,
		const ACCESSED = 1 << 5,
		const DIRTY = 1 << 6,
		const HUGE = 1 << 7,
		const GLOBAL = 1 << 8,
		const NO_EXECUTE = 1 << 63,
	}
}

impl PageEntry {
	pub fn flags(&self) -> EntryFlags {
		EntryFlags::from_bits_truncate(self.0)
	}

	pub fn frame(&self) -> Option<frame_alloc::Frame> {
		if self.flags().contains(PRESENT) {
			Some(frame_alloc::Frame::address((self.0 & 0x000fffff_fffff000) as usize))
		} else {
			None
		}
	}

	pub fn set(&mut self, frame: frame_alloc::Frame, flags: EntryFlags) {
		let address = frame.number * PAGE_SIZE;
		assert!(address & 0xfff00000_00000fff == 0);
		self.0 = address as u64 | flags.bits();
	}

	pub fn used(&self) -> bool {
		self.0 != 0
	}

	pub fn clear(&mut self) {
		self.0 = 0;
	}
}

pub struct PageTable {
	entries: [PageEntry; ENTRY_COUNT],
}

impl PageTable {
	pub fn clear(&mut self) {
		for entry in self.entries.iter_mut() {
			entry.clear();
		}
	}
}
<commit_msg>Added next_table functions<commit_after>//!-----------------------------------------------------------------------------------------------
//!`src/arch/x86_64/memory/paging/mod.rs`
//!
//!Paging management
//!-----------------------------------------------------------------------------------------------

use memory::{frame_alloc, PAGE_SIZE};

const ENTRY_COUNT: usize = 512;

pub const P4: *mut PageTable = 0xffffffff_fffff000 as *mut _;

///An entry in a page table
#[derive(Clone, Copy)]
pub struct PageEntry(u64);

bitflags! {
	flags EntryFlags: u64 {
		const PRESENT = 1 << 0,
		const WRITABLE = 1 << 1,
		const USER_ACCESSIBLE = 1 << 2,
		const WRITE_THROUGH_CACHING = 1 << 3,
		const DISABLE_CACHE = 1 << 4,
		const ACCESSED = 1 << 5,
		const DIRTY = 1 << 6,
		const HUGE = 1 << 7,
		const GLOBAL = 1 << 8,
		const NO_EXECUTE = 1 << 63,
	}
}

impl PageEntry {
	pub fn flags(&self) -> EntryFlags {
		EntryFlags::from_bits_truncate(self.0)
	}

	pub fn frame(&self) -> Option<frame_alloc::Frame> {
		if self.flags().contains(PRESENT) {
			Some(frame_alloc::Frame::address((self.0 & 0x000fffff_fffff000) as usize))
		} else {
			None
		}
	}

	pub fn set(&mut self, frame: frame_alloc::Frame, flags: EntryFlags) {
		let address = frame.number * PAGE_SIZE;
		assert!(address & 0xfff00000_00000fff == 0);
		self.0 = address as u64 | flags.bits();
	}

	pub fn used(&self) -> bool {
		self.0 != 0
	}

	pub fn clear(&mut self) {
		self.0 = 0;
	}
}

pub struct PageTable {
	entries: [PageEntry; ENTRY_COUNT],
}

impl PageTable {
	pub fn clear(&mut self) {
		for entry in self.entries.iter_mut() {
			entry.clear();
		}
	}

	pub fn next_table_address(&self, index: usize) -> Option<usize>{
		let flags = self.entries[index].flags();
		if flags.contains(PRESENT) && !flags.contains(HUGE) {
			let address = self as *const _ as usize;
			Some((address << 9) | (index << 12))
		} else {
			None
		}
	}

	pub fn next_table(&self, index: usize) -> Option<&PageTable> {
		let address = self.next_table_address(index).unwrap();
		Some(unsafe {&*(address as *const _)})
	}

	pub fn next_table_mut(&self, index: usize) -> Option<&mut PageTable> {
		let address = self.next_table_address(index).unwrap();
		Some(unsafe {&mut *(address as *mut _)})
	}
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of `Nodes` from the
//!   `commands::parser::nodes` module. Construction of this tree
//!   is done with the help of the `commands::parser::builder` module.
//! * A `Parser` that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.

pub mod nodes;
pub mod completion;
pub mod builder;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'text` refers to the lifetime of the
/// tokens passed into the parser. This is the same as the lifetime
/// of the text used to create the tokens.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// The easiest and best way to get a root node is to use the
/// `commands::parser::builder` module.
///
/// ```
/// use commands::parser::builder::{Command, CommandTree};
/// use commands::parser::Parser;
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show").finalize());
/// tree.command(Command::new("set").finalize());
/// tree.command(Command::new("help").finalize());
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'text> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'text>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'text> Parser<'text> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'text> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show").finalize());
    /// tree.command(Command::new("set").finalize());
    /// tree.command(Command::new("help").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let acceptable = cn.successors()
                           .into_iter()
                           .filter(|n| n.acceptable(self))
                           .map(|n| n.clone())
                           .collect::<Vec<_>>();
        let matches = acceptable.clone()
                                .into_iter()
                                .filter(|n| n.matches(self, token))
                                .map(|n| n.clone())
                                .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let ref matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token, acceptable)),
            _ => Err(ParseError::AmbiguousMatch(token, matches)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone)]
pub enum ParseError<'text> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'text>, Vec<Rc<Node>>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'text>, Vec<Rc<Node>>),
}

impl<'text> fmt::Debug for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::InvalidState => write!(f, "InvalidState"),
            ParseError::NoMatches(token, _) => write!(f, "NoMatches({:?}, ...)", token),
            ParseError::AmbiguousMatch(token, _) => write!(f, "AmbiguousMatch({:?}, ...)", token),
        }
    }
}

impl<'text> Error for ParseError<'text> {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidState => "Invalid state.",
            ParseError::NoMatches(_, _) => "No match.",
            ParseError::AmbiguousMatch(_, _) => "Ambiguous match.",
        }
    }
}

impl<'text> fmt::Display for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    MissingParameter(String),
}

impl Error for VerifyError {
    fn description(&self) -> &str {
        match *self {
            VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
            VerifyError::MissingParameter(_) => "A required parameter is missing.",
        }
    }
}

impl fmt::Display for VerifyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

impl Matches for ParameterNode {
    /// Parameters can match any token by default.
    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        true
    }
}

impl Matches for FlagParameterNode {
    /// A flag parameter is just looking for the token matching
    /// its name.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'text>(&self, parser: &mut Parser<'text>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::nodes::*;
    use super::builder::{Command, CommandTree};
    use super::*;
    use tokenizer::tokenize;

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new(vec![]);
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_no_matches() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show").finalize());
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("h") {
            match parser.parse(tokens) {
                Err(ParseError::NoMatches(_, _)) => panic!(),
                _ => {}
            }
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_ambiguous_match() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show").finalize());
        tree.command(Command::new("set").finalize());
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("s") {
            match parser.parse(tokens) {
                Err(ParseError::AmbiguousMatch(_, _)) => panic!(),
                _ => {}
            }
        }
    }
}
<commit_msg>Remove ParseError::InvalidState.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The command parser consists of two important things:
//!
//! * A tree that represents the available commands and their arguments.
//!   This tree consists of instances of `Nodes` from the
//!   `commands::parser::nodes` module. Construction of this tree
//!   is done with the help of the `commands::parser::builder` module.
//! * A `Parser` that handles input and matches it against the command
//!   tree. This parser is intended to be short-lived and to just live
//!   for the duration of parsing and evaluating a single command line
//!   input.

pub mod nodes;
pub mod completion;
pub mod builder;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'text` refers to the lifetime of the
/// tokens passed into the parser. This is the same as the lifetime
/// of the text used to create the tokens.
///
/// When creating a `Parser`, you must give it an `Rc<RootNode>`.
/// The easiest and best way to get a root node is to use the
/// `commands::parser::builder` module.
///
/// ```
/// use commands::parser::builder::{Command, CommandTree};
/// use commands::parser::Parser;
///
/// let mut tree = CommandTree::new();
/// tree.command(Command::new("show").finalize());
/// tree.command(Command::new("set").finalize());
/// tree.command(Command::new("help").finalize());
///
/// let mut parser = Parser::new(tree.finalize());
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'text> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'text>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'text> Parser<'text> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'text> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::{Token, tokenize};
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show").finalize());
    /// tree.command(Command::new("set").finalize());
    /// tree.command(Command::new("help").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// // Completing now should have 3 options, 1 for each command.
    /// let comps = parser.complete(None);
    /// assert_eq!(comps.len(), 3);
    ///
    /// // But completing with a token for 'h' should have 1 option.
    /// if let Ok(tokens) = tokenize("h") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 1);
    ///   assert_eq!(comps[0].options.len(), 1);
    ///   assert_eq!(comps[0].options[0].option_string, "help");
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    ///
    /// // And completing for 's' should have 2 options.
    /// if let Ok(tokens) = tokenize("s") {
    ///   let comps = parser.complete(Some(tokens[0]));
    ///   assert_eq!(comps.len(), 2);
    /// } else {
    ///   panic!("Tokenize failed.");
    /// }
    /// ```
    pub fn complete(&self, token: Option<Token<'text>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::builder::{Command, CommandTree};
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut tree = CommandTree::new();
    /// tree.command(Command::new("show interface").finalize());
    ///
    /// let mut parser = Parser::new(tree.finalize());
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'text>>) -> Result<(), ParseError<'text>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'text>) -> Result<(), ParseError<'text>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let acceptable = cn.successors()
                           .into_iter()
                           .filter(|n| n.acceptable(self))
                           .map(|n| n.clone())
                           .collect::<Vec<_>>();
        let matches = acceptable.clone()
                                .into_iter()
                                .filter(|n| n.matches(self, token))
                                .map(|n| n.clone())
                                .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let ref matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token, acceptable)),
            _ => Err(ParseError::AmbiguousMatch(token, matches)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone)]
pub enum ParseError<'text> {
    /// There were no matches for the token.
    NoMatches(Token<'text>, Vec<Rc<Node>>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'text>, Vec<Rc<Node>>),
}

impl<'text> fmt::Debug for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::NoMatches(token, _) => write!(f, "NoMatches({:?}, ...)", token),
            ParseError::AmbiguousMatch(token, _) => write!(f, "AmbiguousMatch({:?}, ...)", token),
        }
    }
}

impl<'text> Error for ParseError<'text> {
    fn description(&self) -> &str {
        match *self {
            ParseError::NoMatches(_, _) => "No match.",
            ParseError::AmbiguousMatch(_, _) => "Ambiguous match.",
        }
    }
}

impl<'text> fmt::Display for ParseError<'text> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    MissingParameter(String),
}

impl Error for VerifyError {
    fn description(&self) -> &str {
        match *self {
            VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
            VerifyError::MissingParameter(_) => "A required parameter is missing.",
        }
    }
}

impl fmt::Display for VerifyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

impl Matches for ParameterNode {
    /// Parameters can match any token by default.
    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        true
    }
}

impl Matches for FlagParameterNode {
    /// A flag parameter is just looking for the token matching
    /// its name.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'text>(&self, parser: &mut Parser<'text>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::nodes::*;
    use super::builder::{Command, CommandTree};
    use super::*;
    use tokenizer::tokenize;

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new(vec![]);
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_no_matches() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show").finalize());
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("h") {
            match parser.parse(tokens) {
                Err(ParseError::NoMatches(_, _)) => panic!(),
                _ => {}
            }
        }
    }

    #[test]
    #[should_panic]
    fn parse_signals_ambiguous_match() {
        let mut tree = CommandTree::new();
        tree.command(Command::new("show").finalize());
        tree.command(Command::new("set").finalize());
        let mut parser = Parser::new(tree.finalize());
        if let Ok(tokens) = tokenize("s") {
            match parser.parse(tokens) {
                Err(ParseError::AmbiguousMatch(_, _)) => panic!(),
                _ => {}
            }
        }
    }
}
<|endoftext|>