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
122
123
124
125
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.

// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.

use crate::{
    statement::*,
    BoolAnd,
    Expression,
    Monoid,
    MonoidalReducerExpression,
    MonoidalReducerStatement,
    Node,
    Span,
};

pub struct ReturnPathReducer {
    pub errors: Vec<(Span, String)>,
}

impl ReturnPathReducer {
    fn record_error(&mut self, span: Option<&Span>, error: String) {
        self.errors.push((span.cloned().unwrap_or_default(), error));
    }

    pub fn new() -> ReturnPathReducer {
        ReturnPathReducer { errors: vec![] }
    }
}

impl Default for ReturnPathReducer {
    fn default() -> Self {
        Self::new()
    }
}

#[allow(unused_variables)]
impl<'a> MonoidalReducerExpression<'a, BoolAnd> for ReturnPathReducer {
    fn reduce_expression(&mut self, input: &'a Expression<'a>, value: BoolAnd) -> BoolAnd {
        BoolAnd(false)
    }
}

#[allow(unused_variables)]
impl<'a> MonoidalReducerStatement<'a, BoolAnd> for ReturnPathReducer {
    fn reduce_assign_access(&mut self, input: &AssignAccess, left: Option<BoolAnd>, right: Option<BoolAnd>) -> BoolAnd {
        BoolAnd(false)
    }

    fn reduce_assign(&mut self, input: &AssignStatement, accesses: Vec<BoolAnd>, value: BoolAnd) -> BoolAnd {
        BoolAnd(false)
    }

    fn reduce_block(&mut self, input: &BlockStatement, statements: Vec<BoolAnd>) -> BoolAnd {
        if statements.is_empty() {
            BoolAnd(false)
        } else if let Some(index) = statements[..statements.len() - 1].iter().map(|x| x.0).position(|x| x) {
            self.record_error(
                input.statements[index].get().span(),
                "dead code due to unconditional early return".to_string(),
            );
            BoolAnd(true)
        } else {
            BoolAnd(statements[statements.len() - 1].0)
        }
    }

    fn reduce_conditional_statement(
        &mut self,
        input: &ConditionalStatement,
        condition: BoolAnd,
        if_true: BoolAnd,
        if_false: Option<BoolAnd>,
    ) -> BoolAnd {
        if if_false.as_ref().map(|x| x.0).unwrap_or(false) != if_true.0 {
            self.record_error(
                input.span(),
                "cannot have asymmetrical return in if statement".to_string(),
            );
        }
        if_true.append(if_false.unwrap_or(BoolAnd(false)))
    }

    fn reduce_formatted_string(&mut self, input: &FormatString, parameters: Vec<BoolAnd>) -> BoolAnd {
        BoolAnd(false)
    }

    fn reduce_console(&mut self, input: &ConsoleStatement, argument: BoolAnd) -> BoolAnd {
        BoolAnd(false)
    }

    fn reduce_definition(&mut self, input: &DefinitionStatement, value: BoolAnd) -> BoolAnd {
        BoolAnd(false)
    }

    fn reduce_expression_statement(&mut self, input: &ExpressionStatement, expression: BoolAnd) -> BoolAnd {
        BoolAnd(false)
    }

    fn reduce_iteration(
        &mut self,
        input: &IterationStatement,
        start: BoolAnd,
        stop: BoolAnd,
        body: BoolAnd,
    ) -> BoolAnd {
        // loops are const defined ranges, so we could probably check if they run one and emit here
        BoolAnd(false)
    }

    fn reduce_return(&mut self, input: &ReturnStatement, value: BoolAnd) -> BoolAnd {
        BoolAnd(true)
    }
}