Skip to content

Commit

Permalink
moved modules around
Browse files Browse the repository at this point in the history
  • Loading branch information
ascandone committed Jun 21, 2024
1 parent 55fdd32 commit 1af1564
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 370 deletions.
1 change: 1 addition & 0 deletions compiler-core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod constant;
mod typed;
mod untyped;

pub mod inlay_hints;
#[cfg(test)]
mod tests;
pub mod visit;
Expand Down
98 changes: 98 additions & 0 deletions compiler-core/src/ast/inlay_hints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use crate::{
ast::{
visit::{self, Visit},
SrcSpan, TypedAssignment, TypedExpr, TypedModule,
},
line_numbers::LineNumbers,
type_::pretty::Printer,
};

#[derive(Debug, Eq, PartialEq)]
pub struct InlayHint {
pub label: String,
pub offset: u32,
}

fn is_simple_lit(expr: &TypedExpr) -> bool {
matches!(
expr,
TypedExpr::Int { .. }
| TypedExpr::Float { .. }
| TypedExpr::String { .. }
| TypedExpr::BitArray { .. }
)
}

struct InlayHintsVisitor<'a> {
hints: Vec<InlayHint>,
line_numbers: &'a LineNumbers,
}

impl<'a> InlayHintsVisitor<'a> {
fn new(line_numbers: &'a LineNumbers) -> InlayHintsVisitor<'a> {
InlayHintsVisitor {
hints: vec![],
line_numbers,
}
}
}

impl<'a, 'ast> Visit<'ast> for InlayHintsVisitor<'a> {
fn visit_typed_expr_pipeline(
&mut self,
_location: &'ast SrcSpan,
assignments: &'ast [TypedAssignment],
finally: &'ast TypedExpr,
) {
fn get_this_line(this: &InlayHintsVisitor<'_>, span: &SrcSpan) -> u32 {
this.line_numbers.line_and_column_number(span.end).line
}

let mut prev_hint: Option<(u32, Option<InlayHint>)> = None;
for assign in assignments {
let this_line = get_this_line(self, &assign.location);

if let Some((prev_line, prev_hint)) = prev_hint {
if prev_line != this_line {
if let Some(prev_hint) = prev_hint {
self.hints.push(prev_hint);
}
}
};

let this_hint = InlayHint {
label: Printer::new().pretty_print(assign.type_().as_ref(), 0),
offset: assign.location.end,
};
prev_hint = Some((
this_line,
if is_simple_lit(&assign.value) {
None
} else {
Some(this_hint)
},
));

visit::visit_typed_expr(self, &assign.value);
}

if let Some((prev_line, prev_hint)) = prev_hint {
let this_line = get_this_line(self, &finally.location());
if this_line != prev_line {
if let Some(prev_hint) = prev_hint {
self.hints.push(prev_hint);
}
self.hints.push(InlayHint {
label: Printer::new().pretty_print(finally.type_().as_ref(), 0),
offset: finally.location().end,
});
}
}
}
}

pub fn get_inlay_hints(typed_module: TypedModule, line_numbers: &LineNumbers) -> Vec<InlayHint> {
let mut visitor = InlayHintsVisitor::new(line_numbers);
visitor.visit_typed_module(&typed_module);
visitor.hints
}
229 changes: 229 additions & 0 deletions compiler-core/src/ast/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,3 +576,232 @@ use x <- fn(f) { f(1) }
assert!(use_.find_node(23).is_some());
assert!(use_.find_node(26).is_some()); // The int
}

mod inlay_hints_tests {
use super::*;
use crate::{
ast::inlay_hints::{get_inlay_hints, InlayHint},
line_numbers::LineNumbers,
};

#[test]
fn no_hints_when_same_line() {
let src = r#"
fn identity(x) {
x
}
fn ret_str(_x) {
"abc"
}
pub fn example_pipe() {
0 |> ret_str() |> identity()
}
"#;

assert_inlay_hints(src, vec![]);
}

#[test]
fn no_hints_when_value_is_literal() {
let src = r#"
pub fn ret_str(f1) {
"abc"
|> f1()
}
pub fn ret_int(f2) {
42
|> f2()
}
pub fn ret_float(f3) {
42.2
|> f3()
}
pub fn ret_bit_array(f4) {
<<1, 2>>
|> f4()
}
"#;

assert_inlay_hints(
src,
vec![
InlayHint {
label: "a".to_string(),
offset: index_of_end(src, "|> f1()"),
},
InlayHint {
label: "a".to_string(),
offset: index_of_end(src, "|> f2()"),
},
InlayHint {
label: "a".to_string(),
offset: index_of_end(src, "|> f3()"),
},
InlayHint {
label: "a".to_string(),
offset: index_of_end(src, "|> f4()"),
},
],
);
}

#[test]
fn show_many_hints() {
let src = r#"
const int_val = 0
fn identity(x) {
x
}
fn ret_str(_x) {
"abc"
}
pub fn example_pipe() {
int_val
|> ret_str()
|> identity()
}
"#;

assert_inlay_hints(
src,
vec![
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, " int_val"),
},
InlayHint {
label: "String".to_string(),
offset: index_of_end(src, "|> ret_str()"),
},
InlayHint {
label: "String".to_string(),
offset: index_of_end(src, "|> identity()"),
},
],
);
}

#[test]
fn hints_nested_in_case_block() {
let src = r#"
const int_val = 0
fn identity(x) {
x
}
fn main(a) {
case a {
_ -> {
int_val
|> identity()
}
}
}
"#;

assert_inlay_hints(
src,
vec![
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, " int_val"),
},
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, "|> identity()"),
},
],
);
}

#[test]
fn hints_nested_for_apply_fn_let() {
let src = r#"
const int_val = 0
fn identity(x) {
x
}
fn main() {
let f = identity(fn() {
int_val
|> identity()
})
}
"#;

assert_inlay_hints(
src,
vec![
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, " int_val"),
},
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, "|> identity()"),
},
],
);
}

#[test]
fn hints_in_use() {
let src = r#"
const int_val = 0
fn identity(x) {
x
}
fn main(f) {
use a <- f()
int_val
|> identity()
}
"#;

assert_inlay_hints(
src,
vec![
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, " int_val"),
},
InlayHint {
label: "Int".to_string(),
offset: index_of_end(src, "|> identity()"),
},
],
);
}

#[test]
fn test_index_of() {
let src = r#"a[Z]c"#;
assert_eq!(index_of_end(src, "[Z]"), 4);
}

fn index_of_end(src: &str, search_for: &str) -> u32 {
let lookup = src.find(search_for).expect("Expected to find lookup");
(lookup + search_for.len()) as u32
}

fn assert_inlay_hints(src: &str, expected_inlay_hints: Vec<InlayHint>) {
let typed_module = compile_module(src);
let line_numbers = LineNumbers::new(src);
let inlay_hints = get_inlay_hints(typed_module, &line_numbers);

assert_eq!(inlay_hints, expected_inlay_hints);
}
}
1 change: 0 additions & 1 deletion compiler-core/src/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ mod completer;
mod engine;
mod feedback;
mod files;
mod inlay_hints;
mod messages;
mod progress;
mod router;
Expand Down
7 changes: 3 additions & 4 deletions compiler-core/src/language_server/engine.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use crate::{
ast::{
Arg, Definition, ModuleConstant, SrcSpan, TypedExpr, TypedFunction, TypedModule,
self, Arg, Definition, ModuleConstant, SrcSpan, TypedExpr, TypedFunction, TypedModule,
TypedPattern,
},
build::{type_constructor_from_modules, Located, Module, UnqualifiedImport},
config::PackageConfig,
io::{CommandExecutor, FileSystemReader, FileSystemWriter},
language_server::{
compiler::LspProjectCompiler, files::FileSystemProxy, inlay_hints::get_inlay_hints,
progress::ProgressReporter,
compiler::LspProjectCompiler, files::FileSystemProxy, progress::ProgressReporter,
},
line_numbers::LineNumbers,
paths::ProjectPaths,
Expand Down Expand Up @@ -275,7 +274,7 @@ where

let line_numbers = LineNumbers::new(&module.code);

let hints = get_inlay_hints(module.ast.clone(), &line_numbers)
let hints = ast::inlay_hints::get_inlay_hints(module.ast.clone(), &line_numbers)
.iter()
.map(|hint| InlayHint {
position: src_offset_to_lsp_position(hint.offset, &line_numbers),
Expand Down
Loading

0 comments on commit 1af1564

Please sign in to comment.