Skip to content
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
1 change: 1 addition & 0 deletions app/gui/src/project-view/util/ast/__tests__/raw.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ test.each([
{ tree: Tree.Type.Number, repr: '2' },
{ token: Token.Type.Digits, repr: '2' },
{ token: Token.Type.Operator, repr: '+' },
{ tree: Tree.Type.Call, repr: 'a' },
{ tree: Tree.Type.Ident, repr: 'a' },
{ token: Token.Type.Ident, repr: 'a' },
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,9 @@ private List<Name> qualifiedNameSegments(Tree t, boolean generateId) throws Synt
names = join(sanitizeName(buildName(app.getRhs(), generateId)), names);
t = app.getLhs();
}
if (t instanceof Tree.Call call) {
t = call.getValue();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • the intentions of call nodes seem to be good
  • now when I "get them"
  • let's try the approach

}
if (t instanceof Tree.Ident id) {
names = join(sanitizeName(buildName(id, generateId)), names);
} else {
Expand Down
537 changes: 271 additions & 266 deletions lib/rust/parser/debug/tests/parse.rs

Large diffs are not rendered by default.

108 changes: 86 additions & 22 deletions lib/rust/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ use crate::prelude::*;
use crate::lexer::Lexer;
use crate::macros::resolver::RootContext;
use crate::source::Code;
use crate::syntax::token;

use crate::syntax::{maybe_with_error, token};

use crate::syntax::tree::{SyntaxError, Variant};
use crate::syntax::{Finish, Tree};
Expand Down Expand Up @@ -201,44 +202,51 @@ fn unwrap_call(tree: Tree) -> Tree {
}
}

fn is_qualified_name(tree: &Tree) -> bool {
match &tree.variant {
Variant::Call(call) => is_qualified_name(&call.value),
Variant::PropertyAccess(access) => match &access.lhs {
Some(lhs) => is_qualified_name(&lhs),
None => false,
},
Variant::Ident(_) => true,
_ => false,
}
}

/// If the input is a qualified name, return it as Ok after discarding any Call nodes;
/// otherwise, return the input unchanged as Err.
fn to_qualified_name(tree: Tree) -> Result<Tree, Tree> {
use syntax::tree::*;
if matches!(&tree.variant, Variant::Ident(_) | Variant::PropertyAccess(_)) {
return Ok(tree);
}
match tree {
Tree { variant: Variant::Call(mut call), span, .. } => {
call.value.span.left_offset = span.left_offset;
match &call.value.variant {
Variant::Ident(_) | Variant::PropertyAccess(_) => Ok(call.value),
_ => Err(call.value),
}
}
_ => Err(tree),
fn to_qualified_name(mut tree: Tree) -> Result<Tree, Tree> {
if !is_qualified_name(&tree) {
return Err(tree);
}
qn_deep_unwrap_calls(&mut tree);
Ok(tree)
}

fn qn_deep_unwrap_calls(tree: &mut Tree) {
fn qn_deep_unwrap_calls(tree: &mut Tree) -> bool {
match &mut tree.variant {
Variant::Call(call) => {
let mut inner = mem::take(&mut call.value);
qn_deep_unwrap_calls(&mut inner);
let result = qn_deep_unwrap_calls(&mut inner);
tree.variant = inner.variant;
result
}
Variant::PropertyAccess(access) => {
if let Some(lhs) = &mut access.lhs {
qn_deep_unwrap_calls(lhs);
qn_deep_unwrap_calls(lhs)
} else {
false
}
}
_ => {}
Variant::Ident(_) => true,
_ => false,
}
}

fn expect_qualified_name(tree: Tree) -> Tree {
to_qualified_name(unwrap_call(tree))
.unwrap_or_else(|tree| tree.with_error(SyntaxError::ExpectedQualifiedName))
fn expect_qualified_name(mut tree: Tree) -> Tree {
let error = (!qn_deep_unwrap_calls(&mut tree)).then_some(SyntaxError::ExpectedQualifiedName);
maybe_with_error(tree, error)
}

fn empty_tree(location: Code) -> Tree {
Expand All @@ -255,6 +263,11 @@ fn expression_to_pattern(mut input: Tree<'_>) -> Tree<'_> {
transform_tree(body, expression_to_pattern)
}
}
Variant::PropertyAccess(ref mut access) => {
if let Some(value) = &mut access.lhs {
transform_tree(value, expression_to_pattern)
}
}
Variant::App(ref mut app) => match &mut **app {
// === Special-case error ===
App { func: Tree { variant: Variant::Ident(ident), .. }, .. }
Expand Down Expand Up @@ -293,6 +306,57 @@ fn expression_to_pattern(mut input: Tree<'_>) -> Tree<'_> {
maybe_with_error(input, error)
}

fn expression_to_type(mut input: Tree<'_>) -> Tree<'_> {
use syntax::tree::*;
match input.variant {
// === Recursions ===
Variant::Group(ref mut group) => {
if let Group { body: Some(body), .. } = &mut **group {
transform_tree(body, expression_to_type)
}
}
Variant::App(ref mut app) => match &mut **app {
App { func, arg } => {
transform_tree(func, expression_to_type);
transform_tree(arg, expression_to_type);
}
},
Variant::OprApp(ref mut opr_app) => match &mut **opr_app {
OprApp { lhs, rhs, .. } => {
if let Some(lhs) = lhs.as_mut() {
transform_tree(lhs, expression_to_type);
}
if let Some(rhs) = rhs.as_mut() {
transform_tree(rhs, expression_to_type);
}
}
},
Variant::Array(ref mut array) => match &mut **array {
Array { first, .. } => {
if let Some(first) = first.as_mut() {
transform_tree(first, expression_to_type);
}
}
},
Variant::PropertyAccess(ref mut access) => {
if let Some(value) = &mut access.lhs {
transform_tree(value, expression_to_type)
}
}

// === Transformations ===
Variant::Call(value) => {
let mut out = expression_to_type(value.value);
out.span.left_offset += input.span.left_offset;
return out;
}

// === Unhandled ===
_ => {}
};
input
}

thread_local! {
static DEFAULT_TREE: RefCell<Option<Tree<'static>>> = default();
}
Expand Down
7 changes: 4 additions & 3 deletions lib/rust/parser/src/syntax/expression/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::syntax::token;
use crate::syntax::token::TokenOperatorProperties;

use crate::syntax::tree::{MultipleOperatorError, Variant};
use crate::unwrap_call;
use crate::{expression_to_type, unwrap_call};
// ==========================
// === Applying operators ===
// ==========================
Expand Down Expand Up @@ -122,10 +122,10 @@ impl<'s> ApplyOperator<'s> {
_ => operand.value,
});

let call = false;
let mut call = false;
let value = match (token.variant, lhs, rhs) {
(token::Variant::TypeAnnotationOperator(annotation), Some(lhs), Some(rhs)) => {
Tree::type_annotated(lhs, token.with_variant(annotation), rhs)
Tree::type_annotated(lhs, token.with_variant(annotation), expression_to_type(rhs))
}
(
token::Variant::DotOperator(dot),
Expand All @@ -135,6 +135,7 @@ impl<'s> ApplyOperator<'s> {
let mut ident = rhs.token;
ident.left_offset = span.left_offset;
let value = Tree::property_access(lhs, token.with_variant(dot), ident);
call = true;
value
}
(_, lhs, rhs) => apply_operator(lhs, token, rhs),
Expand Down
2 changes: 2 additions & 0 deletions lib/rust/parser/src/syntax/expression/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::syntax::token::TokenOperatorProperties;
use crate::syntax::tree::block::Line;
use crate::syntax::tree::block::OperatorBlockExpression;
use crate::syntax::tree::block::OperatorLine;
use crate::unwrap_call;

/// Consumes `Item`s and passes their content to a token/tree consumer, using an
/// [`ExpressionParser`] to flatten blocks.
Expand Down Expand Up @@ -145,6 +146,7 @@ impl<'s> ApplicableBlock<'s> {
Tree::operator_block_application(expression, operator_lines, excess)
}
Self::ArgumentBlock { body_lines } => {
let expression = expression.map(unwrap_call);
Tree::argument_block_application(expression, body_lines)
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rust/parser/src/syntax/expression/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct Operand<'s> {
/// Unit. Creates a Operand from a node.
impl<'s> From<Tree<'s>> for Operand<'s> {
fn from(value: Tree<'s>) -> Self {
let call = false;
let call = matches!(value.variant, tree::Variant::Ident(_));
let wildcards = matches!(value.variant, tree::Variant::Wildcard(_));
Self { value, wildcards, call }
}
Expand Down
4 changes: 2 additions & 2 deletions lib/rust/parser/src/syntax/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
mod function_def;
mod type_def;

use crate::expression_to_pattern;
use crate::prelude::*;
use crate::syntax::Item;
use crate::syntax::Token;
Expand All @@ -27,6 +26,7 @@ use crate::syntax::tree::TypeSignature;
use crate::syntax::tree::TypeSignatureLine;
use crate::syntax::tree::block;
use crate::{empty_tree, to_qualified_name};
use crate::{expression_to_pattern, expression_to_type};

pub use function_def::parse_args;

Expand Down Expand Up @@ -595,7 +595,7 @@ fn parse_type_annotation_statement<'s>(
let operator: token::TypeAnnotationOperator =
items.pop().unwrap().into_token().unwrap().try_into().unwrap();
let lhs = expression_parser.parse_non_section_offset(start, items);
let type_ = type_.unwrap_or_else(|| {
let type_ = type_.map(expression_to_type).unwrap_or_else(|| {
empty_tree(operator.code.position_after()).with_error(SyntaxError::ExpectedType)
});
debug_assert!(items.len() <= start);
Expand Down
9 changes: 6 additions & 3 deletions lib/rust/parser/src/syntax/statement/function_def.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::prelude::*;

use crate::empty_tree;
use crate::syntax::Item;
use crate::syntax::Token;
use crate::syntax::Tree;
Expand Down Expand Up @@ -30,6 +29,8 @@ use crate::syntax::tree::ReturnSpecification;
use crate::syntax::tree::SyntaxError;
use crate::syntax::tree::TypeSignatureLine;

use crate::{empty_tree, expression_to_type, qn_deep_unwrap_calls};

pub struct FunctionBuilder<'s> {
name: Tree<'s>,
return_: Option<ReturnSpecification<'s>>,
Expand Down Expand Up @@ -68,7 +69,8 @@ impl<'s> FunctionBuilder<'s> {
);
let args = args_buffer.drain(..).rev().collect();

let name = expression_parser.parse_non_section_offset(start, items).unwrap();
let mut name = expression_parser.parse_non_section_offset(start, items).unwrap();
qn_deep_unwrap_calls(&mut name);

Self { name, return_, args, line, start }
}
Expand Down Expand Up @@ -164,6 +166,7 @@ impl<'s> FunctionBuilder<'s> {
fn qn_equivalent(a: &Tree, b: &Tree) -> bool {
use tree::Variant::*;
match (&a.variant, &b.variant) {
(Call(a), Call(b)) => qn_equivalent(&a.value, &b.value),
(Ident(a), Ident(b)) => a.token.code.repr == b.token.code.repr,
(PropertyAccess(a), PropertyAccess(b)) => {
a.rhs.code.repr == b.rhs.code.repr && opt_qn_equivalent(&a.lhs, &b.lhs)
Expand Down Expand Up @@ -451,7 +454,7 @@ fn parse_arg_def<'s>(
let items = parenthesized_body.as_mut().unwrap_or(items);
let tree = expression_parser.parse_non_section_offset(start + type_ + 1, items);
let operator = items.pop().unwrap().into_token().unwrap();
let type_ = tree.unwrap_or_else(|| {
let type_ = tree.map(expression_to_type).unwrap_or_else(|| {
empty_tree(operator.code.position_after()).with_error(SyntaxError::ExpectedType)
});
let token::Variant::TypeAnnotationOperator(variant) = operator.variant else {
Expand Down
Loading