1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
pub extern crate graviton_ast as ast;
pub extern crate graviton_backend as backend;
pub extern crate graviton_frontend as frontend;

pub extern crate colored;
use colored::*;

pub mod errors;

#[derive(Debug, Clone)]
pub enum GravitonError {
    ParseError(Vec<frontend::parser::ParseError>),
    SemanticError(Vec<ast::semantic::SemanticError>),
    NativeError(Vec<backend::native::NativeError>),
}

impl<'a> GravitonError {
    pub fn report(&self, source: Option<&'a str>) {
        match self {
            GravitonError::ParseError(perrors) => {
                for perror in perrors {
                    errors::report_parser_error(perror, source)
                }
            }
            GravitonError::SemanticError(serrors) => {
                for serror in serrors {
                    errors::report_semantic_error(serror, source)
                }
            }
            GravitonError::NativeError(nerrors) => {
                for nerror in nerrors {
                    errors::report_native_error(nerror, source)
                }
            }
        }
    }
}

pub fn parse_source<'a>(
    source: &'a str,
    filename: Option<&'a str>,
) -> Result<ast::AstNode, GravitonError> {
    match frontend::parser::Parser::parse(source, filename) {
        Ok(mut ast) => {
            match analyze_ast(
                if let Some(f) = filename {
                    Some(String::from(f))
                } else {
                    None
                },
                &mut ast,
            ) {
                Ok(_) => Ok(ast),
                Err(e) => Err(e),
            }
        }
        Err(e) => Err(GravitonError::ParseError(e)),
    }
}

pub fn analyze_ast(name: Option<String>, ast: &mut ast::AstNode) -> Result<(), GravitonError> {
    match ast::semantic::SemanticAnalyzer::analyze(
        ast,
        name,
        Some(backend::native::stdlib::get_stdlib_signatures()),
    ) {
        Ok(_) => Ok(()),
        Err(e) => Err(GravitonError::SemanticError(e)),
    }
}

pub fn compile_ast(
    name: String,
    ast: &ast::AstNode,
    debug_level: i32,
) -> Result<backend::native::NativeObject, GravitonError> {
    match backend::native::Native::compile(name, ast, debug_level) {
        Ok(obj) => Ok(obj),
        Err(e) => Err(GravitonError::NativeError(e)),
    }
}

pub fn compile_source<'a>(
    source: &'a str,
    filename: Option<&'a str>,
    debug_level: i32,
) -> Result<backend::native::NativeObject, GravitonError> {
    let ast = parse_source(source, filename)?;
    if debug_level >= 2 {
        println!("{}: {:#?}", "Typed AST".cyan(), ast);
    }
    compile_ast(
        if let Some(f) = filename {
            String::from(f)
        } else {
            String::from("graviton")
        },
        &ast,
        debug_level,
    )
}