Skip to content

Commit

Permalink
Backport Gleam 1.2.0 fixes to Nix (#2)
Browse files Browse the repository at this point in the history
* fix module select in guard clauses

adapt gleam-lang/gleam#3045 to the Nix target

* use common string escape chars function

Adapt gleam-lang/gleam#3139 to the Nix target

* add 'module_access_aliased' test to nix
  • Loading branch information
PgBiel authored Jun 8, 2024
1 parent 6e84c34 commit f4c0a8d
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 61 deletions.
64 changes: 7 additions & 57 deletions compiler-core/src/nix/pattern.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::analyse::Inferred;
use ecow::EcoString;
use itertools::Itertools;
use std::sync::OnceLock;

use crate::analyse::Inferred;
use crate::ast::{AssignName, ClauseGuard, Pattern, TypedClauseGuard, TypedExpr, TypedPattern};
use crate::docvec;
use crate::nix::{
expression, maybe_escape_identifier_doc, module_var_name_doc, syntax, Error, Output,
UsageTracker,
};
use crate::pretty::{nil, Document, Documentable};
use crate::strings::convert_string_escape_chars;
use crate::type_::{FieldMap, PatternConstructor};

pub static ASSIGNMENT_VAR: &str = "_pat'";
Expand Down Expand Up @@ -347,9 +348,11 @@ impl<'module_ctx, 'expression_gen, 'a> Generator<'module_ctx, 'expression_gen, '
}

ClauseGuard::ModuleSelect {
module_name, label, ..
module_alias,
label,
..
} => docvec!(
module_var_name_doc(module_name),
module_var_name_doc(module_alias),
".",
maybe_escape_identifier_doc(label)
),
Expand Down Expand Up @@ -1058,58 +1061,5 @@ pub(crate) fn assign_subjects<'a>(

/// Calculates the length of str as UTF-8 bytes without escape characters.
fn no_escape_bytes_len(str: &EcoString) -> usize {
let mut filtered_str = String::new();
let mut str_iter = str.chars().peekable();
loop {
match str_iter.next() {
Some('\\') => match str_iter.next() {
// Check for Unicode escape sequence, e.g. \u{00012FF}
Some('u') => {
if str_iter.peek() != Some(&'{') {
// Invalid Unicode escape sequence
filtered_str.push('u');
continue;
}

// Consume the left brace after peeking
let _ = str_iter.next();

let codepoint_str = str_iter
.peeking_take_while(char::is_ascii_hexdigit)
.collect::<String>();

if codepoint_str.is_empty() || str_iter.peek() != Some(&'}') {
// Invalid Unicode escape sequence
filtered_str.push_str("u{");
filtered_str.push_str(&codepoint_str);
continue;
}

let codepoint = u32::from_str_radix(&codepoint_str, 16)
.ok()
.and_then(char::from_u32);

if let Some(codepoint) = codepoint {
// Consume the right brace after peeking
let _ = str_iter.next();

// Consider this codepoint's length instead of
// that of the Unicode escape sequence itself
filtered_str.push(codepoint);
} else {
// Invalid Unicode escape sequence
// (codepoint value not in base 16 or too large)
filtered_str.push_str("u{");
filtered_str.push_str(&codepoint_str);
}
}
Some(c) => filtered_str.push(c),
None => break,
},
Some(c) => filtered_str.push(c),
None => break,
}
}

filtered_str.len()
convert_string_escape_chars(str).len()
}
60 changes: 56 additions & 4 deletions compiler-core/src/nix/tests/case_clause_guards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ fn alternative_patterns_assignment() {
[x] | [_, x] -> x
_ -> 1
}
}
}
"#,
);
}
Expand All @@ -215,7 +215,7 @@ fn alternative_patterns_guard() {
[x] | [_, x] if x == 1 -> x
_ -> 0
}
}
}
"#,
);
}
Expand All @@ -227,11 +227,11 @@ fn field_access() {
pub type Person {
Person(username: String, name: String, age: Int)
}
pub fn main() {
let given_name = "jack"
let raiden = Person("raiden", "jack", 31)
case given_name {
name if name == raiden.name -> "It's jack"
_ -> "It's not jack"
Expand Down Expand Up @@ -380,6 +380,58 @@ fn module_access() {
);
}

#[test]
fn module_access_submodule() {
assert_nix!(
(
"package",
"hero/submodule",
r#"
pub type Hero {
Hero(name: String)
}
pub const ironman = Hero("Tony Stark")
"#
),
r#"
import hero/submodule
pub fn main() {
let name = "Tony Stark"
case name {
n if n == submodule.ironman.name -> True
_ -> False
}
}
"#
);
}

#[test]
fn module_access_aliased() {
assert_nix!(
(
"package",
"hero/submodule",
r#"
pub type Hero {
Hero(name: String)
}
pub const ironman = Hero("Tony Stark")
"#
),
r#"
import hero/submodule as myhero
pub fn main() {
let name = "Tony Stark"
case name {
n if n == myhero.ironman.name -> True
_ -> False
}
}
"#
);
}

#[test]
fn module_nested_access() {
assert_nix!(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
source: compiler-core/src/nix/tests/case_clause_guards.rs
expression: "\n import hero/submodule as myhero\n pub fn main() {\n let name = \"Tony Stark\"\n case name {\n n if n == myhero.ironman.name -> True\n _ -> False\n }\n }\n "
---
let
myhero' = builtins.import ./../../package/hero/submodule.nix;

main =
{ }:
let
name = "Tony Stark";
in
if name == myhero'.ironman.name then let n = name; in true
else false;
in
{ inherit main; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
source: compiler-core/src/nix/tests/case_clause_guards.rs
expression: "\n import hero/submodule\n pub fn main() {\n let name = \"Tony Stark\"\n case name {\n n if n == submodule.ironman.name -> True\n _ -> False\n }\n }\n "
---
let
submodule' = builtins.import ./../../package/hero/submodule.nix;

main =
{ }:
let
name = "Tony Stark";
in
if name == submodule'.ironman.name then let n = name; in true
else false;
in
{ inherit main; }

0 comments on commit f4c0a8d

Please sign in to comment.