heraclitus_compiler/compiling/parser/
preset.rs

1use crate::compiling::failing::position_info::PositionInfo;
2use crate::compiling::failing::failure::Failure;
3use super::Metadata;
4
5/// Match variable name
6/// 
7/// Matches one token with a word that would be considered as a variable name.
8/// If desired - one can extend this implementation with other chars.
9pub fn variable(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
10    match meta.get_current_token() {
11        Some(token) => {
12            // This boolean stores false if we are past
13            // the first letter otherwise it's true
14            let mut is_later: bool = false;
15            for letter in token.word.chars() {
16                // Check if rest of the letters are alphanumeric
17                if is_later {
18                    if !(letter.is_alphanumeric() || extend.contains(&letter)) {
19                        return Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token))))
20                    }
21                }
22                // Check if first letter is alphabetic
23                else {
24                    if !(letter.is_alphabetic() || extend.contains(&letter)) {
25                        return Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token))))
26                    }
27                    is_later = true;
28                }
29            }
30            meta.increment_index();
31            Ok(token.word)
32        }
33        None => Err(Failure::Quiet(PositionInfo::at_eof(meta)))
34    }
35}
36
37/// Match alphabetic word
38///
39/// Matches one token with a word that consists of letters only.
40/// If desired - one can extend this implementation with other chars.
41pub fn alphabetic(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
42    match meta.get_current_token() {
43        Some(token) => {
44            if token.word.chars().all(|letter| letter.is_alphabetic() || extend.contains(&letter)) {
45                meta.increment_index();
46                Ok(token.word)
47            } else { Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token)))) }
48        }
49        None => Err(Failure::Quiet(PositionInfo::at_eof(meta)))
50    }
51}
52
53/// Match alphanumeric word
54/// 
55/// Matches one token with a word that consists of letters or numbers only.
56/// If desired - one can extend this implementation with other chars.
57pub fn alphanumeric(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
58    match meta.get_current_token() {
59        Some(token) => {
60            if token.word.chars().all(|letter| letter.is_alphanumeric() || extend.contains(&letter)) {
61                meta.increment_index();
62                Ok(token.word)
63            } else { Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token)))) }
64        }
65        None => Err(Failure::Quiet(PositionInfo::at_eof(meta)))
66    }
67}
68
69/// Match numeric word
70/// 
71/// Matches a token of which word is a string of digits.
72/// If desired - one can extend this implementation with other chars.
73pub fn numeric(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
74    match meta.get_current_token() {
75        Some(token) => {
76            if token.word.chars().all(|letter| letter.is_numeric() || extend.contains(&letter)) {
77                meta.increment_index();
78                Ok(token.word)
79            } else { Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token)))) }
80        }
81        None => Err(Failure::Quiet(PositionInfo::at_eof(meta)))
82    }
83}
84
85/// Match an integer
86/// 
87/// Matches a positive or negetive integer.
88/// If desired - one can extend this implementation with other chars.
89pub fn integer(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
90    match meta.get_current_token() {
91        Some(token) => {
92            let mut word = token.word.clone();
93            // If it's a negative number - consume
94            if word.starts_with('-') {
95                word = word[1..].chars().collect();
96            }
97            // For each further letter match a digit
98            for letter in word.chars() {
99                if !(letter.is_numeric() || extend.contains(&letter)) {
100                    return Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token))))
101                }
102            }
103            meta.increment_index();
104            Ok(token.word)
105        }
106        None => Err(Failure::Quiet(PositionInfo::at_eof(meta)))
107    }
108}
109
110/// Match a float
111/// 
112/// Matches a number that contains a floating point (has a dot in decimal notation)
113/// If desired - one can extend this implementation with other chars.
114pub fn float(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
115    match meta.get_current_token() {
116        Some(token) => {
117            let mut word = token.word.clone();
118            // If it's a negative number - consume
119            if word.starts_with('-') {
120                word = word[1..].chars().collect();
121            }
122            // Determine if 'dot' was found
123            let mut is_frac = false;
124            for letter in word.chars() {
125                if letter == '.' {
126                    // Set fraction if dot - exit match otherwise
127                    is_frac = if is_frac { return Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token)))) } else { true };
128                    continue
129                }
130                if !(letter.is_numeric() || extend.contains(&letter)) {
131                    return Err(Failure::Quiet(PositionInfo::from_token(meta, Some(token))))
132                }
133            }
134            meta.increment_index();
135            Ok(token.word)
136        }
137        None => Err(Failure::Quiet(PositionInfo::at_eof(meta)))
138    }
139}
140
141/// Match a number
142/// 
143/// Matches a number that is an integer or float
144/// If desired - one can extend this implementation with other chars.
145pub fn number(meta: &mut impl Metadata, extend: Vec<char>) -> Result<String, Failure> {
146    if let Ok(integer) = integer(meta, extend.clone()) {
147        return Ok(integer);
148    }
149    float(meta, extend)
150}