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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use super::binder::BinderError;
use super::hir::HirLoweringError;
use crate::ast;
use crate::binder::Binder;
use crate::hir;
use crate::mir;
use crate::parser::parse_error::ParseError;
use crate::script_env::ScriptEnv;
use crate::type_infer::assign_type;
use crate::type_infer::TypeInferenceError;
extern crate derive_more;
use derive_more::From;
use ergotree_ir::ergo_tree::ErgoTree;
use ergotree_ir::type_check::TypeCheckError;
use mir::lower::MirLoweringError;
#[derive(Debug, PartialEq, From)]
pub enum CompileError {
ParseError(Vec<ParseError>),
HirLoweringError(HirLoweringError),
BinderError(BinderError),
TypeInferenceError(TypeInferenceError),
MirLoweringError(MirLoweringError),
TypeCheckError(TypeCheckError),
}
impl CompileError {
pub fn pretty_desc(&self, source: &str) -> String {
match self {
CompileError::ParseError(errors) => {
errors.iter().map(|e| e.pretty_desc(source)).collect()
}
CompileError::HirLoweringError(e) => e.pretty_desc(source),
CompileError::BinderError(e) => e.pretty_desc(source),
CompileError::TypeInferenceError(e) => e.pretty_desc(source),
CompileError::MirLoweringError(e) => e.pretty_desc(source),
CompileError::TypeCheckError(e) => e.pretty_desc(),
}
}
}
pub fn compile_expr(
source: &str,
env: ScriptEnv,
) -> Result<ergotree_ir::mir::expr::Expr, CompileError> {
let hir = compile_hir(source)?;
let binder = Binder::new(env);
let bind = binder.bind(hir)?;
let typed = assign_type(bind)?;
let mir = mir::lower::lower(typed)?;
let res = ergotree_ir::type_check::type_check(mir)?;
Ok(res)
}
pub fn compile(source: &str, env: ScriptEnv) -> Result<ErgoTree, CompileError> {
let expr = compile_expr(source, env)?;
Ok(expr.into())
}
pub(crate) fn compile_hir(source: &str) -> Result<hir::Expr, CompileError> {
let parse = super::parser::parse(&source);
if !parse.errors.is_empty() {
return Err(CompileError::ParseError(parse.errors));
}
let syntax = parse.syntax();
let root = ast::Root::cast(syntax).unwrap();
let hir = hir::lower(root)?;
Ok(hir)
}
#[cfg(test)]
fn check(input: &str, expected_tree: expect_test::Expect) {
let res = compile_expr(input, ScriptEnv::new());
let expected_out = res
.map(|tree| tree.debug_tree())
.unwrap_or_else(|e| e.pretty_desc(input));
expected_tree.assert_eq(&expected_out);
}
#[cfg(test)]
mod tests {
use super::*;
use expect_test::expect;
#[test]
fn test_height() {
check(
"HEIGHT",
expect![[r#"
GlobalVars(
Height,
)"#]],
);
}
#[test]
fn test_parser_error() {
check(
"HSB.HEIGHT",
expect![[r#"
error: expected ‘+’, ‘-’, ‘*’, ‘/’, ‘val’, number, number, identifier, ‘-’ or ‘(’, but found an unrecognized token
line: 1
HSB.HEIGHT
^^"#]],
);
}
}