Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduces compiler-wasm binary file size #3780

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ authors = ["Louis Pilfold <louis@lpil.uk>"]
edition = "2021"
license-file = "LICENCE"

[features]
disable-erlang = []
disable-hide-internal = []

[dependencies]
# Error message and warning formatting
codespan-reporting = "0"
Expand Down
31 changes: 15 additions & 16 deletions compiler-core/src/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ use ecow::EcoString;
use hexpm::version::Version;
use itertools::Itertools;
use name::{check_argument_names, check_name_case};
use std::{
collections::HashMap,
ops::Deref,
sync::{Arc, OnceLock},
};
use std::{collections::HashMap, ops::Deref, sync::Arc};
use vec1::Vec1;

use self::imports::Importer;
Expand Down Expand Up @@ -654,29 +650,32 @@ impl<'a, A> ModuleAnalyzer<'a, A> {
external_javascript: Option<&(EcoString, EcoString, SrcSpan)>,
location: SrcSpan,
) {
use regex::Regex;
fn is_module(s: &str) -> bool {
// ^[@a-zA-Z0-9\\./:_-]+$
!s.is_empty()
&& s.chars()
.all(|ch| "@\\./:_-".contains(ch) || ch.is_ascii_alphanumeric())
}

static MODULE: OnceLock<Regex> = OnceLock::new();
static FUNCTION: OnceLock<Regex> = OnceLock::new();
fn is_function(s: &str) -> bool {
// ^[a-zA-Z_][a-zA-Z0-9_]*$
let mut chars = s.chars();
chars.next().map(|ch| ch == '_' || ch.is_ascii_alphabetic()) == Some(true)
&& chars.all(|ch| ch == '_' || ch.is_ascii_alphanumeric())
}

let (module, function) = match external_javascript {
None => return,
Some((module, function, _location)) => (module, function),
};
if !MODULE
.get_or_init(|| Regex::new("^[@a-zA-Z0-9\\./:_-]+$").expect("regex"))
.is_match(module)
{
if !is_module(module) {
self.problems.error(Error::InvalidExternalJavascriptModule {
location,
module: module.clone(),
name: function_name.clone(),
});
}
if !FUNCTION
.get_or_init(|| Regex::new("^[a-zA-Z_][a-zA-Z0-9_]*$").expect("regex"))
.is_match(function)
{
if !is_function(function) {
self.problems
.error(Error::InvalidExternalJavascriptFunction {
location,
Expand Down
41 changes: 21 additions & 20 deletions compiler-core/src/analyse/name.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::sync::OnceLock;

use ecow::{eco_format, EcoString};
use regex::Regex;

use crate::{
ast::{ArgNames, SrcSpan},
Expand All @@ -11,30 +8,34 @@ use crate::{
use super::{Error, Named};
use heck::{ToSnakeCase, ToUpperCamelCase};

static VALID_NAME_PATTERN: OnceLock<Regex> = OnceLock::new();

fn valid_name(name: &EcoString) -> bool {
// Some of the internally generated variables (such as `_capture` and `_use0`)
// start with underscores, so we allow underscores here.
let valid_name_pattern = VALID_NAME_PATTERN
.get_or_init(|| Regex::new("^_?[a-z][a-z0-9_]*$").expect("Regex is correct"));
valid_name_pattern.is_match(name)
// ^_?[a-z][a-z0-9_]*$
let mut chars = name.chars();
if chars.clone().next() == Some('_') {
let _ = chars.next();
}
if chars.next().map(|ch| ch.is_ascii_lowercase()) != Some(true) {
return false;
}
chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_')
}

static VALID_DISCARD_PATTERN: OnceLock<Regex> = OnceLock::new();

fn valid_discard_name(name: &EcoString) -> bool {
let valid_discard_pattern = VALID_DISCARD_PATTERN
.get_or_init(|| Regex::new("^_[a-z0-9_]*$").expect("Regex is correct"));
valid_discard_pattern.is_match(name)
// ^_[a-z0-9_]*$
let mut chars = name.chars();
if chars.next() != Some('_') {
return false;
}
chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_')
}

static VALID_UPNAME_PATTERN: OnceLock<Regex> = OnceLock::new();

fn valid_upname(name: &EcoString) -> bool {
let valid_upname_pattern = VALID_UPNAME_PATTERN
.get_or_init(|| Regex::new("^[A-Z][A-Za-z0-9]*$").expect("Regex is correct"));
valid_upname_pattern.is_match(name)
// ^[A-Z][A-Za-z0-9]*$
let mut chars = name.chars();
if chars.next().map(|ch| ch.is_ascii_uppercase()) != Some(true) {
return false;
}
chars.all(|c| c.is_ascii_alphanumeric())
}

pub fn check_name_case(location: SrcSpan, name: &EcoString, kind: Named) -> Result<(), Error> {
Expand Down
11 changes: 2 additions & 9 deletions compiler-core/src/ast/typed.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::sync::OnceLock;

use super::*;
use crate::type_::{bool, HasType, Type, ValueConstructorVariant};

Expand Down Expand Up @@ -317,15 +315,10 @@ impl TypedExpr {
}

pub fn non_zero_compile_time_number(&self) -> bool {
use regex::Regex;
static NON_ZERO: OnceLock<Regex> = OnceLock::new();

matches!(
self,
Self::Int{ value, .. } | Self::Float { value, .. } if NON_ZERO.get_or_init(||


Regex::new(r"[1-9]").expect("NON_ZERO regex")).is_match(value)
Self::Int{ value, .. } | Self::Float { value, .. }
if matches!(value.chars().next(), Some('1'..='9'))
)
}

Expand Down
2 changes: 2 additions & 0 deletions compiler-core/src/build/package_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ where
prelude_location,
),
TargetCodegenConfiguration::Erlang { app_file } => {
#[cfg(feature = "disable-erlang")]
panic!("Erlang code generation is disabled.");
self.perform_erlang_codegen(modules, app_file.as_ref())
}
}
Expand Down
60 changes: 44 additions & 16 deletions compiler-core/src/build/package_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,23 +193,45 @@ where
}

pub fn is_gleam_path(&self, path: &Utf8Path, dir: &Utf8Path) -> bool {
use regex::Regex;
use std::cell::OnceCell;
const RE: OnceCell<Regex> = OnceCell::new();
let mut chars = path
.strip_prefix(dir)
.expect("is_gleam_path(): strip_prefix")
.as_str()
.chars();

RE.get_or_init(|| {
Regex::new(&format!(
"^({module}{slash})*{module}\\.gleam$",
module = "[a-z][_a-z0-9]*",
slash = "(/|\\\\)",
))
.expect("is_gleam_path() RE regex")
})
.is_match(
path.strip_prefix(dir)
.expect("is_gleam_path(): strip_prefix")
.as_str(),
)
// ^({module}{slash})*{module}\\.gleam$
loop {
// module = "[a-z][_a-z0-9]*"
// [a-z]
if chars.next().map(|ch| ch.is_ascii_lowercase()) != Some(true) {
return false;
}

// [_a-z0-9]*
while chars
.clone()
.next()
.map(|ch| ch == '_' || ch.is_ascii_lowercase() || ch.is_ascii_digit())
== Some(true)
{
let _ = chars.next();
}

if chars.as_str() == ".gleam" {
return true;
}

// slash = "(/|\\\\)"
if let Some(s) = chars
.as_str()
.strip_prefix("/")
.or(chars.as_str().strip_prefix("\\\\"))
{
chars = s.chars();
} else {
return false;
}
}
}

fn read_sources_and_caches(&self) -> Result<HashMap<EcoString, Input>> {
Expand Down Expand Up @@ -354,6 +376,12 @@ where
}
}

#[cfg(feature = "disable-erlang")]
fn ensure_gleam_module_does_not_overwrite_standard_erlang_module(input: &Input) -> Result<()> {
Ok(())
}

#[cfg(not(feature = "disable-erlang"))]
fn ensure_gleam_module_does_not_overwrite_standard_erlang_module(input: &Input) -> Result<()> {
// We only need to check uncached modules as it's not possible for these
// to have compiled successfully.
Expand Down
23 changes: 13 additions & 10 deletions compiler-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::version::COMPILER_VERSION;
use crate::{Error, Result};
use camino::{Utf8Path, Utf8PathBuf};
use ecow::EcoString;
use globset::{Glob, GlobSetBuilder};
use globset::Glob;
use hexpm::version::{self, Version};
use http::Uri;
use serde::Deserialize;
Expand Down Expand Up @@ -193,19 +193,20 @@ impl PackageConfig {
///
/// The developer can specify a list of glob patterns in the gleam.toml file
/// to determine modules that should not be shown in the package's documentation
#[cfg(not(feature = "disable-hide-internal"))]
pub fn is_internal_module(&self, module: &str) -> bool {
let package = &self.name;
match &self.internal_modules {
Some(globs) => {
let mut builder = GlobSetBuilder::new();
let mut builder = globset::GlobSetBuilder::new();
for glob in globs {
_ = builder.add(glob.clone());
}
builder.build()
}

// If no patterns were specified in the config then we use a default value
None => GlobSetBuilder::new()
None => globset::GlobSetBuilder::new()
.add(Glob::new(&format!("{package}/internal")).expect("internal module glob"))
.add(Glob::new(&format!("{package}/internal/*")).expect("internal module glob"))
.build(),
Expand All @@ -214,6 +215,11 @@ impl PackageConfig {
.is_match(module)
}

#[cfg(feature = "disable-hide-internal")]
pub fn is_internal_module(&self, _module: &str) -> bool {
false
}

// Checks to see if the gleam version specified in the config is compatible
// with the current compiler version
pub fn check_gleam_compatibility(&self) -> Result<(), Error> {
Expand Down Expand Up @@ -914,20 +920,17 @@ mod uri_serde_default_https {

mod package_name {
use ecow::EcoString;
use regex::Regex;
use serde::Deserializer;
use std::sync::OnceLock;

static PACKAGE_NAME_PATTERN: OnceLock<Regex> = OnceLock::new();

pub fn deserialize<'de, D>(deserializer: D) -> Result<EcoString, D::Error>
where
D: Deserializer<'de>,
{
let name: &str = serde::de::Deserialize::deserialize(deserializer)?;
if PACKAGE_NAME_PATTERN
.get_or_init(|| Regex::new("^[a-z][a-z0-9_]*$").expect("Package name regex"))
.is_match(name)
// ^[a-z][a-z0-9_]*$
let mut chars = name.chars();
if chars.next().map(|ch| ch.is_ascii_lowercase()) == Some(true)
&& chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_')
{
Ok(name.into())
} else {
Expand Down
3 changes: 3 additions & 0 deletions compiler-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ license-file = "LICENCE"
# This package compiles to wasm
crate-type = ["cdylib", "rlib"]

[features]
reduce-bin-size = ["gleam-core/disable-erlang", "gleam-core/disable-hide-internal"]

[dependencies]
gleam-core = { path = "../compiler-core" }
console_error_panic_hook = "0"
Expand Down