1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#[macro_use]
extern crate log;

extern crate regex;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
use regex::Regex;
use std::io::Write;

mod ast;
mod context;
mod error;
mod evaluator;
mod sass;
mod optimizer;
mod parser;
mod token;
mod tokenizer;

use context::Context;
use error::Result;
use tokenizer::Tokenizer;
use parser::Parser;
use sass::output_style::SassOutputStyle;

fn resolve_imports(inputpath: &PathBuf) -> Result<String> {
    let mut file = try!(File::open(&inputpath));
    let mut sass = String::new();

    try!(file.read_to_string(&mut sass));

    let mut imports_resolved = String::new();
    for line in sass.split("\n") {
        let re = Regex::new("@import \"([^\"]*)\";").unwrap();

        match re.captures(line) {
            Some(caps) => {
                let imported = try!(resolve_imports(&inputpath.with_file_name(caps.at(1).unwrap())));
                imports_resolved.push_str(&imported);
            },
            None => {
                imports_resolved.push_str(line);
            },
        }
        imports_resolved.push_str("\n");
    }
    Ok(imports_resolved)
}

pub fn compile<W: Write>(input_filename: &str, output: &mut W, style: &str) -> Result<()> {
    let input_path = PathBuf::from(input_filename);
    let imports_resolved = try!(resolve_imports(&input_path));

    let style: SassOutputStyle = try!(style.parse());

    match style {
        SassOutputStyle::Tokens => {
            let mut tokenizer = Tokenizer::new(&imports_resolved);
            while let Some(token) = tokenizer.next() {
                try!(write!(output, "{:?}\n", token))
            }
        },
        SassOutputStyle::AST => {
            let mut parser = Parser::new(&imports_resolved);
            while let Some(ast_node) = parser.next() {
                try!(write!(output, "{:?}\n", ast_node));
            }
        },
        other_style => {
            let mut parser  = Parser::new(&imports_resolved);
            let mut context = Context::new();
            while let Some(Ok(ast_node)) = parser.next() {
                let evaluated = evaluator::evaluate(ast_node, &mut context);
                if let Some(root) = evaluated {
                    let optimized = optimizer::optimize(root);
                    for r in optimized {
                        try!(r.stream(output, other_style));
                    }
                }
            }
        },
    }

    Ok(())
}