Skip to content

Commit

Permalink
Disallow reserved words in project names
Browse files Browse the repository at this point in the history
Closes #773
  • Loading branch information
lpil committed Aug 31, 2020
1 parent bdaaa55 commit ed72943
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 13 deletions.
8 changes: 4 additions & 4 deletions src/erl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,15 @@ pub fn records(module: &TypedModule) -> Vec<(&str, String)> {

pub fn record_definition(name: &str, fields: &[&str]) -> String {
let name = &name.to_snake_case();
let escaped_name = if is_reserved_word(name) {
let escaped_name = if is_erlang_reserved_word(name) {
format!("'{}'", name)
} else {
format!("{}", name)
};
use std::fmt::Write;
let mut buffer = format!("-record({}, {{", escaped_name);
for field in fields.iter().intersperse(&", ") {
let escaped_field = if is_reserved_word(field) {
let escaped_field = if is_erlang_reserved_word(field) {
format!("'{}'", field)
} else {
format!("{}", field)
Expand Down Expand Up @@ -265,7 +265,7 @@ fn atom(value: String) -> Document {

match &*value {
// Escape because of keyword collision
value if is_reserved_word(value) => format!("'{}'", value).to_doc(),
value if is_erlang_reserved_word(value) => format!("'{}'", value).to_doc(),

// No need to escape
_ if RE.is_match(&value) => value.to_doc(),
Expand Down Expand Up @@ -1232,7 +1232,7 @@ fn external_fun(name: &str, module: &str, fun: &str, arity: usize) -> Document {
.nest(INDENT)
}

fn is_reserved_word(name: &str) -> bool {
pub fn is_erlang_reserved_word(name: &str) -> bool {
return match name {
"!" | "receive" | "bnot" | "div" | "rem" | "band" | "bor" | "bxor" | "bsl" | "bsr"
| "not" | "and" | "or" | "xor" | "orelse" | "andalso" | "when" | "end" | "fun" | "try"
Expand Down
35 changes: 35 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ pub enum Error {
command: String,
err: Option<std::io::ErrorKind>,
},

InvalidProjectName {
name: String,
reason: InvalidProjectNameReason,
},
}

#[derive(Debug, PartialEq)]
pub enum InvalidProjectNameReason {
Format,
ErlangReservedWord,
GleamReservedWord,
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -223,6 +235,29 @@ impl Error {
.expect("error pretty buffer write space before");

match self {
Error::InvalidProjectName { name, reason } => {
let diagnostic = ProjectErrorDiagnostic {
title: "Invalid project name".to_string(),
label: format!(
"We were not able to create your project as `{}` is
{}
Please try again with a different project name.",
name,
match reason {
InvalidProjectNameReason::ErlangReservedWord =>
"a reserved word in Erlang.",
InvalidProjectNameReason::GleamReservedWord =>
"a reserved word in Gleam.",
InvalidProjectNameReason::Format =>
"does not have the correct format. Project names must start
with a lowercase latter and may only contain lowercase letters
and underscores.",
}
),
};
write_project(buffer, diagnostic);
}
Error::ShellCommand { command, err: None } => {
let diagnostic = ProjectErrorDiagnostic {
title: "Shell command failure".to_string(),
Expand Down
35 changes: 26 additions & 9 deletions src/new.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::{Error, FileIOAction, FileKind, GleamExpect};
use crate::error::{Error, FileIOAction, FileKind, GleamExpect, InvalidProjectNameReason};
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::Write;
Expand All @@ -20,14 +20,7 @@ pub fn create(
path: Option<String>,
version: &'static str,
) -> Result<(), Error> {
if !regex::Regex::new("^[a-z_]+$")
.gleam_expect("new name regex could not be compiled")
.is_match(&name)
{
// TODO
println!("error: Project name may only contain lowercase letters and underscores");
std::process::exit(1);
}
let name = validate_name(name)?;

let description = description.unwrap_or_else(|| String::from("A Gleam program"));
let path = path.unwrap_or_else(|| name.clone());
Expand Down Expand Up @@ -510,3 +503,27 @@ fn app_rebar_config(name: &str) -> String {
name
))
}

fn validate_name(name: String) -> Result<String, Error> {
if crate::erl::is_erlang_reserved_word(name.as_str()) {
Err(Error::InvalidProjectName {
name,
reason: InvalidProjectNameReason::ErlangReservedWord,
})
} else if crate::parser::is_gleam_reserved_word(name.as_str()) {
Err(Error::InvalidProjectName {
name,
reason: InvalidProjectNameReason::GleamReservedWord,
})
} else if !regex::Regex::new("^[a-z_]+$")
.gleam_expect("new name regex could not be compiled")
.is_match(&name)
{
Err(Error::InvalidProjectName {
name,
reason: InvalidProjectNameReason::Format,
})
} else {
Ok(name)
}
}
7 changes: 7 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,10 @@ pub fn make_call(
}),
}
}

pub fn is_gleam_reserved_word(s: &str) -> bool {
match s {
"pub" | "fn" | "import" | "as" | "type" | "extern" | "case" | "try" | "assert" => true,
_ => false,
}
}

0 comments on commit ed72943

Please sign in to comment.