mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Merge branch 'trunk' into tag-cleanup
This commit is contained in:
commit
2bb8d0d66e
10 changed files with 482 additions and 60 deletions
|
@ -111,6 +111,26 @@ pub enum EdError {
|
|||
backtrace: Backtrace,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
"UnexpectedASTNode: required a {} at this position, node was a {}.",
|
||||
required_node_type,
|
||||
encountered_node_type
|
||||
))]
|
||||
UnexpectedASTNode {
|
||||
required_node_type: String,
|
||||
encountered_node_type: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
"UnexpectedEmptyPoolVec: expected PoolVec {} to have at least one element.",
|
||||
descriptive_vec_name
|
||||
))]
|
||||
UnexpectedEmptyPoolVec {
|
||||
descriptive_vec_name: String,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
|
||||
#[snafu(display(
|
||||
"OutOfBounds: index {} was out of bounds for {} with length {}.",
|
||||
index,
|
||||
|
@ -127,7 +147,7 @@ pub enum EdError {
|
|||
#[snafu(display("ParseError: Failed to parse AST: SyntaxError: {}.", syntax_err))]
|
||||
ParseError { syntax_err: String },
|
||||
|
||||
#[snafu(display("RecordWithoutFields: expected record to have at least one field because it is not an EmpyRecord."))]
|
||||
#[snafu(display("RecordWithoutFields: expected record to have at least one field because it is not an EmptyRecord."))]
|
||||
RecordWithoutFields { backtrace: Backtrace },
|
||||
|
||||
#[snafu(display("StringParseError: {}", msg))]
|
||||
|
|
|
@ -26,6 +26,7 @@ use bumpalo::collections::String as BumpString;
|
|||
use bumpalo::Bump;
|
||||
use cgmath::Vector2;
|
||||
use pipelines::RectResources;
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::{IdentIds, ModuleIds};
|
||||
use roc_types::subs::VarStore;
|
||||
use std::{error::Error, io, path::Path};
|
||||
|
@ -140,13 +141,18 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
|||
let mut module_ids = ModuleIds::default();
|
||||
let mod_id = module_ids.get_or_insert(&"ModId123".into());
|
||||
|
||||
let interns = Interns {
|
||||
module_ids,
|
||||
all_ident_ids: IdentIds::exposed_builtins(8),
|
||||
};
|
||||
|
||||
let env = Env::new(
|
||||
mod_id,
|
||||
&env_arena,
|
||||
&mut env_pool,
|
||||
&mut var_store,
|
||||
dep_idents,
|
||||
&module_ids,
|
||||
&interns.module_ids,
|
||||
exposed_ident_ids,
|
||||
);
|
||||
|
||||
|
@ -172,7 +178,7 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
|||
};
|
||||
|
||||
let ed_model_opt = {
|
||||
let ed_model_res = ed_model::init_model(&code_str, file_path, env, &code_arena);
|
||||
let ed_model_res = ed_model::init_model(&code_str, file_path, env, &interns, &code_arena);
|
||||
|
||||
match ed_model_res {
|
||||
Ok(mut ed_model) => {
|
||||
|
|
|
@ -143,6 +143,8 @@ fn get_string<'a>(env: &Env<'a>, pool_str: &PoolStr) -> String {
|
|||
pub const BLANK_PLACEHOLDER: &str = " ";
|
||||
pub const LEFT_ACCOLADE: &str = "{ ";
|
||||
pub const RIGHT_ACCOLADE: &str = " }";
|
||||
pub const LEFT_SQUARE_BR: &str = "[ ";
|
||||
pub const RIGHT_SQUARE_BR: &str = " ]";
|
||||
pub const COLON: &str = ": ";
|
||||
pub const STRING_QUOTES: &str = "\"\"";
|
||||
|
||||
|
@ -209,7 +211,7 @@ pub fn expr2_to_markup<'a, 'b>(
|
|||
}
|
||||
Expr2::List { elems, .. } => {
|
||||
let mut children_ids = vec![new_markup_node(
|
||||
"[ ".to_string(),
|
||||
LEFT_SQUARE_BR.to_string(),
|
||||
expr2_node_id,
|
||||
HighlightStyle::Bracket,
|
||||
markup_node_pool,
|
||||
|
@ -236,7 +238,7 @@ pub fn expr2_to_markup<'a, 'b>(
|
|||
}
|
||||
}
|
||||
children_ids.push(new_markup_node(
|
||||
"] ".to_string(),
|
||||
RIGHT_SQUARE_BR.to_string(),
|
||||
expr2_node_id,
|
||||
HighlightStyle::Bracket,
|
||||
markup_node_pool,
|
||||
|
|
|
@ -21,6 +21,7 @@ use crate::ui::ui_error::UIResult;
|
|||
use bumpalo::collections::String as BumpString;
|
||||
use bumpalo::Bump;
|
||||
use nonempty::NonEmpty;
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_region::all::Region;
|
||||
use std::path::Path;
|
||||
|
||||
|
@ -38,12 +39,13 @@ pub struct EdModel<'a> {
|
|||
pub has_focus: bool,
|
||||
pub caret_w_select_vec: NonEmpty<(CaretWSelect, Option<MarkNodeId>)>,
|
||||
pub selected_expr_opt: Option<SelectedExpression>,
|
||||
pub interns: &'a Interns, // this should eventually come from LoadedModule, see #1442
|
||||
pub show_debug_view: bool,
|
||||
// EdModel is dirty if it has changed since the previous render.
|
||||
pub dirty: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct SelectedExpression {
|
||||
pub ast_node_id: NodeId<Expr2>,
|
||||
pub mark_node_id: MarkNodeId,
|
||||
|
@ -54,6 +56,7 @@ pub fn init_model<'a>(
|
|||
code_str: &'a BumpString,
|
||||
file_path: &'a Path,
|
||||
env: Env<'a>,
|
||||
interns: &'a Interns,
|
||||
code_arena: &'a Bump,
|
||||
) -> EdResult<EdModel<'a>> {
|
||||
let mut module = EdModule::new(&code_str, env, code_arena)?;
|
||||
|
@ -99,6 +102,7 @@ pub fn init_model<'a>(
|
|||
has_focus: true,
|
||||
caret_w_select_vec: NonEmpty::new((CaretWSelect::default(), None)),
|
||||
selected_expr_opt: None,
|
||||
interns,
|
||||
show_debug_view: false,
|
||||
dirty: true,
|
||||
})
|
||||
|
@ -185,7 +189,7 @@ pub mod test_ed_model {
|
|||
use bumpalo::collections::String as BumpString;
|
||||
use bumpalo::Bump;
|
||||
use ed_model::EdModel;
|
||||
use roc_module::symbol::{IdentIds, ModuleIds};
|
||||
use roc_module::symbol::{IdentIds, Interns, ModuleIds};
|
||||
use roc_types::subs::VarStore;
|
||||
use std::path::Path;
|
||||
|
||||
|
@ -196,9 +200,11 @@ pub mod test_ed_model {
|
|||
let file_path = Path::new("");
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(8);
|
||||
|
||||
let exposed_ident_ids = IdentIds::default();
|
||||
let mod_id = ed_model_refs.module_ids.get_or_insert(&"ModId123".into());
|
||||
let mod_id = ed_model_refs
|
||||
.interns
|
||||
.module_ids
|
||||
.get_or_insert(&"ModId123".into());
|
||||
|
||||
let env = Env::new(
|
||||
mod_id,
|
||||
|
@ -206,11 +212,17 @@ pub mod test_ed_model {
|
|||
&mut ed_model_refs.env_pool,
|
||||
&mut ed_model_refs.var_store,
|
||||
dep_idents,
|
||||
&ed_model_refs.module_ids,
|
||||
&ed_model_refs.interns.module_ids,
|
||||
exposed_ident_ids,
|
||||
);
|
||||
|
||||
ed_model::init_model(&code_str, file_path, env, &ed_model_refs.code_arena)
|
||||
ed_model::init_model(
|
||||
&code_str,
|
||||
file_path,
|
||||
env,
|
||||
&ed_model_refs.interns,
|
||||
&ed_model_refs.code_arena,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct EdModelRefs {
|
||||
|
@ -218,7 +230,7 @@ pub mod test_ed_model {
|
|||
env_arena: Bump,
|
||||
env_pool: Pool,
|
||||
var_store: VarStore,
|
||||
module_ids: ModuleIds,
|
||||
interns: Interns,
|
||||
}
|
||||
|
||||
pub fn init_model_refs() -> EdModelRefs {
|
||||
|
@ -227,7 +239,10 @@ pub mod test_ed_model {
|
|||
env_arena: Bump::new(),
|
||||
env_pool: Pool::with_capacity(1024),
|
||||
var_store: VarStore::default(),
|
||||
module_ids: ModuleIds::default(),
|
||||
interns: Interns {
|
||||
module_ids: ModuleIds::default(),
|
||||
all_ident_ids: IdentIds::exposed_builtins(8),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +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::lookup_update::update_invalid_lookup;
|
||||
use crate::editor::mvc::record_update::start_new_record;
|
||||
use crate::editor::mvc::record_update::update_empty_record;
|
||||
|
@ -176,12 +177,12 @@ impl<'a> EdModel<'a> {
|
|||
|
||||
self.set_caret(expr_start_pos);
|
||||
|
||||
//let type_str = self.expr2_to_type(ast_node_id);
|
||||
let type_str = self.expr2_to_type(ast_node_id);
|
||||
|
||||
self.selected_expr_opt = Some(SelectedExpression {
|
||||
ast_node_id,
|
||||
mark_node_id,
|
||||
type_str: PoolStr::new("{}", self.module.env.pool), // TODO get this PoolStr from type inference
|
||||
type_str,
|
||||
});
|
||||
|
||||
self.dirty = true;
|
||||
|
@ -242,7 +243,7 @@ impl<'a> EdModel<'a> {
|
|||
Region::zero(),
|
||||
);
|
||||
|
||||
// extract the var_store out of the env again
|
||||
// extract the var_store out of the env
|
||||
let mut var_store = VarStore::default();
|
||||
std::mem::swap(self.module.env.var_store, &mut var_store);
|
||||
|
||||
|
@ -254,12 +255,18 @@ impl<'a> EdModel<'a> {
|
|||
var_store,
|
||||
);
|
||||
|
||||
// put the updated var_store back in env
|
||||
std::mem::swap(
|
||||
&mut VarStore::new_from_subs(solved.inner()),
|
||||
self.module.env.var_store,
|
||||
);
|
||||
|
||||
let subs = solved.inner_mut();
|
||||
|
||||
let content = subs.get(var).content;
|
||||
|
||||
PoolStr::new(
|
||||
&content_to_string(content, &subs, self.module.env.home, &Default::default()),
|
||||
&content_to_string(content, &subs, self.module.env.home, self.interns),
|
||||
self.module.env.pool,
|
||||
)
|
||||
}
|
||||
|
@ -575,11 +582,18 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
|||
'0'..='9' => {
|
||||
start_new_int(ed_model, ch)?
|
||||
}
|
||||
'[' => {
|
||||
// this can also be a tag union or become a set, assuming list for now
|
||||
start_new_list(ed_model)?
|
||||
}
|
||||
_ => InputOutcome::Ignored
|
||||
}
|
||||
} else if let Some(prev_mark_node_id) = prev_mark_node_id_opt{
|
||||
if prev_mark_node_id == curr_mark_node_id {
|
||||
match ast_node_ref {
|
||||
Expr2::SmallInt{ .. } => {
|
||||
update_int(ed_model, curr_mark_node_id, ch)?
|
||||
}
|
||||
Expr2::SmallStr(old_arr_str) => {
|
||||
update_small_string(
|
||||
&ch, old_arr_str, ed_model
|
||||
|
@ -616,9 +630,6 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
|||
InputOutcome::Ignored
|
||||
}
|
||||
}
|
||||
Expr2::SmallInt{ .. } => {
|
||||
update_int(ed_model, curr_mark_node_id, ch)?
|
||||
}
|
||||
_ => InputOutcome::Ignored
|
||||
}
|
||||
} else if ch.is_ascii_alphanumeric() { // prev_mark_node_id != curr_mark_node_id
|
||||
|
@ -637,6 +648,9 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
|||
let prev_node_ref = ed_model.module.env.pool.get(prev_ast_node_id);
|
||||
|
||||
match prev_node_ref {
|
||||
Expr2::SmallInt{ .. } => {
|
||||
update_int(ed_model, prev_mark_node_id, ch)?
|
||||
}
|
||||
Expr2::InvalidLookup(old_pool_str) => {
|
||||
update_invalid_lookup(
|
||||
&ch.to_string(),
|
||||
|
@ -670,8 +684,19 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
|||
InputOutcome::Ignored
|
||||
}
|
||||
}
|
||||
Expr2::SmallInt{ .. } => {
|
||||
update_int(ed_model, prev_mark_node_id, ch)?
|
||||
Expr2::List{ elem_var: _, elems: _} => {
|
||||
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
|
||||
handle_new_char(received_char, ed_model)?
|
||||
} else {
|
||||
InputOutcome::Ignored
|
||||
}
|
||||
} else {
|
||||
InputOutcome::Ignored
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match ast_node_ref {
|
||||
|
@ -701,6 +726,19 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
|||
} 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
|
||||
handle_new_char(received_char, ed_model)?
|
||||
} else {
|
||||
InputOutcome::Ignored
|
||||
}
|
||||
} else {
|
||||
InputOutcome::Ignored
|
||||
}
|
||||
} else {
|
||||
InputOutcome::Ignored
|
||||
}
|
||||
|
@ -1460,6 +1498,90 @@ pub mod test_ed_update {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list() -> Result<(), String> {
|
||||
assert_insert(&["┃"], &["[ ┃ ]"], '[')?;
|
||||
|
||||
assert_insert_seq(&["┃"], &["[ 0┃ ]"], "[0")?;
|
||||
assert_insert_seq(&["┃"], &["[ 1┃ ]"], "[1")?;
|
||||
assert_insert_seq(&["┃"], &["[ 9┃ ]"], "[9")?;
|
||||
|
||||
assert_insert_seq(&["┃"], &["[ \"┃\" ]"], "[\"")?;
|
||||
assert_insert_seq(
|
||||
&["┃"],
|
||||
&["[ \"hello, hello.0123456789ZXY{}[]-><-┃\" ]"],
|
||||
"[\"hello, hello.0123456789ZXY{}[]-><-",
|
||||
)?;
|
||||
|
||||
assert_insert_seq(&["┃"], &["[ { ┃ } ]"], "[{")?;
|
||||
assert_insert_seq(&["┃"], &["[ { a┃ } ]"], "[{a")?;
|
||||
assert_insert_seq(
|
||||
&["┃"],
|
||||
&["[ { camelCase: { zulu: \"nested┃\" } } ]"],
|
||||
"[{camelCase:{zulu:\"nested",
|
||||
)?;
|
||||
|
||||
assert_insert_seq(&["┃"], &["[ [ ┃ ] ]"], "[[")?;
|
||||
assert_insert_seq(&["┃"], &["[ [ [ ┃ ] ] ]"], "[[[")?;
|
||||
assert_insert_seq(&["┃"], &["[ [ 0┃ ] ]"], "[[0")?;
|
||||
assert_insert_seq(&["┃"], &["[ [ \"abc┃\" ] ]"], "[[\"abc")?;
|
||||
assert_insert_seq(
|
||||
&["┃"],
|
||||
&["[ [ { camelCase: { a: 79000┃ } } ] ]"],
|
||||
"[[{camelCase:{a:79000",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ignore_list() -> Result<(), String> {
|
||||
assert_insert_seq_ignore(&["┃[ ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ ]┃"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[┃ ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ ┃]"], IGNORE_CHARS)?;
|
||||
|
||||
assert_insert_seq_ignore(&["┃[ 0 ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ 0 ]┃"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[┃ 0 ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ 0 ┃]"], IGNORE_CHARS)?;
|
||||
|
||||
assert_insert_seq_ignore(&["┃[ 137 ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ 137 ]┃"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[┃ 137 ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ 137 ┃]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ ┃137 ]"], IGNORE_NO_NUM)?;
|
||||
assert_insert_seq_ignore(&["[ 137┃ ]"], IGNORE_NO_NUM)?;
|
||||
|
||||
assert_insert_seq_ignore(&["┃[ \"teststring\" ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ \"teststring\" ]┃"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[┃ \"teststring\" ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ \"teststring\" ┃]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ ┃\"teststring\" ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ \"teststring\"┃ ]"], IGNORE_CHARS)?;
|
||||
|
||||
assert_insert_seq_ignore(&["┃[ { a: 1 } ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ { a: 1 } ]┃"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[┃ { a: 1 } ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ { a: 1 } ┃]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ ┃{ a: 1 } ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ {┃ a: 1 } ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ { a:┃ 1 } ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ { a: 1 ┃} ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ { a: 1 }┃ ]"], IGNORE_CHARS)?;
|
||||
|
||||
assert_insert_seq_ignore(&["┃[ [ ] ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ [ ] ]┃"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[┃ [ ] ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ [ ] ┃]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ ┃[ ] ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ [ ]┃ ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ [┃ ] ]"], IGNORE_CHARS)?;
|
||||
assert_insert_seq_ignore(&["[ [ ┃] ]"], IGNORE_CHARS)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Create ed_model from pre_lines DSL, do ctrl+shift+up as many times as repeat.
|
||||
// check if modified ed_model has expected string representation of code, caret position and active selection.
|
||||
pub fn assert_ctrl_shift_up_repeat(
|
||||
|
@ -1539,6 +1661,7 @@ pub mod test_ed_update {
|
|||
|
||||
#[test]
|
||||
fn test_ctrl_shift_up_record() -> Result<(), String> {
|
||||
// TODO uncomment tests once editor::lang::constrain::constrain_expr does not contain anymore todo's
|
||||
assert_ctrl_shift_up(&["{ ┃ }"], &["┃❮{ }❯"])?;
|
||||
assert_ctrl_shift_up(&["{┃ }"], &["┃❮{ }❯"])?;
|
||||
assert_ctrl_shift_up(&["┃{ }"], &["┃❮{ }❯"])?;
|
||||
|
@ -1546,7 +1669,7 @@ pub mod test_ed_update {
|
|||
assert_ctrl_shift_up_repeat(&["{ ┃ }"], &["┃❮{ }❯"], 4)?;
|
||||
assert_ctrl_shift_up(&["{ }┃"], &["┃❮{ }❯"])?;
|
||||
|
||||
assert_ctrl_shift_up(&["{ pear┃ }"], &["┃❮{ pear }❯"])?;
|
||||
/*assert_ctrl_shift_up(&["{ pear┃ }"], &["┃❮{ pear }❯"])?;
|
||||
assert_ctrl_shift_up(&["{ pea┃r }"], &["┃❮{ pear }❯"])?;
|
||||
assert_ctrl_shift_up(&["{ p┃ear }"], &["┃❮{ pear }❯"])?;
|
||||
assert_ctrl_shift_up(&["{ ┃pear }"], &["┃❮{ pear }❯"])?;
|
||||
|
@ -1556,7 +1679,7 @@ pub mod test_ed_update {
|
|||
assert_ctrl_shift_up_repeat(&["{ pear┃ }"], &["┃❮{ pear }❯"], 3)?;
|
||||
assert_ctrl_shift_up(&["{ pear }┃"], &["┃❮{ pear }❯"])?;
|
||||
|
||||
assert_ctrl_shift_up(&["{ camelCase123┃ }"], &["┃❮{ camelCase123 }❯"])?;
|
||||
assert_ctrl_shift_up(&["{ camelCase123┃ }"], &["┃❮{ camelCase123 }❯"])?;*/
|
||||
|
||||
assert_ctrl_shift_up(&["{ a: \"┃\" }"], &["{ a: ┃❮\"\"❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ a: ┃\"\" }"], &["{ a: ┃❮\"\"❯ }"])?;
|
||||
|
@ -1614,19 +1737,20 @@ pub mod test_ed_update {
|
|||
|
||||
#[test]
|
||||
fn test_ctrl_shift_up_nested_record() -> Result<(), String> {
|
||||
// TODO uncomment tests once editor::lang::constrain::constrain_expr does not contain anymore todo's
|
||||
assert_ctrl_shift_up(&["{ abc: { ┃ } }"], &["{ abc: ┃❮{ }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: {┃ } }"], &["{ abc: ┃❮{ }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: ┃{ } }"], &["{ abc: ┃❮{ }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: { ┃} }"], &["{ abc: ┃❮{ }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: { }┃ }"], &["┃❮{ abc: { } }❯"])?;
|
||||
|
||||
assert_ctrl_shift_up(&["{ abc: { ┃d } }"], &["{ abc: ┃❮{ d }❯ }"])?;
|
||||
/*assert_ctrl_shift_up(&["{ abc: { ┃d } }"], &["{ abc: ┃❮{ d }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: {┃ d } }"], &["{ abc: ┃❮{ d }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: ┃{ d } }"], &["{ abc: ┃❮{ d }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: { d ┃} }"], &["{ abc: ┃❮{ d }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: { d┃e } }"], &["{ abc: ┃❮{ de }❯ }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: { d }┃ }"], &["┃❮{ abc: { d } }❯"])?;
|
||||
assert_ctrl_shift_up(&["┃{ abc: { d } }"], &["┃❮{ abc: { d } }❯"])?;
|
||||
assert_ctrl_shift_up(&["┃{ abc: { d } }"], &["┃❮{ abc: { d } }❯"])?;*/
|
||||
|
||||
assert_ctrl_shift_up(&["{ abc: { de: { ┃ } } }"], &["{ abc: { de: ┃❮{ }❯ } }"])?;
|
||||
assert_ctrl_shift_up(&["{ abc: { de: ┃{ } } }"], &["{ abc: { de: ┃❮{ }❯ } }"])?;
|
||||
|
@ -1697,7 +1821,7 @@ pub mod test_ed_update {
|
|||
assert_ctrl_shift_up_repeat(&["{ abc: { de: ┃55 } }"], &["┃❮{ abc: { de: 55 } }❯"], 3)?;
|
||||
assert_ctrl_shift_up_repeat(&["{ abc: { de: ┃400 } }"], &["┃❮{ abc: { de: 400 } }❯"], 4)?;
|
||||
|
||||
assert_ctrl_shift_up_repeat(
|
||||
/*assert_ctrl_shift_up_repeat(
|
||||
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase┃ } } } } } } } }"],
|
||||
&["{ g: { oi: { ng: { d: ┃❮{ e: { e: { p: { camelCase } } } }❯ } } } }"],
|
||||
4,
|
||||
|
@ -1711,16 +1835,16 @@ pub mod test_ed_update {
|
|||
&["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase┃ } } } } } } } }"],
|
||||
&["┃❮{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }❯"],
|
||||
9,
|
||||
)?;
|
||||
)?;*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Create ed_model from pre_lines DSL, do handle_new_char() with new_char_seq, select current Expr2,
|
||||
// check if generated tooltip matches expected_tooltip.
|
||||
pub fn assert_type_tooltip_seq(
|
||||
// check if generated tooltips match expected_tooltips.
|
||||
pub fn assert_type_tooltips_seq(
|
||||
pre_lines: &[&str],
|
||||
expected_tooltip: &str,
|
||||
expected_tooltips: &[&str],
|
||||
new_char_seq: &str,
|
||||
) -> Result<(), String> {
|
||||
let test_arena = Bump::new();
|
||||
|
@ -1734,14 +1858,16 @@ pub mod test_ed_update {
|
|||
ed_res_to_res(handle_new_char(&input_char, &mut ed_model))?;
|
||||
}
|
||||
|
||||
ed_model.select_expr()?;
|
||||
for expected_tooltip in expected_tooltips.iter() {
|
||||
ed_model.select_expr()?;
|
||||
|
||||
let created_tooltip = ed_model.selected_expr_opt.unwrap().type_str;
|
||||
let created_tooltip = ed_model.selected_expr_opt.unwrap().type_str;
|
||||
|
||||
assert_eq!(
|
||||
created_tooltip.as_str(ed_model.module.env.pool),
|
||||
expected_tooltip
|
||||
);
|
||||
assert_eq!(
|
||||
created_tooltip.as_str(ed_model.module.env.pool),
|
||||
*expected_tooltip
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1753,13 +1879,80 @@ pub mod test_ed_update {
|
|||
expected_tooltip: &str,
|
||||
new_char: char,
|
||||
) -> Result<(), String> {
|
||||
assert_type_tooltip_seq(pre_lines, expected_tooltip, &new_char.to_string())
|
||||
assert_type_tooltips_seq(pre_lines, &vec![expected_tooltip], &new_char.to_string())
|
||||
}
|
||||
|
||||
pub fn assert_type_tooltip_clean(lines: &[&str], expected_tooltip: &str) -> Result<(), String> {
|
||||
assert_type_tooltips_seq(lines, &vec![expected_tooltip], "")
|
||||
}
|
||||
|
||||
// When doing ctrl+shift+up multiple times we select the surrounding expression every time,
|
||||
// every new selection should have the correct tooltip
|
||||
pub fn assert_type_tooltips_clean(
|
||||
lines: &[&str],
|
||||
expected_tooltips: &[&str],
|
||||
) -> Result<(), String> {
|
||||
assert_type_tooltips_seq(lines, expected_tooltips, "")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_tooltip_record() -> Result<(), String> {
|
||||
fn test_type_tooltip() -> Result<(), String> {
|
||||
assert_type_tooltip(&["┃"], "{}", '{')?;
|
||||
|
||||
assert_type_tooltip_clean(&["┃5"], "Num *")?;
|
||||
assert_type_tooltip_clean(&["42┃"], "Num *")?;
|
||||
assert_type_tooltip_clean(&["13┃7"], "Num *")?;
|
||||
|
||||
assert_type_tooltip_clean(&["\"┃abc\""], "Str")?;
|
||||
assert_type_tooltip_clean(&["┃\"abc\""], "Str")?;
|
||||
assert_type_tooltip_clean(&["\"abc\"┃"], "Str")?;
|
||||
|
||||
assert_type_tooltip_clean(&["{ a: \"abc\" }┃"], "{ a : Str }")?;
|
||||
assert_type_tooltip_clean(&["{ ┃a: 0 }"], "{ a : Num * }")?;
|
||||
assert_type_tooltip_clean(&["{ ┃z: { } }"], "{ z : {} }")?;
|
||||
assert_type_tooltip_clean(&["{ camelCase: ┃0 }"], "Num *")?;
|
||||
|
||||
assert_type_tooltips_seq(&["┃"], &vec!["*"], "")?;
|
||||
assert_type_tooltips_seq(&["┃"], &vec!["*", "{ a : * }"], "{a:")?;
|
||||
|
||||
assert_type_tooltips_clean(
|
||||
&["{ camelCase: ┃0 }"],
|
||||
&vec!["Num *", "{ camelCase : Num * }"],
|
||||
)?;
|
||||
assert_type_tooltips_clean(
|
||||
&["{ a: { b: { c: \"hello┃, hello.0123456789ZXY{}[]-><-\" } } }"],
|
||||
&vec![
|
||||
"Str",
|
||||
"{ c : Str }",
|
||||
"{ b : { c : Str } }",
|
||||
"{ a : { b : { c : Str } } }",
|
||||
],
|
||||
)?;
|
||||
|
||||
assert_type_tooltip(&["┃"], "List *", '[')?;
|
||||
assert_type_tooltips_seq(&["┃"], &vec!["List (Num *)"], "[0")?;
|
||||
assert_type_tooltips_seq(&["┃"], &vec!["List (Num *)", "List (List (Num *))"], "[[0")?;
|
||||
assert_type_tooltips_seq(&["┃"], &vec!["Str", "List Str"], "[\"a")?;
|
||||
assert_type_tooltips_seq(
|
||||
&["┃"],
|
||||
&vec![
|
||||
"Str",
|
||||
"List Str",
|
||||
"List (List Str)",
|
||||
"List (List (List Str))",
|
||||
],
|
||||
"[[[\"a",
|
||||
)?;
|
||||
assert_type_tooltips_seq(
|
||||
&["┃"],
|
||||
&vec![
|
||||
"{ a : Num * }",
|
||||
"List { a : Num * }",
|
||||
"List (List { a : Num * })",
|
||||
],
|
||||
"[[{a:1",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1867,9 +2060,10 @@ pub mod test_ed_update {
|
|||
|
||||
#[test]
|
||||
fn test_ctrl_shift_up_move_record() -> Result<(), String> {
|
||||
// TODO uncomment tests once editor::lang::constrain::constrain_expr does not contain anymore todo's
|
||||
assert_ctrl_shift_single_up_move(&["┃{ }"], &["┃{ }"], move_home!())?;
|
||||
assert_ctrl_shift_single_up_move(&["┃{ a }"], &["{ a }┃"], move_down!())?;
|
||||
assert_ctrl_shift_single_up_move(&["┃{ a: { b } }"], &["{ a: { b } }┃"], move_right!())?;
|
||||
//assert_ctrl_shift_single_up_move(&["┃{ a }"], &["{ a }┃"], move_down!())?;
|
||||
//assert_ctrl_shift_single_up_move(&["┃{ a: { b } }"], &["{ a: { b } }┃"], move_right!())?;
|
||||
assert_ctrl_shift_single_up_move(&["{ a: { ┃ } }"], &["{ a: { } }┃"], move_end!())?;
|
||||
assert_ctrl_shift_up_move(
|
||||
&["{ a: { b: { ┃ } } }"],
|
||||
|
@ -1963,19 +2157,20 @@ pub mod test_ed_update {
|
|||
|
||||
#[test]
|
||||
fn test_ctrl_shift_up_backspace_record() -> Result<(), String> {
|
||||
// TODO uncomment tests once editor::lang::constrain::constrain_expr does not contain anymore todo's
|
||||
// Blank is inserted when root is deleted
|
||||
assert_ctrl_shift_single_up_backspace(&["{┃ }"], &["┃ "])?;
|
||||
assert_ctrl_shift_single_up_backspace(&["{ a┃ }"], &["┃ "])?;
|
||||
assert_ctrl_shift_single_up_backspace(&["{ a: { b }┃ }"], &["┃ "])?;
|
||||
//assert_ctrl_shift_single_up_backspace(&["{ a┃ }"], &["┃ "])?;
|
||||
//assert_ctrl_shift_single_up_backspace(&["{ a: { b }┃ }"], &["┃ "])?;
|
||||
assert_ctrl_shift_single_up_backspace(&["{ a: \"b cd\"┃ }"], &["┃ "])?;
|
||||
|
||||
assert_ctrl_shift_single_up_backspace(&["{ a: ┃{ b } }"], &["{ a: ┃ }"])?;
|
||||
//assert_ctrl_shift_single_up_backspace(&["{ a: ┃{ b } }"], &["{ a: ┃ }"])?;
|
||||
assert_ctrl_shift_single_up_backspace(&["{ a: \"┃b cd\" }"], &["{ a: ┃ }"])?;
|
||||
assert_ctrl_shift_single_up_backspace(&["{ a: ┃12 }"], &["{ a: ┃ }"])?;
|
||||
assert_ctrl_shift_single_up_backspace(
|
||||
/*assert_ctrl_shift_single_up_backspace(
|
||||
&["{ g: { oi: { ng: { d: { ┃e: { e: { p: { camelCase } } } } } } } }"],
|
||||
&["{ g: { oi: { ng: { d: ┃ } } } }"],
|
||||
)?;
|
||||
)?;*/
|
||||
|
||||
assert_ctrl_shift_up_backspace(
|
||||
&["{ a: { b: { c: \"abc┃ \" } } }"],
|
||||
|
@ -1988,11 +2183,11 @@ pub mod test_ed_update {
|
|||
2,
|
||||
)?;
|
||||
assert_ctrl_shift_up_backspace(&["{ a: { b: { c: {┃ } } } }"], &["{ a: { b: ┃ } }"], 2)?;
|
||||
assert_ctrl_shift_up_backspace(
|
||||
/*assert_ctrl_shift_up_backspace(
|
||||
&["{ g: { oi: { ng: { d: { e: { e: { p┃: { camelCase } } } } } } } }"],
|
||||
&["{ g: ┃ }"],
|
||||
6,
|
||||
)?;
|
||||
)?;*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
164
editor/src/editor/mvc/list_update.rs
Normal file
164
editor/src/editor/mvc/list_update.rs
Normal file
|
@ -0,0 +1,164 @@
|
|||
use crate::editor::ed_error::EdResult;
|
||||
use crate::editor::ed_error::{MissingParent, UnexpectedASTNode, UnexpectedEmptyPoolVec};
|
||||
use crate::editor::markup::attribute::Attributes;
|
||||
use crate::editor::markup::nodes;
|
||||
use crate::editor::markup::nodes::MarkupNode;
|
||||
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::syntax_highlight::HighlightStyle;
|
||||
use crate::lang::ast::expr2_to_string;
|
||||
use crate::lang::ast::Expr2;
|
||||
use crate::lang::pool::PoolVec;
|
||||
use snafu::OptionExt;
|
||||
|
||||
pub fn start_new_list(ed_model: &mut EdModel) -> EdResult<InputOutcome> {
|
||||
let NodeContext {
|
||||
old_caret_pos,
|
||||
curr_mark_node_id,
|
||||
curr_mark_node,
|
||||
parent_id_opt,
|
||||
ast_node_id,
|
||||
} = get_node_context(&ed_model)?;
|
||||
|
||||
let is_blank_node = curr_mark_node.is_blank();
|
||||
|
||||
let expr2_node = Expr2::List {
|
||||
elem_var: ed_model.module.env.var_store.fresh(),
|
||||
elems: PoolVec::empty(ed_model.module.env.pool),
|
||||
};
|
||||
|
||||
let mark_node_pool = &mut ed_model.markup_node_pool;
|
||||
|
||||
ed_model.module.env.pool.set(ast_node_id, expr2_node);
|
||||
|
||||
let left_bracket_node = MarkupNode::Text {
|
||||
content: nodes::LEFT_SQUARE_BR.to_owned(),
|
||||
ast_node_id,
|
||||
syn_high_style: HighlightStyle::Bracket,
|
||||
attributes: Attributes::new(),
|
||||
parent_id_opt: Some(curr_mark_node_id), // current node will be replaced with nested one
|
||||
};
|
||||
|
||||
let left_bracket_node_id = mark_node_pool.add(left_bracket_node);
|
||||
|
||||
let right_bracket_node = MarkupNode::Text {
|
||||
content: nodes::RIGHT_SQUARE_BR.to_owned(),
|
||||
ast_node_id,
|
||||
syn_high_style: HighlightStyle::Bracket,
|
||||
attributes: Attributes::new(),
|
||||
parent_id_opt: Some(curr_mark_node_id), // current node will be replaced with nested one
|
||||
};
|
||||
|
||||
let right_bracket_node_id = mark_node_pool.add(right_bracket_node);
|
||||
|
||||
let nested_node = MarkupNode::Nested {
|
||||
ast_node_id,
|
||||
children_ids: vec![left_bracket_node_id, right_bracket_node_id],
|
||||
parent_id_opt,
|
||||
};
|
||||
|
||||
if is_blank_node {
|
||||
mark_node_pool.replace_node(curr_mark_node_id, nested_node);
|
||||
|
||||
// remove data corresponding to Blank node
|
||||
ed_model.del_at_line(old_caret_pos.line, old_caret_pos.column)?;
|
||||
|
||||
ed_model.simple_move_carets_right(nodes::LEFT_SQUARE_BR.len());
|
||||
|
||||
// update GridNodeMap and CodeLines
|
||||
ed_model.insert_between_line(
|
||||
old_caret_pos.line,
|
||||
old_caret_pos.column,
|
||||
nodes::LEFT_SQUARE_BR,
|
||||
left_bracket_node_id,
|
||||
)?;
|
||||
|
||||
ed_model.insert_between_line(
|
||||
old_caret_pos.line,
|
||||
old_caret_pos.column + nodes::LEFT_SQUARE_BR.len(),
|
||||
nodes::RIGHT_SQUARE_BR,
|
||||
right_bracket_node_id,
|
||||
)?;
|
||||
|
||||
Ok(InputOutcome::Accepted)
|
||||
} else {
|
||||
Ok(InputOutcome::Ignored)
|
||||
}
|
||||
}
|
||||
|
||||
// insert Blank at current position for easy code reuse
|
||||
pub fn prep_empty_list(ed_model: &mut EdModel) -> EdResult<InputOutcome> {
|
||||
let NodeContext {
|
||||
old_caret_pos,
|
||||
curr_mark_node_id,
|
||||
curr_mark_node: _,
|
||||
parent_id_opt,
|
||||
ast_node_id,
|
||||
} = get_node_context(&ed_model)?;
|
||||
|
||||
let blank_elt = Expr2::Blank;
|
||||
|
||||
let list_ast_node = ed_model.module.env.pool.get(ast_node_id);
|
||||
|
||||
match list_ast_node {
|
||||
Expr2::List { elem_var, elems: _ } => {
|
||||
let children: Vec<Expr2> = vec![blank_elt];
|
||||
let children_pool_vec = PoolVec::new(children.into_iter(), ed_model.module.env.pool);
|
||||
|
||||
let blank_elt_id =
|
||||
children_pool_vec
|
||||
.iter_node_ids()
|
||||
.next()
|
||||
.context(UnexpectedEmptyPoolVec {
|
||||
descriptive_vec_name: "\"children of List AST node\"",
|
||||
})?;
|
||||
|
||||
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,
|
||||
}
|
||||
.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,
|
||||
)?;
|
||||
|
||||
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()?,
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ pub mod ed_model;
|
|||
pub mod ed_update;
|
||||
pub mod ed_view;
|
||||
mod int_update;
|
||||
mod list_update;
|
||||
mod lookup_update;
|
||||
mod record_update;
|
||||
mod string_update;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
pub const NOTHING_OPENED: &str = "Execute `cargo run edit <filename>` to open a file.";
|
||||
pub const START_TIP: &str =
|
||||
"Start by typing '{', '\"' or a number.\nInput chars that would create parse errors will be ignored.";
|
||||
"Start by typing '[', '{', '\"' or a number.\nInput chars that would create parse errors will be ignored.";
|
||||
|
|
|
@ -347,8 +347,9 @@ impl RecordField {
|
|||
|
||||
pub fn expr2_to_string(node_id: NodeId<Expr2>, pool: &Pool) -> String {
|
||||
let mut full_string = String::new();
|
||||
let expr2 = pool.get(node_id);
|
||||
|
||||
expr2_to_string_helper(node_id, 0, pool, &mut full_string);
|
||||
expr2_to_string_helper(expr2, 0, pool, &mut full_string);
|
||||
|
||||
full_string
|
||||
}
|
||||
|
@ -361,13 +362,11 @@ fn get_spacing(indent_level: usize) -> String {
|
|||
}
|
||||
|
||||
fn expr2_to_string_helper(
|
||||
node_id: NodeId<Expr2>,
|
||||
expr2: &Expr2,
|
||||
indent_level: usize,
|
||||
pool: &Pool,
|
||||
out_string: &mut String,
|
||||
) {
|
||||
let expr2 = pool.get(node_id);
|
||||
|
||||
out_string.push_str(&get_spacing(indent_level));
|
||||
|
||||
match expr2 {
|
||||
|
@ -384,11 +383,7 @@ fn expr2_to_string_helper(
|
|||
Expr2::EmptyRecord => out_string.push_str("EmptyRecord"),
|
||||
Expr2::Record { record_var, fields } => {
|
||||
out_string.push_str("Record:\n");
|
||||
out_string.push_str(&format!(
|
||||
"{}Var({:?})\n",
|
||||
get_spacing(indent_level + 1),
|
||||
record_var
|
||||
));
|
||||
out_string.push_str(&var_to_string(&record_var, indent_level + 1));
|
||||
|
||||
out_string.push_str(&format!("{}fields: [\n", get_spacing(indent_level + 1)));
|
||||
|
||||
|
@ -427,7 +422,8 @@ fn expr2_to_string_helper(
|
|||
var,
|
||||
));
|
||||
|
||||
expr2_to_string_helper(*val_node_id, indent_level + 3, pool, out_string);
|
||||
let val_expr2 = pool.get(*val_node_id);
|
||||
expr2_to_string_helper(val_expr2, indent_level + 3, pool, out_string);
|
||||
out_string.push_str(&format!("{})\n", get_spacing(indent_level + 2)));
|
||||
}
|
||||
}
|
||||
|
@ -435,6 +431,25 @@ fn expr2_to_string_helper(
|
|||
|
||||
out_string.push_str(&format!("{}]\n", get_spacing(indent_level + 1)));
|
||||
}
|
||||
Expr2::List { elem_var, elems } => {
|
||||
out_string.push_str("List:\n");
|
||||
out_string.push_str(&var_to_string(elem_var, indent_level + 1));
|
||||
out_string.push_str(&format!("{}elems: [\n", get_spacing(indent_level + 1)));
|
||||
|
||||
let mut first_elt = true;
|
||||
|
||||
for elem_expr2 in elems.iter(pool) {
|
||||
if !first_elt {
|
||||
out_string.push_str(", ")
|
||||
} else {
|
||||
first_elt = false;
|
||||
}
|
||||
|
||||
expr2_to_string_helper(elem_expr2, indent_level + 2, pool, out_string)
|
||||
}
|
||||
|
||||
out_string.push_str(&format!("{}]\n", get_spacing(indent_level + 1)));
|
||||
}
|
||||
Expr2::InvalidLookup(pool_str) => {
|
||||
out_string.push_str(&format!("InvalidLookup({})", pool_str.as_str(pool)));
|
||||
}
|
||||
|
@ -447,6 +462,10 @@ fn expr2_to_string_helper(
|
|||
out_string.push('\n');
|
||||
}
|
||||
|
||||
fn var_to_string(some_var: &Variable, indent_level: usize) -> String {
|
||||
format!("{}Var({:?})\n", get_spacing(indent_level + 1), some_var)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn size_of_expr() {
|
||||
assert_eq!(std::mem::size_of::<Expr2>(), crate::lang::pool::NODE_BYTES);
|
||||
|
|
|
@ -62,7 +62,6 @@ fn infer_eq(actual: &str, expected_str: &str) {
|
|||
let mut var_store = VarStore::default();
|
||||
let var = var_store.fresh();
|
||||
let dep_idents = IdentIds::exposed_builtins(8);
|
||||
|
||||
let exposed_ident_ids = IdentIds::default();
|
||||
let mut module_ids = ModuleIds::default();
|
||||
let mod_id = module_ids.get_or_insert(&"ModId123".into());
|
||||
|
@ -121,6 +120,7 @@ fn infer_eq(actual: &str, expected_str: &str) {
|
|||
module_ids,
|
||||
all_ident_ids: dep_idents,
|
||||
};
|
||||
|
||||
let actual_str = content_to_string(content, &subs, mod_id, &interns);
|
||||
|
||||
assert_eq!(actual_str, expected_str);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue