Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / analyse / name.rs
3.7 kB 118 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2024 The Gleam contributors 3 4use std::sync::OnceLock; 5 6use ecow::{EcoString, eco_format}; 7use regex::Regex; 8 9use crate::{ 10 ast::{ArgNames, SrcSpan}, 11 strings::{to_snake_case, to_upper_camel_case}, 12 type_::Problems, 13}; 14 15use super::{Error, Named}; 16 17static VALID_NAME_PATTERN: OnceLock<Regex> = OnceLock::new(); 18 19fn valid_name(name: &EcoString) -> bool { 20 // Some of the internally generated variables (such as `_capture` and `_use0`) 21 // start with underscores, so we allow underscores here. 22 let valid_name_pattern = VALID_NAME_PATTERN 23 .get_or_init(|| Regex::new("^_?[a-z][a-z0-9_]*$").expect("Regex is correct")); 24 valid_name_pattern.is_match(name) 25} 26 27static VALID_DISCARD_PATTERN: OnceLock<Regex> = OnceLock::new(); 28 29fn valid_discard_name(name: &EcoString) -> bool { 30 let valid_discard_pattern = VALID_DISCARD_PATTERN 31 .get_or_init(|| Regex::new("^_[a-z0-9_]*$").expect("Regex is correct")); 32 valid_discard_pattern.is_match(name) 33} 34 35static VALID_UPNAME_PATTERN: OnceLock<Regex> = OnceLock::new(); 36 37fn valid_upname(name: &EcoString) -> bool { 38 let valid_upname_pattern = VALID_UPNAME_PATTERN 39 .get_or_init(|| Regex::new("^[A-Z][A-Za-z0-9]*$").expect("Regex is correct")); 40 valid_upname_pattern.is_match(name) 41} 42 43pub fn check_name_case(location: SrcSpan, name: &EcoString, kind: Named) -> Result<(), Error> { 44 let valid = match kind { 45 Named::Type | Named::TypeAlias | Named::CustomTypeVariant => valid_upname(name), 46 Named::Variable 47 | Named::TypeVariable 48 | Named::Argument 49 | Named::Label 50 | Named::Constant 51 | Named::Function => valid_name(name), 52 Named::Discard => valid_discard_name(name), 53 }; 54 55 if valid { 56 return Ok(()); 57 } 58 59 Err(Error::BadName { 60 location, 61 kind, 62 name: name.clone(), 63 }) 64} 65 66pub fn correct_name_case(name: &EcoString, kind: Named) -> EcoString { 67 match kind { 68 Named::Type | Named::TypeAlias | Named::CustomTypeVariant => to_upper_camel_case(name), 69 Named::Variable 70 | Named::TypeVariable 71 | Named::Argument 72 | Named::Label 73 | Named::Constant 74 | Named::Function => to_snake_case(name), 75 Named::Discard => eco_format!("_{}", to_snake_case(name)), 76 } 77} 78 79pub fn check_argument_names(names: &ArgNames, problems: &mut Problems) { 80 match names { 81 ArgNames::Discard { name, location } => { 82 if let Err(error) = check_name_case(*location, name, Named::Discard) { 83 problems.error(error); 84 } 85 } 86 ArgNames::LabelledDiscard { 87 label, 88 label_location, 89 name, 90 name_location, 91 } => { 92 if let Err(error) = check_name_case(*label_location, label, Named::Label) { 93 problems.error(error); 94 } 95 if let Err(error) = check_name_case(*name_location, name, Named::Discard) { 96 problems.error(error); 97 } 98 } 99 ArgNames::Named { name, location } => { 100 if let Err(error) = check_name_case(*location, name, Named::Argument) { 101 problems.error(error); 102 } 103 } 104 ArgNames::NamedLabelled { 105 name, 106 name_location, 107 label, 108 label_location, 109 } => { 110 if let Err(error) = check_name_case(*label_location, label, Named::Label) { 111 problems.error(error); 112 } 113 if let Err(error) = check_name_case(*name_location, name, Named::Argument) { 114 problems.error(error); 115 } 116 } 117 } 118}