RESS Scanners

In the initial implementation of the ress scanner, it was more important to get something working correctly than to have something blazing fast. To that end, the original Scanner performs a significant amount of memory allocation, which slows everything down quite a bit. To improve upon that ress offers a section option the RefScanner, which is a bit unfortunately named as it doesn't actually use any references. The RefScanner provides almost the same information as the Scanner but it does so without making any copies from the original javascript string, it the has the option to request the String for any Item giving the control to the user. Here is an example of the two approaches.

Example JS

function things() {
    return [1,2,3,4];
}

Example Rust

use ress::{
    Scanner
};
fn main() {
    let js = include_str!("../example.js");
    let scanner = Scanner::new(js);
    for (i, item) in scanner.enumerate() {
        let item = item.unwrap();
        let prefix = if i < 10 {
            format!(" {}", i)
        } else {
            format!("{}", i)
        };
        println!("{} token: {:?}", prefix, item.token);
    }
}

#[cfg(test)]
mod test {
    use ress::*;
    #[test]
    fn chapter_1_1() {
        let js = "var i = 0;";
        let scanner = Scanner::new(js);
        for token in scanner {
            println!("{:#?}", token.unwrap());
        }
    }
    use ressa::Parser;
    #[test]
    fn ressa_ex1() {
        static JS: &str = "
function Thing(stuff) {
    this.stuff = stuff;
}
";
        let parser = Parser::new(JS).expect("Failed to create parser");
        for part in parser {
            let part = part.expect("Failed to parse part");
            println!("{:#?}", part);
        }
    }
}

Output


running 1 test
Decl(
    Func(
        Func {
            id: Some(
                Ident {
                    name: "Thing",
                },
            ),
            params: [
                Pat(
                    Ident(
                        Ident {
                            name: "stuff",
                        },
                    ),
                ),
            ],
            body: FuncBody(
                [
                    Stmt(
                        Expr(
                            Assign(
                                AssignExpr {
                                    operator: Equal,
                                    left: Expr(
                                        Member(
                                            MemberExpr {
                                                object: This,
                                                property: Ident(
                                                    Ident {
                                                        name: "stuff",
                                                    },
                                                ),
                                                computed: false,
                                            },
                                        ),
                                    ),
                                    right: Ident(
                                        Ident {
                                            name: "stuff",
                                        },
                                    ),
                                },
                            ),
                        ),
                    ),
                ],
            ),
            generator: false,
            is_async: false,
        },
    ),
)
test test::ressa_ex1 ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out

Let's look at token 7, the original token is Token::Numeric(Number(String::From("1"))) while the ref token is Token::Numeric(Number::Dec), both give similar information but the ref token doesn't allocate a new string for the text being represented, instead just informing the user that it is a decimal number. If you wanted to know what that string was, you could use the RefScanner::string_for method by passing it RefItem.span, this will return an Option<String> and so long as your span doesn't overflow the length of the js provided, it will have the value you are looking for.