ergoscript_compiler/
compiler.rs1use super::binder::BinderError;
4use super::hir::HirLoweringError;
5use crate::ast;
6use crate::binder::Binder;
7use crate::hir;
8use crate::mir;
9use crate::parser::parse_error::ParseError;
10use crate::script_env::ScriptEnv;
11use crate::type_infer::assign_type;
12use crate::type_infer::TypeInferenceError;
13use std::convert::TryInto;
14
15extern crate derive_more;
16use derive_more::From;
17use ergotree_ir::ergo_tree::ErgoTree;
18use ergotree_ir::ergo_tree::ErgoTreeError;
19use ergotree_ir::type_check::TypeCheckError;
20use mir::lower::MirLoweringError;
21
22#[derive(Debug, PartialEq, Eq, From)]
24pub enum CompileError {
25 ParseError(Vec<ParseError>),
27 HirLoweringError(HirLoweringError),
29 BinderError(BinderError),
31 TypeInferenceError(TypeInferenceError),
33 MirLoweringError(MirLoweringError),
35 TypeCheckError(TypeCheckError),
37 ErgoTreeError(ErgoTreeError),
39}
40
41impl CompileError {
42 pub fn pretty_desc(&self, source: &str) -> String {
44 match self {
45 CompileError::ParseError(errors) => {
46 errors.iter().map(|e| e.pretty_desc(source)).collect()
47 }
48 CompileError::HirLoweringError(e) => e.pretty_desc(source),
49 CompileError::BinderError(e) => e.pretty_desc(source),
50 CompileError::TypeInferenceError(e) => e.pretty_desc(source),
51 CompileError::MirLoweringError(e) => e.pretty_desc(source),
52 CompileError::TypeCheckError(e) => e.pretty_desc(),
53 CompileError::ErgoTreeError(e) => format!("{:?}", e),
54 }
55 }
56}
57
58pub fn compile_expr(
60 source: &str,
61 env: ScriptEnv,
62) -> Result<ergotree_ir::mir::expr::Expr, CompileError> {
63 let hir = compile_hir(source)?;
64 let binder = Binder::new(env);
65 let bind = binder.bind(hir)?;
66 let typed = assign_type(bind)?;
67 let mir = mir::lower::lower(typed)?;
68 let res = ergotree_ir::type_check::type_check(mir)?;
69 Ok(res)
70}
71
72pub fn compile(source: &str, env: ScriptEnv) -> Result<ErgoTree, CompileError> {
74 let expr = compile_expr(source, env)?;
75 Ok(expr.try_into()?)
76}
77
78pub(crate) fn compile_hir(source: &str) -> Result<hir::Expr, CompileError> {
79 let parse = super::parser::parse(source);
80 if !parse.errors.is_empty() {
81 return Err(CompileError::ParseError(parse.errors));
82 }
83 let syntax = parse.syntax();
84 let root = ast::Root::cast(syntax).unwrap();
85 let hir = hir::lower(root)?;
86 Ok(hir)
87}
88
89#[cfg(test)]
90fn check(input: &str, expected_tree: expect_test::Expect) {
91 let res = compile_expr(input, ScriptEnv::new());
92
93 let expected_out = res
94 .map(|tree| tree.debug_tree())
95 .unwrap_or_else(|e| e.pretty_desc(input));
96 expected_tree.assert_eq(&expected_out);
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use expect_test::expect;
103
104 #[test]
105 fn test_height() {
106 check(
107 "HEIGHT",
108 expect![[r#"
109 GlobalVars(
110 Height,
111 )"#]],
112 );
113 }
114
115 #[test]
116 fn test_parser_error() {
117 check(
118 "HSB.HEIGHT",
119 expect![[r#"
120 error: expected ‘+’, ‘-’, ‘*’, ‘/’, ‘val’, number, number, identifier, ‘-’ or ‘(’, but found an unrecognized token
121 line: 1
122 HSB.HEIGHT
123 ^^"#]],
124 );
125 }
126}