mirror of
https://github.com/enso-org/enso.git
synced 2024-12-19 19:13:16 +03:00
Generating SpanTree from macros (https://github.com/enso-org/ide/pull/389)
Before during SpanTree generation we treated macros as a leaves. Now we properly look into them, get all the AST nodes in their patterns and generate children of these SpanTree nodes from them.
Original commit: aeff31f2d8
This commit is contained in:
parent
bc2551daf6
commit
ef5cb279a3
@ -92,7 +92,7 @@ pub struct WrongEnum {pub expected_con:String}
|
||||
// === Tree ===
|
||||
// ============
|
||||
|
||||
/// A tree structure where each node may store value of `K` and has arbitrary
|
||||
/// A tree structure where each node may store value of `V` and has arbitrary
|
||||
/// number of children nodes, each marked with a single `K`.
|
||||
///
|
||||
/// It is used to describe ambiguous macro match.
|
||||
|
@ -159,8 +159,8 @@ impl<'a> Implementation for node::Ref<'a> {
|
||||
fn erase_impl(&self) -> Option<EraseOperation> {
|
||||
|
||||
match self.node.kind {
|
||||
node::Kind::Argument{removable:true,..} |
|
||||
node::Kind::Target {removable:true} => Some(Box::new(move |root| {
|
||||
node::Kind::Argument{is_removable:true} |
|
||||
node::Kind::Target {is_removable:true} => Some(Box::new(move |root| {
|
||||
let parent_crumb = &self.ast_crumbs[..self.ast_crumbs.len()-1];
|
||||
let ast = root.get_traversing(parent_crumb)?;
|
||||
let new_ast = if let Some(mut infix) = ast::opr::Chain::try_new(ast) {
|
||||
@ -233,46 +233,52 @@ mod test {
|
||||
|
||||
let cases:&[Case] = &
|
||||
// Setting
|
||||
[ Case{expr:"a + b" , span:0..5, action:Set , expected:"foo" }
|
||||
, Case{expr:"a + b" , span:0..1, action:Set , expected:"foo + b" }
|
||||
, Case{expr:"a + b" , span:4..5, action:Set , expected:"a + foo" }
|
||||
, Case{expr:"a + b + c", span:0..1, action:Set , expected:"foo + b + c" }
|
||||
, Case{expr:"a + b + c", span:4..5, action:Set , expected:"a + foo + c" }
|
||||
, Case{expr:"a , b , c", span:0..1, action:Set , expected:"foo , b , c" }
|
||||
, Case{expr:"a , b , c", span:4..5, action:Set , expected:"a , foo , c" }
|
||||
, Case{expr:"a , b , c", span:8..9, action:Set , expected:"a , b , foo" }
|
||||
, Case{expr:"f a b" , span:0..1, action:Set , expected:"foo a b" }
|
||||
, Case{expr:"f a b" , span:2..3, action:Set , expected:"f foo b" }
|
||||
, Case{expr:"f a b" , span:4..5, action:Set , expected:"f a foo" }
|
||||
, Case{expr:"+ b" , span:0..0, action:Set , expected:"foo + b" }
|
||||
, Case{expr:"+ b" , span:2..3, action:Set , expected:"+ foo" }
|
||||
, Case{expr:"a +" , span:0..1, action:Set , expected:"foo +" }
|
||||
, Case{expr:"a +" , span:3..3, action:Set , expected:"a + foo" }
|
||||
, Case{expr:"+" , span:0..0, action:Set , expected:"foo +" }
|
||||
, Case{expr:"+" , span:1..1, action:Set , expected:"+ foo" }
|
||||
, Case{expr:"a + b" , span:0..0, action:Set , expected:"foo + a + b" }
|
||||
, Case{expr:"a + b" , span:1..1, action:Set , expected:"a + foo + b" }
|
||||
, Case{expr:"a + b" , span:5..5, action:Set , expected:"a + b + foo" }
|
||||
, Case{expr:"+ b" , span:3..3, action:Set , expected:"+ b + foo" }
|
||||
, Case{expr:"a + b + c", span:0..0, action:Set , expected:"foo + a + b + c"}
|
||||
, Case{expr:"a + b + c", span:5..5, action:Set , expected:"a + b + foo + c"}
|
||||
, Case{expr:"a , b , c", span:0..0, action:Set , expected:"foo , a , b , c"}
|
||||
, Case{expr:"a , b , c", span:4..4, action:Set , expected:"a , foo , b , c"}
|
||||
, Case{expr:"a , b , c", span:8..8, action:Set , expected:"a , b , foo , c"}
|
||||
, Case{expr:"a , b , c", span:9..9, action:Set , expected:"a , b , c , foo"}
|
||||
, Case{expr:", b" , span:3..3, action:Set , expected:", b , foo" }
|
||||
, Case{expr:"f a b" , span:2..2, action:Set , expected:"f foo a b" }
|
||||
, Case{expr:"f a b" , span:3..3, action:Set , expected:"f a foo b" }
|
||||
, Case{expr:"f a b" , span:5..5, action:Set , expected:"f a b foo" }
|
||||
[ Case{expr:"a + b" , span:0..5 , action:Set , expected:"foo" }
|
||||
, Case{expr:"a + b" , span:0..1 , action:Set , expected:"foo + b" }
|
||||
, Case{expr:"a + b" , span:4..5 , action:Set , expected:"a + foo" }
|
||||
, Case{expr:"a + b + c" , span:0..1 , action:Set , expected:"foo + b + c" }
|
||||
, Case{expr:"a + b + c" , span:4..5 , action:Set , expected:"a + foo + c" }
|
||||
, Case{expr:"a , b , c" , span:0..1 , action:Set , expected:"foo , b , c" }
|
||||
, Case{expr:"a , b , c" , span:4..5 , action:Set , expected:"a , foo , c" }
|
||||
, Case{expr:"a , b , c" , span:8..9 , action:Set , expected:"a , b , foo" }
|
||||
, Case{expr:"f a b" , span:0..1 , action:Set , expected:"foo a b" }
|
||||
, Case{expr:"f a b" , span:2..3 , action:Set , expected:"f foo b" }
|
||||
, Case{expr:"f a b" , span:4..5 , action:Set , expected:"f a foo" }
|
||||
, Case{expr:"+ b" , span:0..0 , action:Set , expected:"foo + b" }
|
||||
, Case{expr:"+ b" , span:2..3 , action:Set , expected:"+ foo" }
|
||||
, Case{expr:"a +" , span:0..1 , action:Set , expected:"foo +" }
|
||||
, Case{expr:"a +" , span:3..3 , action:Set , expected:"a + foo" }
|
||||
, Case{expr:"+" , span:0..0 , action:Set , expected:"foo +" }
|
||||
, Case{expr:"+" , span:1..1 , action:Set , expected:"+ foo" }
|
||||
, Case{expr:"a + b" , span:0..0 , action:Set , expected:"foo + a + b" }
|
||||
, Case{expr:"a + b" , span:1..1 , action:Set , expected:"a + foo + b" }
|
||||
, Case{expr:"a + b" , span:5..5 , action:Set , expected:"a + b + foo" }
|
||||
, Case{expr:"+ b" , span:3..3 , action:Set , expected:"+ b + foo" }
|
||||
, Case{expr:"a + b + c" , span:0..0 , action:Set , expected:"foo + a + b + c"}
|
||||
, Case{expr:"a + b + c" , span:5..5 , action:Set , expected:"a + b + foo + c"}
|
||||
, Case{expr:"a , b , c" , span:0..0 , action:Set , expected:"foo , a , b , c"}
|
||||
, Case{expr:"a , b , c" , span:4..4 , action:Set , expected:"a , foo , b , c"}
|
||||
, Case{expr:"a , b , c" , span:8..8 , action:Set , expected:"a , b , foo , c"}
|
||||
, Case{expr:"a , b , c" , span:9..9 , action:Set , expected:"a , b , c , foo"}
|
||||
, Case{expr:", b" , span:3..3 , action:Set , expected:", b , foo" }
|
||||
, Case{expr:"f a b" , span:2..2 , action:Set , expected:"f foo a b" }
|
||||
, Case{expr:"f a b" , span:3..3 , action:Set , expected:"f a foo b" }
|
||||
, Case{expr:"f a b" , span:5..5 , action:Set , expected:"f a b foo" }
|
||||
, Case{expr:"if a then b", span:3..4 , action:Set , expected: "if foo then b" }
|
||||
, Case{expr:"if a then b", span:10..11, action:Set , expected: "if a then foo" }
|
||||
, Case{expr:"(a + b + c)", span:5..6 , action:Set , expected: "(a + foo + c)" }
|
||||
, Case{expr:"(a + b + c" , span:5..6 , action:Set , expected: "(a + foo + c" }
|
||||
// Erasing
|
||||
, Case{expr:"a + b + c", span:0..1, action:Erase, expected:"b + c" }
|
||||
, Case{expr:"a + b + c", span:4..5, action:Erase, expected:"a + c" }
|
||||
, Case{expr:"a + b + c", span:8..9, action:Erase, expected:"a + b" }
|
||||
, Case{expr:"a , b , c", span:0..1, action:Erase, expected:"b , c" }
|
||||
, Case{expr:"a , b , c", span:4..5, action:Erase, expected:"a , c" }
|
||||
, Case{expr:"a , b , c", span:8..9, action:Erase, expected:"a , b" }
|
||||
, Case{expr:"f a b" , span:2..3, action:Erase, expected:"f b" }
|
||||
, Case{expr:"f a b" , span:4..5, action:Erase, expected:"f a" }
|
||||
, Case{expr:"a + b + c" , span:0..1 , action:Erase, expected:"b + c" }
|
||||
, Case{expr:"a + b + c" , span:4..5 , action:Erase, expected:"a + c" }
|
||||
, Case{expr:"a + b + c" , span:8..9 , action:Erase, expected:"a + b" }
|
||||
, Case{expr:"a , b , c" , span:0..1 , action:Erase, expected:"b , c" }
|
||||
, Case{expr:"a , b , c" , span:4..5 , action:Erase, expected:"a , c" }
|
||||
, Case{expr:"a , b , c" , span:8..9 , action:Erase, expected:"a , b" }
|
||||
, Case{expr:"f a b" , span:2..3 , action:Erase, expected:"f b" }
|
||||
, Case{expr:"f a b" , span:4..5 , action:Erase, expected:"f a" }
|
||||
, Case{expr:"(a + b + c)", span:5..6 , action:Erase, expected: "(a + c)" }
|
||||
, Case{expr:"(a + b + c" , span:5..6 , action:Erase, expected: "(a + c" }
|
||||
];
|
||||
let parser = Parser::new_or_panic();
|
||||
for case in cases { case.run(&parser); }
|
||||
@ -306,27 +312,32 @@ mod test {
|
||||
}
|
||||
}
|
||||
let cases:&[Case] = &
|
||||
[ Case{expr:"abc" , span:0..3, expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:0..0, expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:0..1, expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:1..1, expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:2..3, expected: &[] }
|
||||
, Case{expr:"a + b" , span:4..5, expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:5..5, expected: &[Set] }
|
||||
, Case{expr:"a + b + c", span:0..0, expected: &[Set] }
|
||||
, Case{expr:"a + b + c", span:0..1, expected: &[Set,Erase] }
|
||||
, Case{expr:"a + b + c", span:1..1, expected: &[Set] }
|
||||
, Case{expr:"a + b + c", span:4..5, expected: &[Set,Erase] }
|
||||
, Case{expr:"a + b + c", span:5..5, expected: &[Set] }
|
||||
, Case{expr:"a + b + c", span:8..9, expected: &[Set,Erase] }
|
||||
, Case{expr:"a + b + c", span:9..9, expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:0..1, expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:2..2, expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:2..3, expected: &[Set,Erase] }
|
||||
, Case{expr:"f a b" , span:3..3, expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:4..5, expected: &[Set,Erase] }
|
||||
, Case{expr:"f a b" , span:5..5, expected: &[Set] }
|
||||
, Case{expr:"f a" , span:2..3, expected: &[Set] }
|
||||
[ Case{expr:"abc" , span:0..3 , expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:0..0 , expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:0..1 , expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:1..1 , expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:2..3 , expected: &[] }
|
||||
, Case{expr:"a + b" , span:4..5 , expected: &[Set] }
|
||||
, Case{expr:"a + b" , span:5..5 , expected: &[Set] }
|
||||
, Case{expr:"a + b + c" , span:0..0 , expected: &[Set] }
|
||||
, Case{expr:"a + b + c" , span:0..1 , expected: &[Set,Erase] }
|
||||
, Case{expr:"a + b + c" , span:1..1 , expected: &[Set] }
|
||||
, Case{expr:"a + b + c" , span:4..5 , expected: &[Set,Erase] }
|
||||
, Case{expr:"a + b + c" , span:5..5 , expected: &[Set] }
|
||||
, Case{expr:"a + b + c" , span:8..9 , expected: &[Set,Erase] }
|
||||
, Case{expr:"a + b + c" , span:9..9 , expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:0..1 , expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:2..2 , expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:2..3 , expected: &[Set,Erase] }
|
||||
, Case{expr:"f a b" , span:3..3 , expected: &[Set] }
|
||||
, Case{expr:"f a b" , span:4..5 , expected: &[Set,Erase] }
|
||||
, Case{expr:"f a b" , span:5..5 , expected: &[Set] }
|
||||
, Case{expr:"f a" , span:2..3 , expected: &[Set] }
|
||||
, Case{expr:"if a then b", span:3..4 , expected: &[Set] }
|
||||
, Case{expr:"if a then b", span:10..11, expected: &[Set] }
|
||||
, Case{expr:"(a + b + c)", span:5..6 , expected: &[Set,Erase] }
|
||||
, Case{expr:"(a" , span:1..2 , expected: &[Set] }
|
||||
, Case{expr:"(a + b + c" , span:5..6 , expected: &[Set,Erase] }
|
||||
];
|
||||
let parser = Parser::new_or_panic();
|
||||
for case in cases { case.run(&parser); }
|
||||
|
@ -1,4 +1,5 @@
|
||||
//! A module containing code related to SpanTree generation.
|
||||
pub mod macros;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -8,6 +9,8 @@ use crate::Node;
|
||||
use crate::SpanTree;
|
||||
|
||||
use ast::Ast;
|
||||
use ast::MacroMatchSegment;
|
||||
use ast::MacroAmbiguousSegment;
|
||||
use ast::assoc::Assoc;
|
||||
use ast::crumbs::Located;
|
||||
use ast::HasLength;
|
||||
@ -15,6 +18,7 @@ use ast::opr::GeneralizedInfix;
|
||||
use data::text::Size;
|
||||
|
||||
|
||||
|
||||
// =============
|
||||
// === Trait ===
|
||||
// =============
|
||||
@ -34,6 +38,7 @@ pub trait SpanTreeGenerator {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === Utilities ===
|
||||
// =================
|
||||
@ -101,13 +106,19 @@ impl SpanTreeGenerator for Ast {
|
||||
infix.flatten().generate_node(kind)
|
||||
} else {
|
||||
match self.shape() {
|
||||
ast::Shape::Prefix {..} =>
|
||||
ast::Shape::Prefix(_) =>
|
||||
ast::prefix::Chain::try_new(self).unwrap().generate_node(kind),
|
||||
// TODO[a] add other shapes, e.g. macros
|
||||
_ => Ok(Node {kind,
|
||||
size : Size::new(self.len()),
|
||||
children : default(),
|
||||
}),
|
||||
// Lambdas should fall in _ case, because we don't want to create subports for
|
||||
// them
|
||||
ast::Shape::Match(ast) if ast::macros::as_lambda_match(self).is_none() =>
|
||||
ast.generate_node(kind),
|
||||
ast::Shape::Ambiguous(ast) =>
|
||||
ast.generate_node(kind),
|
||||
_ => {
|
||||
let size = Size::new(self.len());
|
||||
let children = default();
|
||||
Ok(Node {kind,size,children})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,10 +131,12 @@ impl SpanTreeGenerator for ast::opr::Chain {
|
||||
fn generate_node(&self, kind:node::Kind) -> FallibleResult<Node> {
|
||||
// Removing operands is possible only when chain has at least 3 of them
|
||||
// (target and two arguments).
|
||||
let removable = self.args.len() >= 2;
|
||||
let node_and_offset = match &self.target {
|
||||
Some(target) =>
|
||||
target.arg.generate_node(node::Kind::Target {removable}).map(|n| (n,target.offset)),
|
||||
let is_removable = self.args.len() >= 2;
|
||||
let node_and_offset:FallibleResult<(Node,usize)> = match &self.target {
|
||||
Some(target) => {
|
||||
let node = target.arg.generate_node(node::Kind::Target {is_removable})?;
|
||||
Ok((node,target.offset))
|
||||
},
|
||||
None => Ok((Node::new_empty(InsertType::BeforeTarget),0)),
|
||||
};
|
||||
|
||||
@ -151,7 +164,8 @@ impl SpanTreeGenerator for ast::opr::Chain {
|
||||
let arg_crumbs = elem.crumb_to_operand(has_left);
|
||||
let arg_ast = Located::new(arg_crumbs,operand.arg.clone_ref());
|
||||
gen.spacing(operand.offset);
|
||||
gen.generate_ast_node(arg_ast,node::Kind::Argument {removable})?;
|
||||
|
||||
gen.generate_ast_node(arg_ast,node::Kind::Argument {is_removable})?;
|
||||
}
|
||||
gen.generate_empty_node(InsertType::Append);
|
||||
|
||||
@ -176,14 +190,14 @@ impl SpanTreeGenerator for ast::prefix::Chain {
|
||||
fn generate_node(&self, kind:node::Kind) -> FallibleResult<Node> {
|
||||
use ast::crumbs::PrefixCrumb::*;
|
||||
// Removing arguments is possible if there at least two of them
|
||||
let removable = self.args.len() >= 2;
|
||||
let node = self.func.generate_node(node::Kind::Operation);
|
||||
let is_removable = self.args.len() >= 2;
|
||||
let node = self.func.generate_node(node::Kind::Operation);
|
||||
self.args.iter().enumerate().fold(node, |node,(i,arg)| {
|
||||
let node = node?;
|
||||
let is_first = i == 0;
|
||||
let is_last = i + 1 == self.args.len();
|
||||
let arg_kind = if is_first { node::Kind::Target {removable} }
|
||||
else { node::Kind::Argument {removable} };
|
||||
let arg_kind = if is_first { node::Kind::Target {is_removable} }
|
||||
else { node::Kind::Argument {is_removable} };
|
||||
|
||||
let mut gen = ChildGenerator::default();
|
||||
gen.add_node(vec![Func.into()],node);
|
||||
@ -203,6 +217,82 @@ impl SpanTreeGenerator for ast::prefix::Chain {
|
||||
}
|
||||
|
||||
|
||||
// === Match ===
|
||||
|
||||
impl SpanTreeGenerator for ast::Match<Ast> {
|
||||
fn generate_node(&self, kind:node::Kind) -> FallibleResult<Node> {
|
||||
let is_removable = false;
|
||||
let children_kind = node::Kind::Argument {is_removable};
|
||||
let mut gen = ChildGenerator::default();
|
||||
if let Some(pat) = &self.pfx {
|
||||
for macros::AstInPattern {ast,crumbs} in macros::all_ast_nodes_in_pattern(&pat) {
|
||||
let ast_crumb = ast::crumbs::MatchCrumb::Pfx {val:crumbs};
|
||||
let located_ast = Located::new(ast_crumb,ast.wrapped);
|
||||
gen.generate_ast_node(located_ast,children_kind)?;
|
||||
gen.spacing(ast.off);
|
||||
}
|
||||
}
|
||||
let first_segment_index = 0;
|
||||
generate_children_from_segment(&mut gen,first_segment_index,&self.segs.head)?;
|
||||
for (index,segment) in self.segs.tail.iter().enumerate() {
|
||||
gen.spacing(segment.off);
|
||||
generate_children_from_segment(&mut gen,index+1,&segment.wrapped)?;
|
||||
}
|
||||
Ok(Node {kind,
|
||||
size : gen.current_offset,
|
||||
children : gen.children,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_children_from_segment
|
||||
(gen:&mut ChildGenerator, index:usize, segment:&MacroMatchSegment<Ast>) -> FallibleResult<()> {
|
||||
let is_removable = false;
|
||||
let children_kind = node::Kind::Argument {is_removable};
|
||||
gen.spacing(segment.head.len());
|
||||
for macros::AstInPattern {ast,crumbs} in macros::all_ast_nodes_in_pattern(&segment.body) {
|
||||
gen.spacing(ast.off);
|
||||
let segment_crumb = ast::crumbs::SegmentMatchCrumb::Body {val:crumbs};
|
||||
let ast_crumb = ast::crumbs::MatchCrumb::Segs{val:segment_crumb, index};
|
||||
let located_ast = Located::new(ast_crumb,ast.wrapped);
|
||||
gen.generate_ast_node(located_ast,children_kind)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// === Ambiguous ==
|
||||
|
||||
impl SpanTreeGenerator for ast::Ambiguous<Ast> {
|
||||
fn generate_node(&self, kind:node::Kind) -> FallibleResult<Node> {
|
||||
let mut gen = ChildGenerator::default();
|
||||
let first_segment_index = 0;
|
||||
generate_children_from_abiguous_segment(&mut gen,first_segment_index,&self.segs.head)?;
|
||||
for (index,segment) in self.segs.tail.iter().enumerate() {
|
||||
gen.spacing(segment.off);
|
||||
generate_children_from_abiguous_segment(&mut gen, index+1, &segment.wrapped)?;
|
||||
}
|
||||
Ok(Node{kind,
|
||||
size : gen.current_offset,
|
||||
children : gen.children,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_children_from_abiguous_segment
|
||||
(gen:&mut ChildGenerator, index:usize, segment:&MacroAmbiguousSegment<Ast>) -> FallibleResult<()> {
|
||||
let is_removable = false;
|
||||
let children_kind = node::Kind::Argument {is_removable};
|
||||
gen.spacing(segment.head.len());
|
||||
if let Some(sast) = &segment.body {
|
||||
gen.spacing(sast.off);
|
||||
let field = ast::crumbs::AmbiguousSegmentCrumb::Body;
|
||||
let located_ast = Located::new(ast::crumbs::AmbiguousCrumb{index,field}, sast.clone_ref());
|
||||
gen.generate_ast_node(located_ast,children_kind)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
// ============
|
||||
// === Test ===
|
||||
@ -216,7 +306,10 @@ mod test {
|
||||
use crate::node::Kind::*;
|
||||
use crate::node::InsertType::*;
|
||||
|
||||
use ast::crumbs::AmbiguousCrumb;
|
||||
use ast::crumbs::AmbiguousSegmentCrumb;
|
||||
use ast::crumbs::InfixCrumb;
|
||||
use ast::crumbs::PatternMatchCrumb;
|
||||
use ast::crumbs::PrefixCrumb;
|
||||
use ast::crumbs::SectionLeftCrumb;
|
||||
use ast::crumbs::SectionRightCrumb;
|
||||
@ -229,29 +322,29 @@ mod test {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generating_span_tree() {
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("2 + foo bar - 3").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let removable = false;
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("2 + foo bar - 3").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = false;
|
||||
|
||||
let expected = TreeBuilder::new(15)
|
||||
.add_empty_child(0,BeforeTarget)
|
||||
.add_child(0,11,Target{removable},vec![InfixCrumb::LeftOperand])
|
||||
.add_child(0,11,Target{is_removable},InfixCrumb::LeftOperand)
|
||||
.add_empty_child(0,BeforeTarget)
|
||||
.add_leaf (0,1,Target{removable},vec![InfixCrumb::LeftOperand])
|
||||
.add_leaf (0,1,Target{is_removable},InfixCrumb::LeftOperand)
|
||||
.add_empty_child(1,AfterTarget)
|
||||
.add_leaf (2,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_child(4,7,Argument{removable} ,vec![InfixCrumb::RightOperand])
|
||||
.add_leaf(0,3,Operation,vec![PrefixCrumb::Func])
|
||||
.add_leaf (2,1,Operation,InfixCrumb::Operator)
|
||||
.add_child(4,7,Argument{is_removable} ,InfixCrumb::RightOperand)
|
||||
.add_leaf(0,3,Operation,PrefixCrumb::Func)
|
||||
.add_empty_child(4,BeforeTarget)
|
||||
.add_leaf(4,3,Target{removable},vec![PrefixCrumb::Arg])
|
||||
.add_leaf(4,3,Target{is_removable},PrefixCrumb::Arg)
|
||||
.add_empty_child(7,Append)
|
||||
.done()
|
||||
.add_empty_child(11,Append)
|
||||
.done()
|
||||
.add_empty_child(11,AfterTarget)
|
||||
.add_leaf(12,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_leaf(14,1,Argument{removable},vec![InfixCrumb::RightOperand])
|
||||
.add_leaf(12,1,Operation,InfixCrumb::Operator)
|
||||
.add_leaf(14,1,Argument{is_removable},InfixCrumb::RightOperand)
|
||||
.add_empty_child(15,Append)
|
||||
.build();
|
||||
|
||||
@ -260,40 +353,40 @@ mod test {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generate_span_tree_with_chains() {
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("2 + 3 + foo bar baz 13 + 5").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let removable = true;
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("2 + 3 + foo bar baz 13 + 5").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = true;
|
||||
|
||||
let expected = TreeBuilder::new(26)
|
||||
.add_child(0,22,Chained,vec![InfixCrumb::LeftOperand])
|
||||
.add_child(0,5,Chained,vec![InfixCrumb::LeftOperand])
|
||||
.add_child(0,22,Chained,InfixCrumb::LeftOperand)
|
||||
.add_child(0,5,Chained,InfixCrumb::LeftOperand)
|
||||
.add_empty_child(0,BeforeTarget)
|
||||
.add_leaf(0,1,Target{removable},vec![InfixCrumb::LeftOperand])
|
||||
.add_leaf(0,1,Target{is_removable},InfixCrumb::LeftOperand)
|
||||
.add_empty_child(1,AfterTarget)
|
||||
.add_leaf(2,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_leaf(4,1,Argument{removable},vec![InfixCrumb::RightOperand])
|
||||
.add_leaf(2,1,Operation,InfixCrumb::Operator)
|
||||
.add_leaf(4,1,Argument{is_removable},InfixCrumb::RightOperand)
|
||||
.add_empty_child(5,Append)
|
||||
.done()
|
||||
.add_leaf (6,1 ,Operation,vec![InfixCrumb::Operator])
|
||||
.add_child(8,14,Argument{removable},vec![InfixCrumb::RightOperand])
|
||||
.add_child(0,11,Chained,vec![PrefixCrumb::Func])
|
||||
.add_child(0,7,Chained,vec![PrefixCrumb::Func])
|
||||
.add_leaf(0,3,Operation,vec![PrefixCrumb::Func])
|
||||
.add_leaf (6,1 ,Operation,InfixCrumb::Operator)
|
||||
.add_child(8,14,Argument{is_removable},InfixCrumb::RightOperand)
|
||||
.add_child(0,11,Chained,PrefixCrumb::Func)
|
||||
.add_child(0,7,Chained,PrefixCrumb::Func)
|
||||
.add_leaf(0,3,Operation,PrefixCrumb::Func)
|
||||
.add_empty_child(4,BeforeTarget)
|
||||
.add_leaf(4,3,Target{removable},vec![PrefixCrumb::Arg])
|
||||
.add_leaf(4,3,Target{is_removable},PrefixCrumb::Arg)
|
||||
.add_empty_child(7,Append)
|
||||
.done()
|
||||
.add_leaf(8,3,Argument{removable},vec![PrefixCrumb::Arg])
|
||||
.add_leaf(8,3,Argument{is_removable},PrefixCrumb::Arg)
|
||||
.add_empty_child(11,Append)
|
||||
.done()
|
||||
.add_leaf(12,2,Argument{removable},vec![PrefixCrumb::Arg])
|
||||
.add_leaf(12,2,Argument{is_removable},PrefixCrumb::Arg)
|
||||
.add_empty_child(14,Append)
|
||||
.done()
|
||||
.add_empty_child(22,Append)
|
||||
.done()
|
||||
.add_leaf(23,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_leaf(25,1,Argument{removable},vec![InfixCrumb::RightOperand])
|
||||
.add_leaf(23,1,Operation,InfixCrumb::Operator)
|
||||
.add_leaf(25,1,Argument{is_removable},InfixCrumb::RightOperand)
|
||||
.add_empty_child(26,Append)
|
||||
.build();
|
||||
|
||||
@ -302,21 +395,21 @@ mod test {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generating_span_tree_from_right_assoc_operator() {
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("1,2,3").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let removable = true;
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("1,2,3").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = true;
|
||||
|
||||
let expected = TreeBuilder::new(5)
|
||||
.add_empty_child(0,Append)
|
||||
.add_leaf (0,1,Argument{removable},vec![InfixCrumb::LeftOperand])
|
||||
.add_leaf (1,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_child(2,3,Chained ,vec![InfixCrumb::RightOperand])
|
||||
.add_leaf (0,1,Argument{is_removable},InfixCrumb::LeftOperand)
|
||||
.add_leaf (1,1,Operation,InfixCrumb::Operator)
|
||||
.add_child(2,3,Chained ,InfixCrumb::RightOperand)
|
||||
.add_empty_child(0,Append)
|
||||
.add_leaf(0,1,Argument{removable},vec![InfixCrumb::LeftOperand])
|
||||
.add_leaf(1,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_leaf(0,1,Argument{is_removable},InfixCrumb::LeftOperand)
|
||||
.add_leaf(1,1,Operation,InfixCrumb::Operator)
|
||||
.add_empty_child(2,AfterTarget)
|
||||
.add_leaf(2,1,Target{removable},vec![InfixCrumb::RightOperand])
|
||||
.add_leaf(2,1,Target{is_removable},InfixCrumb::RightOperand)
|
||||
.add_empty_child(3,BeforeTarget)
|
||||
.done()
|
||||
.build();
|
||||
@ -329,31 +422,31 @@ mod test {
|
||||
let parser = Parser::new_or_panic();
|
||||
// The star makes `SectionSides` ast being one of the parameters of + chain. First + makes
|
||||
// SectionRight, and last + makes SectionLeft.
|
||||
let ast = parser.parse_line("+ * + + 2 +").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let removable = true;
|
||||
let ast = parser.parse_line("+ * + + 2 +").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = true;
|
||||
|
||||
let expected = TreeBuilder::new(11)
|
||||
.add_child(0,9,Chained,vec![SectionLeftCrumb::Arg])
|
||||
.add_child(0,5,Chained,vec![InfixCrumb::LeftOperand])
|
||||
.add_child(0,3,Chained,vec![SectionLeftCrumb::Arg])
|
||||
.add_child(0,9,Chained,SectionLeftCrumb::Arg)
|
||||
.add_child(0,5,Chained,InfixCrumb::LeftOperand)
|
||||
.add_child(0,3,Chained,SectionLeftCrumb::Arg)
|
||||
.add_empty_child(0,BeforeTarget)
|
||||
.add_leaf (0,1,Operation,vec![SectionRightCrumb::Opr])
|
||||
.add_child(2,1,Argument{removable},vec![SectionRightCrumb::Arg])
|
||||
.add_leaf (0,1,Operation,SectionRightCrumb::Opr)
|
||||
.add_child(2,1,Argument{is_removable},SectionRightCrumb::Arg)
|
||||
.add_empty_child(0,BeforeTarget)
|
||||
.add_leaf(0,1,Operation,vec![SectionSidesCrumb])
|
||||
.add_leaf(0,1,Operation,SectionSidesCrumb)
|
||||
.add_empty_child(1,Append)
|
||||
.done()
|
||||
.add_empty_child(3,Append)
|
||||
.done()
|
||||
.add_leaf(4,1,Operation,vec![SectionLeftCrumb::Opr])
|
||||
.add_leaf(4,1,Operation,SectionLeftCrumb::Opr)
|
||||
.add_empty_child(5,Append)
|
||||
.done()
|
||||
.add_leaf(6,1,Operation,vec![InfixCrumb::Operator])
|
||||
.add_leaf(8,1,Argument{removable},vec![InfixCrumb::RightOperand])
|
||||
.add_leaf(6,1,Operation,InfixCrumb::Operator)
|
||||
.add_leaf(8,1,Argument{is_removable},InfixCrumb::RightOperand)
|
||||
.add_empty_child(9,Append)
|
||||
.done()
|
||||
.add_leaf(10,1,Operation,vec![SectionLeftCrumb::Opr])
|
||||
.add_leaf(10,1,Operation,SectionLeftCrumb::Opr)
|
||||
.add_empty_child(11,Append)
|
||||
.build();
|
||||
|
||||
@ -362,22 +455,93 @@ mod test {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generating_span_tree_from_right_assoc_section() {
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line(",2,").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let removable = true;
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line(",2,").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = true;
|
||||
|
||||
let expected = TreeBuilder::new(3)
|
||||
.add_empty_child(0,Append)
|
||||
.add_leaf (0,1,Operation,vec![SectionRightCrumb::Opr])
|
||||
.add_child(1,2,Chained ,vec![SectionRightCrumb::Arg])
|
||||
.add_leaf (0,1,Operation,SectionRightCrumb::Opr)
|
||||
.add_child(1,2,Chained ,SectionRightCrumb::Arg)
|
||||
.add_empty_child(0,Append)
|
||||
.add_leaf(0,1,Argument{removable},vec![SectionLeftCrumb::Arg])
|
||||
.add_leaf(1,1,Operation,vec![SectionLeftCrumb::Opr])
|
||||
.add_leaf(0,1,Argument{is_removable},SectionLeftCrumb::Arg)
|
||||
.add_leaf(1,1,Operation,SectionLeftCrumb::Opr)
|
||||
.add_empty_child(2,BeforeTarget)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
assert_eq!(expected,tree);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generating_span_tree_from_matched_macros() {
|
||||
use PatternMatchCrumb::*;
|
||||
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("if foo then (a + b) x else ()").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = false;
|
||||
|
||||
let if_then_else_cr = vec![Seq { right: false }, Or, Build];
|
||||
let parens_cr = vec![Seq { right: false }, Or, Or, Build];
|
||||
let segment_body_crumbs = |index:usize, pattern_crumb:&Vec<PatternMatchCrumb>| {
|
||||
let val = ast::crumbs::SegmentMatchCrumb::Body {val:pattern_crumb.clone()};
|
||||
ast::crumbs::MatchCrumb::Segs {val,index}
|
||||
};
|
||||
|
||||
let expected = TreeBuilder::new(29)
|
||||
.add_leaf(3,3,Argument {is_removable},segment_body_crumbs(0,&if_then_else_cr))
|
||||
.add_child(12,9,Argument {is_removable},segment_body_crumbs(1,&if_then_else_cr))
|
||||
.add_child(0,7,Operation,PrefixCrumb::Func)
|
||||
.add_child(1,5,Argument {is_removable},segment_body_crumbs(0,&parens_cr))
|
||||
.add_empty_child(0,BeforeTarget)
|
||||
.add_leaf(0,1,Target {is_removable},InfixCrumb::LeftOperand)
|
||||
.add_empty_child(1,AfterTarget)
|
||||
.add_leaf(2,1,Operation,InfixCrumb::Operator)
|
||||
.add_leaf(4,1,Argument {is_removable},InfixCrumb::RightOperand)
|
||||
.add_empty_child(5,Append)
|
||||
.done()
|
||||
.done()
|
||||
.add_empty_child(8,BeforeTarget)
|
||||
.add_leaf(8,1,Target {is_removable},PrefixCrumb::Arg)
|
||||
.add_empty_child(9,Append)
|
||||
.done()
|
||||
.add_leaf(27,2,Argument {is_removable},segment_body_crumbs(2,&if_then_else_cr))
|
||||
.build();
|
||||
|
||||
assert_eq!(expected,tree);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generating_span_tree_from_ambiguous_macros() {
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("(4").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = false;
|
||||
let crumb = AmbiguousCrumb{index:0, field:AmbiguousSegmentCrumb::Body};
|
||||
|
||||
let expected = TreeBuilder::new(2)
|
||||
.add_leaf(1,1,Argument {is_removable},crumb)
|
||||
.build();
|
||||
|
||||
assert_eq!(expected,tree);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn generating_span_tree_for_lambda() {
|
||||
let parser = Parser::new_or_panic();
|
||||
let ast = parser.parse_line("foo a-> b + c").unwrap();
|
||||
let tree = ast.generate_tree().unwrap();
|
||||
let is_removable = false;
|
||||
|
||||
let expected = TreeBuilder::new(13)
|
||||
.add_leaf(0,3,Operation,PrefixCrumb::Func)
|
||||
.add_empty_child(4,BeforeTarget)
|
||||
.add_leaf(4,9,Target{is_removable},PrefixCrumb::Arg)
|
||||
.add_empty_child(13,Append)
|
||||
.build();
|
||||
|
||||
assert_eq!(expected,tree);
|
||||
}
|
||||
}
|
||||
|
142
gui/src/rust/ide/span-tree/src/generate/macros.rs
Normal file
142
gui/src/rust/ide/span-tree/src/generate/macros.rs
Normal file
@ -0,0 +1,142 @@
|
||||
//! A module with utilities for generating SpanTree from macros (Match and Ambiguous).
|
||||
|
||||
// TODO[ao] Duplicated with `pattern_subcrumbs` function in `ast::crumbs`, but adds information
|
||||
// about spacing. All the 'crumblike' utilities should be merged to one solution
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use ast::Ast;
|
||||
use ast::MacroPatternMatch;
|
||||
use ast::Shifted;
|
||||
use ast::crumbs::PatternMatchCrumb;
|
||||
|
||||
|
||||
|
||||
// ======================
|
||||
// === LocatedPattern ===
|
||||
// ======================
|
||||
|
||||
/// A fragment of MacroPatternMatch localized by PatternMatchCrumbs.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug)]
|
||||
pub struct LocatedPattern<'a> {
|
||||
pub pattern : &'a MacroPatternMatch<Shifted<Ast>>,
|
||||
pub crumbs : Vec<PatternMatchCrumb>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==================
|
||||
// === PatternDfs ===
|
||||
// ==================
|
||||
|
||||
/// A iterator over all nodes in MacroPatternMatch tree, traversing it with DFS algorithm.
|
||||
struct PatternDfs<'a> {
|
||||
/// The FILO queue of nodes to visit.
|
||||
to_visit: Vec<LocatedPattern<'a>>
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PatternDfs<'a> {
|
||||
type Item = LocatedPattern<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let to_return = self.to_visit.pop();
|
||||
if let Some(pattern) = &to_return {
|
||||
self.push_children_to_visit(pattern);
|
||||
}
|
||||
to_return
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PatternDfs<'a> {
|
||||
/// Create iterator which start from `root` node.
|
||||
pub fn new(root:&'a MacroPatternMatch<Shifted<Ast>>) -> Self {
|
||||
let first_to_visit = LocatedPattern {
|
||||
pattern : root,
|
||||
crumbs : vec![],
|
||||
};
|
||||
PatternDfs {
|
||||
to_visit: vec![first_to_visit],
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain all children of `pattern` and push them to `to_visit` queue.
|
||||
fn push_children_to_visit(&mut self, pattern:&LocatedPattern<'a>) {
|
||||
use ast::MacroPatternMatchRaw::*;
|
||||
match pattern.pattern.deref() {
|
||||
Except(pat) => self.push_child_to_visit(&pattern,&pat.elem,PatternMatchCrumb::Except),
|
||||
Tag(pat) => self.push_child_to_visit(&pattern,&pat.elem,PatternMatchCrumb::Tag),
|
||||
Cls(pat) => self.push_child_to_visit(&pattern,&pat.elem,PatternMatchCrumb::Cls),
|
||||
Or(pat) => self.push_child_to_visit(&pattern,&pat.elem,PatternMatchCrumb::Or),
|
||||
Seq(pat) => {
|
||||
let (left_elem,right_elem) = &pat.elem;
|
||||
self.push_child_to_visit(&pattern,left_elem ,PatternMatchCrumb::Seq{right:false});
|
||||
self.push_child_to_visit(&pattern,right_elem,PatternMatchCrumb::Seq{right:true});
|
||||
},
|
||||
Many(pat) => {
|
||||
for (index,elem) in pat.elem.iter().enumerate().rev() {
|
||||
self.push_child_to_visit(&pattern,elem,PatternMatchCrumb::Many {index});
|
||||
}
|
||||
}
|
||||
// Other patterns does not have children.
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_child_to_visit
|
||||
( &mut self
|
||||
, pattern : &LocatedPattern<'a>
|
||||
, child : &'a MacroPatternMatch<Shifted<Ast>>
|
||||
, crumb : PatternMatchCrumb
|
||||
) {
|
||||
let loc_pattern = LocatedPattern {
|
||||
pattern : child,
|
||||
crumbs : pattern.crumbs.iter().cloned().chain(std::iter::once(crumb)).collect()
|
||||
};
|
||||
self.to_visit.push(loc_pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// === Retrieving AST Nodes From Patterns ===
|
||||
// ==========================================
|
||||
|
||||
/// An AST node being inside a Match node
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug)]
|
||||
pub struct AstInPattern {
|
||||
pub ast : Shifted<Ast>,
|
||||
pub crumbs : Vec<PatternMatchCrumb>,
|
||||
}
|
||||
|
||||
/// Helper function that returns all AST nodes being on leaves of MacroPatternMatch.
|
||||
pub fn all_ast_nodes_in_pattern<'a>
|
||||
(pattern:&'a MacroPatternMatch<Shifted<Ast>>) -> impl Iterator<Item=AstInPattern> + 'a {
|
||||
use ast::MacroPatternMatchRaw::*;
|
||||
|
||||
PatternDfs::new(pattern).filter_map(|pattern| {
|
||||
let opt_ast_and_crumb = match pattern.pattern.deref() {
|
||||
Build(pat) => Some((&pat.elem,PatternMatchCrumb::Build )),
|
||||
Err(pat) => Some((&pat.elem,PatternMatchCrumb::Err )),
|
||||
Tok(pat) => Some((&pat.elem,PatternMatchCrumb::Tok )),
|
||||
Blank(pat) => Some((&pat.elem,PatternMatchCrumb::Blank )),
|
||||
Var(pat) => Some((&pat.elem,PatternMatchCrumb::Var )),
|
||||
Cons(pat) => Some((&pat.elem,PatternMatchCrumb::Cons )),
|
||||
Opr(pat) => Some((&pat.elem,PatternMatchCrumb::Opr )),
|
||||
Mod(pat) => Some((&pat.elem,PatternMatchCrumb::Mod )),
|
||||
Num(pat) => Some((&pat.elem,PatternMatchCrumb::Num )),
|
||||
Text(pat) => Some((&pat.elem,PatternMatchCrumb::Text )),
|
||||
Block(pat) => Some((&pat.elem,PatternMatchCrumb::Block )),
|
||||
Macro(pat) => Some((&pat.elem,PatternMatchCrumb::Macro )),
|
||||
Invalid(pat) => Some((&pat.elem,PatternMatchCrumb::Invalid)),
|
||||
_ => None,
|
||||
};
|
||||
opt_ast_and_crumb.map(|(ast,crumb)| {
|
||||
AstInPattern {
|
||||
ast : ast.clone(),
|
||||
crumbs : pattern.crumbs.into_iter().chain(std::iter::once(crumb)).collect()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
@ -126,24 +126,24 @@ mod tests {
|
||||
// /| / | \
|
||||
// gg-children: ()() ()() ()
|
||||
|
||||
let removable = false;
|
||||
let is_removable = false;
|
||||
let tree = TreeBuilder::new(14)
|
||||
.add_child(0,10,Chained,vec![LeftOperand])
|
||||
.add_leaf (0,3,Target{removable},vec![LeftOperand])
|
||||
.add_leaf (0,3,Target{is_removable},vec![LeftOperand])
|
||||
.add_leaf (4,1,Operation,vec![Operator])
|
||||
.add_child(6,3,Argument{removable},vec![RightOperand])
|
||||
.add_child(6,3,Argument{is_removable},vec![RightOperand])
|
||||
.add_leaf(0,1,Operation,vec![Func])
|
||||
.add_leaf(2,1,Target{removable},vec![Arg])
|
||||
.add_leaf(2,1,Target{is_removable},vec![Arg])
|
||||
.done()
|
||||
.done()
|
||||
.add_leaf (11,1,Operation,vec![Operator])
|
||||
.add_child(13,1,Chained ,vec![RightOperand])
|
||||
.add_leaf (0,3,Target{removable},vec![LeftOperand])
|
||||
.add_leaf (0,3,Target{is_removable},vec![LeftOperand])
|
||||
.add_leaf (4,1,Operation,vec![Operator])
|
||||
.add_child(6,5,Chained,vec![RightOperand])
|
||||
.add_leaf(0,1,Target{removable},vec![LeftOperand])
|
||||
.add_leaf(0,1,Target{is_removable},vec![LeftOperand])
|
||||
.add_leaf(2,1,Operation,vec![Operator])
|
||||
.add_leaf(4,1,Argument{removable},vec![RightOperand])
|
||||
.add_leaf(4,1,Argument{is_removable},vec![RightOperand])
|
||||
.done()
|
||||
.done()
|
||||
.build();
|
||||
|
@ -27,12 +27,12 @@ pub enum Kind {
|
||||
/// A node being a target (or "self") parameter of parent Infix, Section or Prefix.
|
||||
Target {
|
||||
/// Indicates if this node can be erased from SpanTree.
|
||||
removable:bool
|
||||
is_removable:bool
|
||||
},
|
||||
/// A node being a normal (not target) parameter of parent Infix, Section or Prefix.
|
||||
Argument {
|
||||
/// Indicates if this node can be erased from SpanTree.
|
||||
removable:bool
|
||||
is_removable:bool
|
||||
},
|
||||
/// A node being a placeholder for inserting new child to Prefix or Operator chain. It should
|
||||
/// have assigned span of length 0 and should not have any child.
|
||||
@ -226,14 +226,14 @@ mod test {
|
||||
fn node_lookup() {
|
||||
use ast::crumbs::InfixCrumb::*;
|
||||
|
||||
let removable = false;
|
||||
let is_removable = false;
|
||||
let tree = TreeBuilder::new(7)
|
||||
.add_leaf (0,1,Target{removable},vec![LeftOperand])
|
||||
.add_leaf (0,1,Target{is_removable},vec![LeftOperand])
|
||||
.add_leaf (1,1,Operation,vec![Operator])
|
||||
.add_child(2,5,Argument{removable},vec![RightOperand])
|
||||
.add_leaf(0,2,Target{removable},vec![LeftOperand])
|
||||
.add_child(2,5,Argument{is_removable},vec![RightOperand])
|
||||
.add_leaf(0,2,Target{is_removable},vec![LeftOperand])
|
||||
.add_leaf(3,1,Operation,vec![Operator])
|
||||
.add_leaf(4,1,Argument{removable},vec![RightOperand])
|
||||
.add_leaf(4,1,Argument{is_removable},vec![RightOperand])
|
||||
.done()
|
||||
.build();
|
||||
|
||||
@ -285,14 +285,14 @@ mod test {
|
||||
use ast::crumbs::InfixCrumb::*;
|
||||
use ast::crumbs::PrefixCrumb::*;
|
||||
|
||||
let removable = false;
|
||||
let is_removable = false;
|
||||
let tree = TreeBuilder::new(7)
|
||||
.add_leaf (0,1,Target{removable},vec![LeftOperand])
|
||||
.add_leaf (0,1,Target{is_removable},vec![LeftOperand])
|
||||
.add_empty_child(1,InsertType::AfterTarget)
|
||||
.add_leaf (1,1,Operation,vec![Operator])
|
||||
.add_child(2,5,Argument{removable},vec![RightOperand])
|
||||
.add_child(2,5,Argument{is_removable},vec![RightOperand])
|
||||
.add_leaf(0,3,Operation,vec![Func])
|
||||
.add_leaf(3,1,Target{removable},vec![Arg])
|
||||
.add_leaf(3,1,Target{is_removable},vec![Arg])
|
||||
.done()
|
||||
.build();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user