diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 2b4354d26e..ebd467954d 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -166,9 +166,9 @@ where p.build()? }; - if DEBUG { + /*if DEBUG { eprintln!("{}", program.to_source_string()); - } + }*/ morphic_lib::solve(program) } diff --git a/editor/src/editor/markup/nodes.rs b/editor/src/editor/markup/nodes.rs index 8faf0cbf4b..590fc05c5b 100644 --- a/editor/src/editor/markup/nodes.rs +++ b/editor/src/editor/markup/nodes.rs @@ -6,6 +6,7 @@ use crate::editor::ed_error::NestedNodeRequired; use crate::editor::slow_pool::MarkNodeId; use crate::editor::slow_pool::SlowPool; use crate::editor::syntax_highlight::HighlightStyle; +use crate::lang::ast::ExprId; use crate::lang::ast::RecordField; use crate::lang::{ ast::Expr2, @@ -146,6 +147,7 @@ pub const RIGHT_ACCOLADE: &str = " }"; pub const LEFT_SQUARE_BR: &str = "[ "; pub const RIGHT_SQUARE_BR: &str = " ]"; pub const COLON: &str = ": "; +pub const COMMA: &str = ", "; pub const STRING_QUOTES: &str = "\"\""; fn new_markup_node( @@ -217,21 +219,24 @@ pub fn expr2_to_markup<'a, 'b>( markup_node_pool, )]; - for (idx, node_id) in elems.iter_node_ids().enumerate() { - let sub_expr2 = env.pool.get(node_id); + let indexed_node_ids: Vec<(usize, ExprId)> = + elems.iter(env.pool).copied().enumerate().collect(); + + for (idx, node_id) in indexed_node_ids.iter() { + let sub_expr2 = env.pool.get(*node_id); children_ids.push(expr2_to_markup( arena, env, sub_expr2, - node_id, + *node_id, markup_node_pool, )); if idx + 1 < elems.len() { children_ids.push(new_markup_node( ", ".to_string(), - node_id, + *node_id, HighlightStyle::Operator, markup_node_pool, )); diff --git a/editor/src/editor/mvc/ed_update.rs b/editor/src/editor/mvc/ed_update.rs index 859f01cece..4ea9faac9d 100644 --- a/editor/src/editor/mvc/ed_update.rs +++ b/editor/src/editor/mvc/ed_update.rs @@ -13,7 +13,7 @@ use crate::editor::mvc::ed_model::EdModel; use crate::editor::mvc::ed_model::SelectedExpression; use crate::editor::mvc::int_update::start_new_int; use crate::editor::mvc::int_update::update_int; -use crate::editor::mvc::list_update::{prep_empty_list, start_new_list}; +use crate::editor::mvc::list_update::{add_blank_child, start_new_list}; use crate::editor::mvc::lookup_update::update_invalid_lookup; use crate::editor::mvc::record_update::start_new_record; use crate::editor::mvc::record_update::update_empty_record; @@ -689,7 +689,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult if prev_mark_node.get_content()? == nodes::LEFT_SQUARE_BR { if curr_mark_node.get_content()? == nodes::RIGHT_SQUARE_BR { - prep_empty_list(ed_model)?; // insert a Blank first, this results in cleaner code + add_blank_child(ed_model)?; // insert a Blank first, this results in cleaner code handle_new_char(received_char, ed_model)? } else { InputOutcome::Ignored @@ -726,12 +726,33 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult } else { InputOutcome::Ignored } + } else if *ch == ',' { + let mark_parent_id_opt = curr_mark_node.get_parent_id_opt(); + + if let Some(mark_parent_id) = mark_parent_id_opt { + let parent_ast_id = ed_model.markup_node_pool.get(mark_parent_id).get_ast_node_id(); + let parent_expr2 = ed_model.module.env.pool.get(parent_ast_id); + + match parent_expr2 { + Expr2::List { elem_var:_, elems:_} => { + add_blank_child(ed_model)? + } + Expr2::Record { record_var:_, fields:_ } => { + todo!("multiple record fields") + } + _ => { + InputOutcome::Ignored + } + } + } else { + InputOutcome::Ignored + } } else if "\"{[".contains(*ch) { let prev_mark_node = ed_model.markup_node_pool.get(prev_mark_node_id); if prev_mark_node.get_content()? == nodes::LEFT_SQUARE_BR { if curr_mark_node.get_content()? == nodes::RIGHT_SQUARE_BR { - prep_empty_list(ed_model)?; // insert a Blank first, this results in cleaner code + add_blank_child(ed_model)?; // insert a Blank first, this results in cleaner code handle_new_char(received_char, ed_model)? } else { InputOutcome::Ignored diff --git a/editor/src/editor/mvc/list_update.rs b/editor/src/editor/mvc/list_update.rs index 8533967209..ee9366f7bd 100644 --- a/editor/src/editor/mvc/list_update.rs +++ b/editor/src/editor/mvc/list_update.rs @@ -1,5 +1,5 @@ use crate::editor::ed_error::EdResult; -use crate::editor::ed_error::{MissingParent, UnexpectedASTNode, UnexpectedEmptyPoolVec}; +use crate::editor::ed_error::{MissingParent, UnexpectedASTNode}; use crate::editor::markup::attribute::Attributes; use crate::editor::markup::nodes; use crate::editor::markup::nodes::MarkupNode; @@ -7,11 +7,12 @@ use crate::editor::mvc::app_update::InputOutcome; use crate::editor::mvc::ed_model::EdModel; use crate::editor::mvc::ed_update::get_node_context; use crate::editor::mvc::ed_update::NodeContext; +use crate::editor::slow_pool::MarkNodeId; use crate::editor::syntax_highlight::HighlightStyle; -use crate::lang::ast::expr2_to_string; use crate::lang::ast::Expr2; +use crate::lang::ast::{expr2_to_string, ExprId}; use crate::lang::pool::PoolVec; -use snafu::OptionExt; +use crate::ui::text::text_pos::TextPos; pub fn start_new_list(ed_model: &mut EdModel) -> EdResult { let NodeContext { @@ -89,7 +90,7 @@ pub fn start_new_list(ed_model: &mut EdModel) -> EdResult { } // insert Blank at current position for easy code reuse -pub fn prep_empty_list(ed_model: &mut EdModel) -> EdResult { +pub fn add_blank_child(ed_model: &mut EdModel) -> EdResult { let NodeContext { old_caret_pos, curr_mark_node_id, @@ -98,67 +99,117 @@ pub fn prep_empty_list(ed_model: &mut EdModel) -> EdResult { ast_node_id, } = get_node_context(&ed_model)?; - let blank_elt = Expr2::Blank; + let trip_result: EdResult<(ExprId, usize, ExprId, MarkNodeId)> = + if let Some(parent_id) = parent_id_opt { + let parent = ed_model.markup_node_pool.get(parent_id); - let list_ast_node = ed_model.module.env.pool.get(ast_node_id); + let new_child_index = parent.get_children_ids().len() - 1; // TODO support adding child at place other than end - match list_ast_node { - Expr2::List { elem_var, elems: _ } => { - let children: Vec = vec![blank_elt]; - let children_pool_vec = PoolVec::new(children.into_iter(), ed_model.module.env.pool); + let list_ast_node_id = parent.get_ast_node_id(); + let list_ast_node = ed_model.module.env.pool.get(list_ast_node_id); - let blank_elt_id = - children_pool_vec - .iter_node_ids() - .next() - .context(UnexpectedEmptyPoolVec { - descriptive_vec_name: "\"children of List AST node\"", - })?; + match list_ast_node { + Expr2::List { + elem_var: _, + elems: _, + } => { + let blank_elt = Expr2::Blank; + let blank_elt_id = ed_model.module.env.pool.add(blank_elt); - let new_list_node = Expr2::List { - elem_var: *elem_var, - elems: children_pool_vec, - }; - - ed_model.module.env.pool.set(ast_node_id, new_list_node); - - let blank_mark_node = MarkupNode::Blank { - ast_node_id: blank_elt_id, - syn_high_style: HighlightStyle::Blank, - attributes: Attributes::new(), - parent_id_opt, - }; - - let blank_mark_node_id = ed_model.markup_node_pool.add(blank_mark_node); - - // add blank mark node to nested mark node from list - if let Some(parent_id) = parent_id_opt { - let parent = ed_model.markup_node_pool.get_mut(parent_id); - - let new_child_index = 1; // 1 because left bracket is first element - - parent.add_child_at_index(new_child_index, blank_mark_node_id)?; - } else { - MissingParent { - node_id: curr_mark_node_id, + Ok((blank_elt_id, new_child_index, list_ast_node_id, parent_id)) } - .fail()? + _ => UnexpectedASTNode { + required_node_type: "List".to_string(), + encountered_node_type: expr2_to_string(ast_node_id, ed_model.module.env.pool), + } + .fail(), } + } else { + MissingParent { + node_id: curr_mark_node_id, + } + .fail() + }; - // update GridNodeMap and CodeLines - ed_model.insert_between_line( - old_caret_pos.line, - old_caret_pos.column, - nodes::BLANK_PLACEHOLDER, - blank_mark_node_id, - )?; + let (blank_elt_id, new_child_index, list_ast_node_id, parent_id) = trip_result?; - Ok(InputOutcome::Accepted) - } - _ => UnexpectedASTNode { - required_node_type: "List".to_string(), - encountered_node_type: expr2_to_string(ast_node_id, ed_model.module.env.pool), - } - .fail()?, + let new_mark_children = make_mark_children( + new_child_index, + blank_elt_id, + list_ast_node_id, + old_caret_pos, + parent_id_opt, + ed_model, + )?; + + let parent = ed_model.markup_node_pool.get_mut(parent_id); + + for (indx, child) in new_mark_children.iter().enumerate() { + parent.add_child_at_index(new_child_index + indx, *child)?; } + + //TODO add ast children + + Ok(InputOutcome::Accepted) +} + +pub fn make_mark_children( + new_child_index: usize, + blank_elt_id: ExprId, + list_ast_node_id: ExprId, + old_caret_pos: TextPos, + parent_id_opt: Option, + ed_model: &mut EdModel, +) -> EdResult> { + let blank_mark_node = MarkupNode::Blank { + ast_node_id: blank_elt_id, + syn_high_style: HighlightStyle::Blank, + attributes: Attributes::new(), + parent_id_opt, + }; + + let blank_mark_node_id = ed_model.markup_node_pool.add(blank_mark_node); + + let mut children: Vec = vec![]; + + if new_child_index > 1 { + let comma_mark_node = MarkupNode::Text { + content: nodes::COMMA.to_owned(), + ast_node_id: list_ast_node_id, + syn_high_style: HighlightStyle::Blank, + attributes: Attributes::new(), + parent_id_opt, + }; + + let comma_mark_node_id = ed_model.markup_node_pool.add(comma_mark_node); + + ed_model.simple_move_carets_right(nodes::COMMA.len()); + + ed_model.insert_between_line( + old_caret_pos.line, + old_caret_pos.column, + nodes::COMMA, + comma_mark_node_id, + )?; + + children.push(comma_mark_node_id); + } + + children.push(blank_mark_node_id); + + let comma_shift = if new_child_index == 1 { + 0 + } else { + nodes::COMMA.len() + }; + + // update GridNodeMap and CodeLines + ed_model.insert_between_line( + old_caret_pos.line, + old_caret_pos.column + comma_shift, + nodes::BLANK_PLACEHOLDER, + blank_mark_node_id, + )?; + + Ok(children) } diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index 4b95b1dc62..1e3cba1495 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -114,8 +114,8 @@ pub enum Expr2 { InvalidLookup(PoolStr), // 8B List { - elem_var: Variable, // 4B - elems: PoolVec, // 8B + elem_var: Variable, // 4B + elems: PoolVec, // 8B }, If { cond_var: Variable, // 4B @@ -438,13 +438,15 @@ fn expr2_to_string_helper( let mut first_elt = true; - for elem_expr2 in elems.iter(pool) { + for elem_expr2_id in elems.iter(pool) { if !first_elt { out_string.push_str(", ") } else { first_elt = false; } + let elem_expr2 = pool.get(*elem_expr2_id); + expr2_to_string_helper(elem_expr2, indent_level + 2, pool, out_string) } diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 106eea2f1f..f2ad95ed81 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -1,7 +1,7 @@ use bumpalo::{collections::Vec as BumpVec, Bump}; use crate::lang::{ - ast::{Expr2, RecordField, WhenBranch}, + ast::{Expr2, ExprId, RecordField, WhenBranch}, expr::Env, pattern::{DestructType, Pattern2, PatternState2, RecordDestruct}, pool::{Pool, PoolStr, PoolVec, ShallowClone}, @@ -131,7 +131,10 @@ pub fn constrain_expr<'a>( let list_elem_type = Type2::Variable(*elem_var); - for (index, elem_node_id) in elems.iter_node_ids().enumerate() { + let indexed_node_ids: Vec<(usize, ExprId)> = + elems.iter(env.pool).copied().enumerate().collect(); + + for (index, elem_node_id) in indexed_node_ids { let elem_expr = env.pool.get(elem_node_id); let elem_expected = Expected::ForReason( diff --git a/editor/src/lang/expr.rs b/editor/src/lang/expr.rs index 2a9626bd5b..54843e2576 100644 --- a/editor/src/lang/expr.rs +++ b/editor/src/lang/expr.rs @@ -19,6 +19,7 @@ use roc_module::low_level::LowLevel; use roc_module::operator::CalledVia; use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol}; use roc_parse::ast; +use roc_parse::ast::Expr; use roc_parse::ast::StrLiteral; use roc_parse::parser::{loc, Parser, State, SyntaxError}; use roc_problem::can::{Problem, RuntimeError}; @@ -337,12 +338,18 @@ pub fn to_expr2<'a>( let elems = PoolVec::with_capacity(items.len() as u32, env.pool); - for (node_id, item) in elems.iter_node_ids().zip(items.iter()) { + let node_id_item_tups: Vec<(ExprId, &Located)> = elems + .iter(env.pool) + .map(|node_ref| *node_ref) + .zip(items.iter().map(|item_ref| *item_ref)) + .collect(); + + for (node_id, item) in node_id_item_tups.iter() { let (expr, sub_output) = to_expr2(env, scope, &item.value, item.region); output_ref.union(sub_output); - env.pool[node_id] = expr; + env.pool.set(*node_id, expr); } let expr = Expr2::List {