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

Add echo keyword #3676

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
60b2db1
Define untyped echo
giacomocavalieri Oct 7, 2024
2cfa09a
echo parsing
giacomocavalieri Oct 7, 2024
c0b1786
echo format tests
giacomocavalieri Oct 7, 2024
fa03a8b
tests to make sure echo is followed by an expression
giacomocavalieri Oct 8, 2024
ff4c2a4
handle echo not followed by an expression to print
giacomocavalieri Oct 8, 2024
5b3dce1
add echo typed node
giacomocavalieri Oct 8, 2024
19306e6
make sure one cannot publish echo
giacomocavalieri Oct 10, 2024
e3b730b
refactor pipe assignments to simplify echo code generation
giacomocavalieri Oct 10, 2024
aba255a
first attempt at erlang code generation
giacomocavalieri Oct 10, 2024
b0ae1cc
first attempt at js code generation
giacomocavalieri Oct 10, 2024
7b20f67
some more tests
giacomocavalieri Oct 10, 2024
fb9520b
debug printing on js
giacomocavalieri Oct 11, 2024
5e28d72
change parsing rules for echo in pipelines
giacomocavalieri Oct 11, 2024
7a5b455
erlang and js
giacomocavalieri Oct 21, 2024
2703431
various fixes
giacomocavalieri Oct 21, 2024
62e603e
snaps
giacomocavalieri Oct 21, 2024
cecc5e9
warn for unreachable echo
giacomocavalieri Oct 21, 2024
e6eace9
clippy!
giacomocavalieri Oct 21, 2024
0b75762
improve js echo snapshots
giacomocavalieri Oct 21, 2024
a2d5cfb
improve erl snapshots
giacomocavalieri Oct 21, 2024
9f3094c
erlang snapshots again
giacomocavalieri Oct 21, 2024
53f89fd
snapshots
giacomocavalieri Oct 21, 2024
3e02e29
snapshots one last time
giacomocavalieri Oct 21, 2024
4f7a208
lower precedence of echo
giacomocavalieri Oct 22, 2024
6329555
Add documentation for echo implementation
giacomocavalieri Oct 22, 2024
4f939be
Add documentation for `TypedExpressionAssignment` node
giacomocavalieri Oct 22, 2024
2b0371c
Address some review comments
giacomocavalieri Oct 22, 2024
3830be6
remove old snapshot
giacomocavalieri Oct 25, 2024
3db3661
replace echo code in all tests
giacomocavalieri Oct 25, 2024
6bee12a
avoid clases with user defined types
giacomocavalieri Oct 25, 2024
c1437ae
properly handle Dicts
giacomocavalieri Oct 25, 2024
12c41a4
bools bad!!
giacomocavalieri Oct 25, 2024
b6d61f3
Update snapshots with new format
giacomocavalieri Oct 26, 2024
38c29ac
fix echo bug in js
giacomocavalieri Oct 26, 2024
39c9c24
wip integration tests
giacomocavalieri Oct 26, 2024
7037cd2
use current compiler version
giacomocavalieri Oct 28, 2024
ea0bb6b
Failing test
lpil Oct 30, 2024
e408436
rename echo functions to avoid conflicts with modules
giacomocavalieri Oct 31, 2024
48833e8
rename integration test project
giacomocavalieri Oct 31, 2024
7a1998c
add line number and file to echo output
giacomocavalieri Nov 5, 2024
2c6ac04
make echo printed paths relative to project's root
giacomocavalieri Nov 5, 2024
0a830e8
tests
giacomocavalieri Nov 5, 2024
7122454
rebase gone wrong
giacomocavalieri Nov 5, 2024
2ba0995
clippy
giacomocavalieri Nov 5, 2024
349fcc1
CHANGELOG!
giacomocavalieri Nov 5, 2024
a17c5eb
remove annoyance since we now have echo
giacomocavalieri Nov 12, 2024
e5aa652
rebase gone wrong?
giacomocavalieri Dec 8, 2024
f1da6a6
rebase gone terribly wrong
giacomocavalieri Dec 8, 2024
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
67 changes: 58 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,47 @@

### Compiler

- Removed compiler hint about pattern matching a `Result(a, b)` when being used where `a` is expected.
- You can now use the `echo` keyword to debug print any value: `echo` can be
followed by any expression and it will print it to stderr alongside the module
it comes from and its line number. This:

```gleam
pub fn main() {
echo [1, 2, 3]
}
```

Will output to stderr:

```txt
/src/module.gleam:2
[1, 2, 3]
```

`echo` can also be used in the middle of a pipeline. This:

```gleam
pub fn main() {
[1, 2, 3]
|> echo
|> list.map(fn(x) { x * 2 })
|> echo
}
```

Will output to stderr:

```txt
/src/module.gleam:3
[1, 2, 3]
/src/module.gleam:5
[2, 4, 6]
```

([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- Removed compiler hint about pattern matching a `Result(a, b)` when being used
where `a` is expected.
([Kieran O'Reilly](https://github.com/SoTeKie))

- Optimised code generated for record updates.
Expand Down Expand Up @@ -35,7 +75,8 @@

([Surya Rose](https://github.com/GearsDatapacks))

- A custom panic message can now be specified when asserting a value with `let assert`:
- A custom panic message can now be specified when asserting a value with
`let assert`:

```gleam
let assert Ok(regex) = regex.compile("ab?c+") as "This regex is always valid"
Expand Down Expand Up @@ -73,7 +114,8 @@
O(1) operation instead of O(N), significantly improving performance.
([Richard Viney](https://github.com/richard-viney))

- Better error message for existed type constructor being used as value constructor.
- Better error message for existed type constructor being used as value
constructor.
([Jiangda Wang](https://github.com/Frank-III))

### Build tool
Expand All @@ -90,8 +132,9 @@
team packages and v0 packages.
([Louis Pilfold](https://github.com/lpil))

- `gleam publish` now warns when publishing packages that define multiple top-level
modules, as this can lead to namespace pollution and conflicts for consumers.
- `gleam publish` now warns when publishing packages that define multiple
top-level modules, as this can lead to namespace pollution and conflicts for
consumers.
([Aleksei Gurianov](https://github.com/guria))

- New projects now require `gleam_stdlib` v0.44.0.
Expand All @@ -104,6 +147,12 @@
with a local password, reducing risk of your Hex password being compromised.
([Louis Pilfold](https://github.com/lpil))

### Build tool

- The build tool now refuses to publish any incomplete package that has any
`echo` debug printing left.
([Giacomo Cavalieri](https://github.com/giacomocavalieri))

### Language Server

- The language server now provides type information when hovering over argument
Expand Down Expand Up @@ -237,10 +286,10 @@
- Fixed a bug where the inferred variant of values was not properly cached,
leading to incorrect errors on incremental builds and in the Language Server.
([Surya Rose](https://github.com/GearsDatapacks))
- Fixed a bug where Gleam would be unable to compile to BEAM bytecode if the
project path contains a non-ascii character.
([yoshi](https://github.com/joshi-monster))

- Fixed a bug where Gleam would be unable to compile to BEAM bytecode if the
project path contains a non-ascii character.
([yoshi](https://github.com/joshi-monster))

## v1.6.1 - 2024-11-19

Expand Down
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[workspace]
resolver = "2"
members = [
"compiler-cli",
"compiler-core",
"compiler-wasm",
"test-helpers-rs",
"test-package-compiler",
"test-project-compiler",
"compiler-cli",
"compiler-core",
"compiler-wasm",
"test-helpers-rs",
"test-package-compiler",
"test-project-compiler",
"test-output",
]

# common dependencies
Expand Down Expand Up @@ -59,7 +60,7 @@ thiserror = "1"
# Test assertion errors with diffs
pretty_assertions = "1"
# Snapshot testing to make test maintenance easier
insta = {version = "1", features = ["glob"]}
insta = { version = "1", features = ["glob"] }
# A transitive dependency needed to compile into wasm32-unknown-unknown
# See https://docs.rs/getrandom/latest/getrandom/index.html#webassembly-support
getrandom = { version = "0", features = ["js"] }
35 changes: 23 additions & 12 deletions compiler-cli/src/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,18 +321,29 @@ fn do_build_hex_tarball(paths: &ProjectPaths, config: &mut PackageConfig) -> Res
}
}

// If any of the modules in the package contain a todo then refuse to
// publish as the package is not yet finished.
let unfinished = built
.root_package
.modules
.iter()
.filter(|module| module.ast.type_info.contains_todo())
.map(|module| module.name.clone())
.sorted()
.collect_vec();
if !unfinished.is_empty() {
return Err(Error::CannotPublishTodo { unfinished });
// If any of the modules in the package contain a todo or an echo then
// refuse to publish as the package is not yet finished.
let mut modules_containing_todo = vec![];
let mut modules_containing_echo = vec![];

for module in built.root_package.modules.iter() {
if module.ast.type_info.contains_todo() {
modules_containing_todo.push(module.name.clone());
} else if module.ast.type_info.contains_echo {
modules_containing_echo.push(module.name.clone());
}
}

if !modules_containing_todo.is_empty() {
return Err(Error::CannotPublishTodo {
unfinished: modules_containing_todo,
});
}

if !modules_containing_echo.is_empty() {
return Err(Error::CannotPublishEcho {
unfinished: modules_containing_echo,
});
}

// TODO: If any of the modules in the package contain a leaked internal type then
Expand Down
12 changes: 12 additions & 0 deletions compiler-core/generated/schema_capnp.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions compiler-core/schema.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct Module {
srcPath @7 :Text;
isInternal @8 :Bool;
requiredVersion @9 :Version;
containsEcho @10 :Bool;
}

struct Version {
Expand Down
2 changes: 2 additions & 0 deletions compiler-core/src/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> {
module_values: values,
accessors,
names: type_names,
echo_found,
..
} = env;

Expand Down Expand Up @@ -335,6 +336,7 @@ impl<'a, A> ModuleAnalyzer<'a, A> {
src_path: self.src_path,
warnings,
minimum_required_version: self.minimum_required_version,
contains_echo: echo_found,
},
names: type_names,
};
Expand Down
42 changes: 42 additions & 0 deletions compiler-core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2465,3 +2465,45 @@ impl TypedAssignment {
self.value.type_()
}
}

/// A pipeline is desugared to a series of assignments:
///
/// ```gleam
/// wibble |> wobble |> woo
/// ```
///
/// Becomes:
///
/// ```erl
/// Pipe1 = wibble
/// Pipe2 = wobble(Pipe1)
/// woo(Pipe2)
/// ```
///
/// This represents one of such assignments once the pipeline has been desugared
/// and each step has been typed.
///
/// > We're not using a more general `TypedAssignment` node since that has much
/// > more informations to carry around. This one is limited since we know it
/// > will always be in the form `VarName = <Expr>`, with no patterns on the
/// > left hand side of the assignment.
/// > Being more constrained simplifies code generation for pipelines!
///
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypedPipelineAssignment {
giacomocavalieri marked this conversation as resolved.
Show resolved Hide resolved
pub location: SrcSpan,
pub name: EcoString,
pub value: Box<TypedExpr>,
}

impl TypedPipelineAssignment {
pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> {
self.value
.find_node(byte_index)
.or_else(|| self.value.find_node(byte_index))
}

pub fn type_(&self) -> Arc<Type> {
self.value.type_()
}
}
24 changes: 22 additions & 2 deletions compiler-core/src/ast/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub enum TypedExpr {
/// locations when showing it in error messages, etc.
Pipeline {
location: SrcSpan,
assignments: Vec<TypedAssignment>,
assignments: Vec<TypedPipelineAssignment>,
finally: Box<Self>,
},

Expand Down Expand Up @@ -129,6 +129,12 @@ pub enum TypedExpr {
type_: Arc<Type>,
},

Echo {
location: SrcSpan,
type_: Arc<Type>,
expression: Option<Box<Self>>,
},

BitArray {
location: SrcSpan,
type_: Arc<Type>,
Expand Down Expand Up @@ -195,6 +201,11 @@ impl TypedExpr {
| Self::ModuleSelect { .. }
| Self::Invalid { .. } => self.self_if_contains_location(byte_index),

Self::Echo { expression, .. } => expression
.as_ref()
.and_then(|e| e.find_node(byte_index))
.or_else(|| self.self_if_contains_location(byte_index)),

Self::Todo { kind, .. } => match kind {
TodoKind::Keyword => self.self_if_contains_location(byte_index),
// We don't want to match on todos that were implicitly inserted
Expand Down Expand Up @@ -348,6 +359,7 @@ impl TypedExpr {
| Self::Int { location, .. }
| Self::Var { location, .. }
| Self::Todo { location, .. }
| Self::Echo { location, .. }
| Self::Case { location, .. }
| Self::Call { location, .. }
| Self::List { location, .. }
Expand Down Expand Up @@ -375,6 +387,7 @@ impl TypedExpr {
| Self::Int { location, .. }
| Self::Var { location, .. }
| Self::Todo { location, .. }
| Self::Echo { location, .. }
| Self::Case { location, .. }
| Self::Call { location, .. }
| Self::List { location, .. }
Expand Down Expand Up @@ -404,6 +417,7 @@ impl TypedExpr {
| TypedExpr::Call { .. }
| TypedExpr::Case { .. }
| TypedExpr::Todo { .. }
| TypedExpr::Echo { .. }
| TypedExpr::Panic { .. }
| TypedExpr::BinOp { .. }
| TypedExpr::Float { .. }
Expand Down Expand Up @@ -445,6 +459,7 @@ impl TypedExpr {
Self::Fn { type_, .. }
| Self::Int { type_, .. }
| Self::Todo { type_, .. }
| Self::Echo { type_, .. }
| Self::Case { type_, .. }
| Self::List { type_, .. }
| Self::Call { type_, .. }
Expand Down Expand Up @@ -505,6 +520,7 @@ impl TypedExpr {
| TypedExpr::Tuple { .. }
| TypedExpr::TupleIndex { .. }
| TypedExpr::Todo { .. }
| TypedExpr::Echo { .. }
| TypedExpr::Panic { .. }
| TypedExpr::BitArray { .. }
| TypedExpr::RecordUpdate { .. }
Expand Down Expand Up @@ -604,7 +620,10 @@ impl TypedExpr {
// `panic`, `todo`, and placeholders are never considered pure value constructors,
// we don't want to raise a warning for an unused value if it's one
// of those.
TypedExpr::Todo { .. } | TypedExpr::Panic { .. } | TypedExpr::Invalid { .. } => false,
TypedExpr::Todo { .. }
| TypedExpr::Panic { .. }
| TypedExpr::Echo { .. }
| TypedExpr::Invalid { .. } => false,
}
}

Expand Down Expand Up @@ -684,6 +703,7 @@ impl TypedExpr {
| TypedExpr::NegateBool { location, .. }
| TypedExpr::NegateInt { location, .. }
| TypedExpr::Invalid { location, .. }
| TypedExpr::Echo { location, .. }
| TypedExpr::Pipeline { location, .. } => *location,

TypedExpr::Block { statements, .. } => statements.last().last_location(),
Expand Down
Loading
Loading