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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::high_level::problem::{CompileProblem, FilePosition};

use pest::error::ErrorVariant;
use pest::Parser;

#[derive(Parser)]
#[grammar = "ast/grammar.pest"]
struct NodespeakParser;

pub mod structure {
    pub use super::Rule;
    use pest::iterators::{Pair, Pairs};

    pub type Program<'a> = Pairs<'a, Rule>;
    pub type Node<'a> = Pair<'a, Rule>;

    pub fn rule_name(rule: &Rule) -> &'static str {
        match rule {
            Rule::WHITESPACE => "whitespace",
            Rule::COMMENT | Rule::block_comment | Rule::line_comment => "comment",
            Rule::EOI => "end of file",

            Rule::dec_int => "integer literal",
            Rule::hex_int => "hexadecimal literal",
            Rule::oct_int => "octal literal",
            Rule::legacy_oct_int => "c-style octal literal",
            Rule::bin_int => "binary literal",
            Rule::dec_digit => "digit",
            Rule::float => "float literal",
            Rule::int => "int literal",
            Rule::literal => "literal value",
            Rule::identifier => "identifier",

            Rule::vp_var => "variable",
            Rule::build_array => "array data",
            Rule::vpe_part_1 | Rule::vpe_part_2 | Rule::vpe_part_3 | Rule::vpe_part | Rule::vpe => {
                "value-producing expression"
            }
            Rule::build_array_type => "array type",
            Rule::optional_index_indicator => "?",
            Rule::vp_index => "index expression",
            Rule::get_property => "property access",
            Rule::negate => "negate",
            Rule::not => "not",
            Rule::operator => "binary operator",

            Rule::var_dec => "variable declaration",
            Rule::vc_identifier => "variable",
            Rule::vc_index => "index expression",
            Rule::vce => "value-consuming expression",

            Rule::macro_call_input_list => "input list for macro call",
            Rule::inline_output => "inline keyword",
            Rule::macro_call_output => "output for macro call",
            Rule::macro_call_output_list => "output list for macro call",
            Rule::macro_call => "single-output macro callession",

            Rule::macro_inputs => "input list for macro definition",
            Rule::macro_outputs => "output list for macro definition",
            Rule::single_macro_output => "single output for macro definition",
            Rule::macro_signature => "signature for macro definition",
            Rule::macro_definition => "macro definition",

            Rule::else_if_clause => "else if clause",
            Rule::else_clause => "else clause",
            Rule::if_statement => "if statement",
            Rule::no_unroll_keyword => "no_unroll (keyword)",
            Rule::for_loop_statement => "for loop",

            Rule::raw_string => "string segment",
            Rule::escape_sequence => "string escape sequence",
            Rule::string => "string literal",

            Rule::input_variable_statement => "input declaration",
            Rule::output_variable_statement => "output declaration",
            Rule::static_variable_statement => "static variable declaration",
            Rule::assign_statement => "assignment statement",
            Rule::macro_call_statement => "macro call as statement",
            Rule::var_dec_statement => "variable declaration as statement",
            Rule::return_statement => "return statement",
            Rule::assert_statement => "assert statement",
            Rule::include_statement => "include statement",
            Rule::statement => "statement",

            Rule::code_block => "code block",

            Rule::root => "program",
        }
    }
}

pub(self) mod problems {
    use crate::high_level::problem::{
        CompileProblem, FilePosition, ProblemDescriptor, ProblemType,
    };

    pub fn bad_syntax(pos: FilePosition, message: String) -> CompileProblem {
        CompileProblem::from_descriptors(vec![ProblemDescriptor::new(
            pos,
            ProblemType::Error,
            &format!("Bad Syntax\n{}", message),
        )])
    }
}

pub fn ingest(text: &str, file_id: usize) -> Result<structure::Program, CompileProblem> {
    NodespeakParser::parse(Rule::root, text).map_err(|parse_err| {
        problems::bad_syntax(
            FilePosition::from_input_location(parse_err.location, file_id),
            match parse_err.variant {
                ErrorVariant::ParsingError {
                    positives,
                    negatives,
                } => format!(
                    "Expected {}... but found {}.",
                    {
                        positives
                            .iter()
                            .map(|rule| structure::rule_name(rule))
                            .collect::<Vec<&str>>()
                            .join(", ")
                    },
                    {
                        if negatives.len() == 0 {
                            "unknown syntax".to_owned()
                        } else {
                            negatives
                                .iter()
                                .map(|rule| structure::rule_name(rule))
                                .collect::<Vec<&str>>()
                                .join(", ")
                        }
                    }
                ),
                ErrorVariant::CustomError { message: _message } => {
                    unreachable!("Only parsing errors are encountered in the parser.")
                }
            },
        )
    })
}