From 8944fbbb1f154096336a9a32619702794fc92568 Mon Sep 17 00:00:00 2001 From: T6 Date: Sat, 4 Jan 2025 15:06:54 -0500 Subject: [PATCH] vine: module system enhancements (#160) --- tests/programs/aoc_2024/day_02.vi | 2 +- tests/programs/aoc_2024/day_03.vi | 2 +- tests/programs/aoc_2024/day_04.vi | 2 +- tests/programs/aoc_2024/day_05.vi | 2 +- tests/programs/aoc_2024/day_06.vi | 2 +- tests/programs/aoc_2024/day_07.vi | 2 +- tests/programs/aoc_2024/day_08.vi | 2 +- tests/programs/aoc_2024/day_09.vi | 4 +-- tests/programs/aoc_2024/day_10.vi | 2 +- tests/programs/aoc_2024/day_11.vi | 4 +-- tests/programs/aoc_2024/day_12.vi | 2 +- tests/programs/aoc_2024/day_13.vi | 2 +- tests/programs/aoc_2024/day_14.vi | 2 +- tests/programs/aoc_2024/day_15.vi | 4 +-- tests/programs/aoc_2024/day_16.vi | 4 +-- tests/programs/aoc_2024/day_17.vi | 2 +- tests/programs/aoc_2024/day_18.vi | 2 +- tests/programs/aoc_2024/day_19.vi | 4 +-- tests/programs/aoc_2024/day_20.vi | 2 +- tests/programs/aoc_2024/day_21.vi | 4 +-- tests/programs/aoc_2024/day_22.vi | 6 ++-- tests/programs/aoc_2024/day_23.vi | 2 +- tests/programs/aoc_2024/day_24.vi | 2 +- tests/programs/aoc_2024/day_25.vi | 2 +- tests/programs/fmt/uses.vi | 1 + tests/programs/option_party.vi | 2 +- tests/programs/verbose_add.vi | 2 +- tests/snaps/vine/fail/hallo_world.txt | 6 ++-- tests/snaps/vine/fail/visibility.txt | 6 ++-- tests/snaps/vine/fmt/uses.fmt.vi | 2 ++ tests/tests.rs | 1 + vine/examples/fib_repl.vi | 2 +- vine/examples/guessing_game.vi | 2 +- vine/examples/primeness.vi | 2 +- vine/examples/sub_min.vi | 2 +- vine/src/ast.rs | 15 +++++--- vine/src/fmt.rs | 30 +++++++++++----- vine/src/lexer.rs | 2 ++ vine/src/parser.rs | 50 ++++++++++++++++++++------- vine/src/resolver/build_graph.rs | 35 +++++++++---------- vine/src/resolver/resolve_path.rs | 12 +++---- vine/std/array.vi | 2 +- vine/std/io.vi | 2 +- vine/std/list.vi | 2 +- vine/std/map.vi | 2 +- vine/std/n32.vi | 2 +- vine/std/n64.vi | 2 +- vine/std/std.vi | 2 +- 48 files changed, 147 insertions(+), 103 deletions(-) create mode 100644 tests/programs/fmt/uses.vi create mode 100644 tests/snaps/vine/fmt/uses.fmt.vi diff --git a/tests/programs/aoc_2024/day_02.vi b/tests/programs/aoc_2024/day_02.vi index 3405ec01..3c68d0e0 100644 --- a/tests/programs/aoc_2024/day_02.vi +++ b/tests/programs/aoc_2024/day_02.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}}; +use std::{option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_03.vi b/tests/programs/aoc_2024/day_03.vi index 3870d197..645bbf58 100644 --- a/tests/programs/aoc_2024/day_03.vi +++ b/tests/programs/aoc_2024/day_03.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}}; +use std::{option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_04.vi b/tests/programs/aoc_2024/day_04.vi index c9ac55e5..61bbfa16 100644 --- a/tests/programs/aoc_2024/day_04.vi +++ b/tests/programs/aoc_2024/day_04.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}}; +use std::{option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let lines = []; diff --git a/tests/programs/aoc_2024/day_05.vi b/tests/programs/aoc_2024/day_05.vi index e386b1f7..aab3e1e6 100644 --- a/tests/programs/aoc_2024/day_05.vi +++ b/tests/programs/aoc_2024/day_05.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}}; +use std::{option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let masks = List::new(100, ((0, 0), (0, 0))); diff --git a/tests/programs/aoc_2024/day_06.vi b/tests/programs/aoc_2024/day_06.vi index bf978ae8..8db73bf5 100644 --- a/tests/programs/aoc_2024/day_06.vi +++ b/tests/programs/aoc_2024/day_06.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, array::Array}; +use std::{array::Array, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_07.vi b/tests/programs/aoc_2024/day_07.vi index 8d61f411..21bebcf7 100644 --- a/tests/programs/aoc_2024/day_07.vi +++ b/tests/programs/aoc_2024/day_07.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, n64::N64}; +use std::{n64::N64, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let part1 = N64::from_n32(0); diff --git a/tests/programs/aoc_2024/day_08.vi b/tests/programs/aoc_2024/day_08.vi index d3b8d948..baa947cf 100644 --- a/tests/programs/aoc_2024/day_08.vi +++ b/tests/programs/aoc_2024/day_08.vi @@ -1,5 +1,5 @@ -use std::{option::Option::Some, map::{Map, Cmp, Ord}, tuple::Pair}; +use std::{map::{Cmp, Map, Ord}, option::Option::Some, tuple::Pair}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_09.vi b/tests/programs/aoc_2024/day_09.vi index ea0f2fe9..26c46365 100644 --- a/tests/programs/aoc_2024/day_09.vi +++ b/tests/programs/aoc_2024/day_09.vi @@ -1,8 +1,8 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, n64::N64, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, tuple::Pair, }; diff --git a/tests/programs/aoc_2024/day_10.vi b/tests/programs/aoc_2024/day_10.vi index 8ac04700..b32b2da6 100644 --- a/tests/programs/aoc_2024/day_10.vi +++ b/tests/programs/aoc_2024/day_10.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}}; +use std::{option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_11.vi b/tests/programs/aoc_2024/day_11.vi index 77bed286..244d8e2e 100644 --- a/tests/programs/aoc_2024/day_11.vi +++ b/tests/programs/aoc_2024/day_11.vi @@ -1,9 +1,9 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, map::Map, n64::N64, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, }; const max: N32 = 75; diff --git a/tests/programs/aoc_2024/day_12.vi b/tests/programs/aoc_2024/day_12.vi index f5bb248e..bc7f80ce 100644 --- a/tests/programs/aoc_2024/day_12.vi +++ b/tests/programs/aoc_2024/day_12.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, array::Array}; +use std::{array::Array, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let regions = Regions(Array::empty); diff --git a/tests/programs/aoc_2024/day_13.vi b/tests/programs/aoc_2024/day_13.vi index fd006872..89554baa 100644 --- a/tests/programs/aoc_2024/day_13.vi +++ b/tests/programs/aoc_2024/day_13.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, n64::N64}; +use std::{n64::N64, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_14.vi b/tests/programs/aoc_2024/day_14.vi index d39be287..f9a8d83a 100644 --- a/tests/programs/aoc_2024/day_14.vi +++ b/tests/programs/aoc_2024/day_14.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, array::Array}; +use std::{array::Array, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; const width: N32 = 11; const height: N32 = 7; diff --git a/tests/programs/aoc_2024/day_15.vi b/tests/programs/aoc_2024/day_15.vi index 1dbbd09e..d8dee7ed 100644 --- a/tests/programs/aoc_2024/day_15.vi +++ b/tests/programs/aoc_2024/day_15.vi @@ -1,8 +1,8 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, array::Array, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, tuple::Pair, }; diff --git a/tests/programs/aoc_2024/day_16.vi b/tests/programs/aoc_2024/day_16.vi index 7b428206..a5620cd8 100644 --- a/tests/programs/aoc_2024/day_16.vi +++ b/tests/programs/aoc_2024/day_16.vi @@ -1,9 +1,9 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, array::Array, map::Map, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, }; pub fn main(&io: &IO) { diff --git a/tests/programs/aoc_2024/day_17.vi b/tests/programs/aoc_2024/day_17.vi index 54d05027..e6065104 100644 --- a/tests/programs/aoc_2024/day_17.vi +++ b/tests/programs/aoc_2024/day_17.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, array::Array}; +use std::{array::Array, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let input = io.full_input(); diff --git a/tests/programs/aoc_2024/day_18.vi b/tests/programs/aoc_2024/day_18.vi index 45418c5e..2258d5d4 100644 --- a/tests/programs/aoc_2024/day_18.vi +++ b/tests/programs/aoc_2024/day_18.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, array::Array}; +use std::{array::Array, option::Option::{Option, None, Some}}; const config: (N32, N32) = (7, 12); // const config: (N32, N32) = (71, 1024); diff --git a/tests/programs/aoc_2024/day_19.vi b/tests/programs/aoc_2024/day_19.vi index 42301f39..5acea7f8 100644 --- a/tests/programs/aoc_2024/day_19.vi +++ b/tests/programs/aoc_2024/day_19.vi @@ -1,9 +1,9 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, array::Array, n64::N64, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, }; pub fn main(&io: &IO) { diff --git a/tests/programs/aoc_2024/day_20.vi b/tests/programs/aoc_2024/day_20.vi index f1915481..20351e31 100644 --- a/tests/programs/aoc_2024/day_20.vi +++ b/tests/programs/aoc_2024/day_20.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, array::Array}; +use std::{array::Array, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; const cutoff: N32 = 50; diff --git a/tests/programs/aoc_2024/day_21.vi b/tests/programs/aoc_2024/day_21.vi index 84e390e2..80d9d2e6 100644 --- a/tests/programs/aoc_2024/day_21.vi +++ b/tests/programs/aoc_2024/day_21.vi @@ -1,9 +1,9 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, array::Array, n64::N64, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, }; pub fn main(&io: &IO) { diff --git a/tests/programs/aoc_2024/day_22.vi b/tests/programs/aoc_2024/day_22.vi index 87bd0936..97912a49 100644 --- a/tests/programs/aoc_2024/day_22.vi +++ b/tests/programs/aoc_2024/day_22.vi @@ -1,9 +1,9 @@ use std::{ - option::Option::{Option, Some, None}, - result::Result::{Result, Ok, Err}, - n64::N64, map::Map, + n64::N64, + option::Option::{Option, None, Some}, + result::Result::{Result, Err, Ok}, tuple::Pair, }; diff --git a/tests/programs/aoc_2024/day_23.vi b/tests/programs/aoc_2024/day_23.vi index b39d0af5..203f2d8c 100644 --- a/tests/programs/aoc_2024/day_23.vi +++ b/tests/programs/aoc_2024/day_23.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}, map::Map}; +use std::{map::Map, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let graph = Map::new(N32::cmp); diff --git a/tests/programs/aoc_2024/day_24.vi b/tests/programs/aoc_2024/day_24.vi index 9271aa73..723181bb 100644 --- a/tests/programs/aoc_2024/day_24.vi +++ b/tests/programs/aoc_2024/day_24.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, array::Array, map::Map, n64::N64}; +use std::{array::Array, map::Map, n64::N64, option::Option::{Option, None, Some}}; pub fn main(&io: &IO) { let map = Map::new(String::cmp); diff --git a/tests/programs/aoc_2024/day_25.vi b/tests/programs/aoc_2024/day_25.vi index 83bc731a..219e6697 100644 --- a/tests/programs/aoc_2024/day_25.vi +++ b/tests/programs/aoc_2024/day_25.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, result::Result::{Result, Ok, Err}}; +use std::{option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; pub fn main(&io: &IO) { let locks = []; diff --git a/tests/programs/fmt/uses.vi b/tests/programs/fmt/uses.vi new file mode 100644 index 00000000..f7709861 --- /dev/null +++ b/tests/programs/fmt/uses.vi @@ -0,0 +1 @@ +use a::{b::c as c, b::d as D, a, f::{f}, g::{g as G}, e::e},x::y,a::h,p::{q::{}, {}} \ No newline at end of file diff --git a/tests/programs/option_party.vi b/tests/programs/option_party.vi index b670ec3b..0023dfbd 100644 --- a/tests/programs/option_party.vi +++ b/tests/programs/option_party.vi @@ -1,5 +1,5 @@ -use std::option::Option::{Option, Some, None}; +use std::option::Option::{Option, None, Some}; pub fn main(&io: &IO) { dyn fn print_option_n32(option: Option[N32]) { diff --git a/tests/programs/verbose_add.vi b/tests/programs/verbose_add.vi index 3eb0fb75..b6c20487 100644 --- a/tests/programs/verbose_add.vi +++ b/tests/programs/verbose_add.vi @@ -1,5 +1,5 @@ -use std::option::Option::{Option, Some, None}; +use std::option::Option::{Option, None, Some}; pub fn main(&io: &IO) { io.println(verbose_add(Some(1), Some(2))); diff --git a/tests/snaps/vine/fail/hallo_world.txt b/tests/snaps/vine/fail/hallo_world.txt index d007746f..2b38d7ff 100644 --- a/tests/snaps/vine/fail/hallo_world.txt +++ b/tests/snaps/vine/fail/hallo_world.txt @@ -1,6 +1,6 @@ -error tests/programs/fail/hallo_world.vi:4:3 - duplicate definition of `println` -error tests/programs/fail/hallo_world.vi:5:3 - cannot find `print_ln` in `::std::io` -error tests/programs/fail/hallo_world.vi:3:3 - cannot find `println` in `::std::io` +error tests/programs/fail/hallo_world.vi:2:1 - duplicate definition of `println` +error tests/programs/fail/hallo_world.vi:2:1 - cannot find `print_ln` in `::std::io` +error tests/programs/fail/hallo_world.vi:2:1 - cannot find `println` in `::std::io` error tests/programs/fail/hallo_world.vi:8:13 - invalid pattern; this path is not a struct or enum variant error tests/programs/fail/hallo_world.vi:9:3 - cannot find `io` in `::hallo_world::main` error tests/programs/fail/hallo_world.vi:9:14 - cannot find `hallo` in `::hallo_world::main` diff --git a/tests/snaps/vine/fail/visibility.txt b/tests/snaps/vine/fail/visibility.txt index ba9022f3..631d0ac3 100644 --- a/tests/snaps/vine/fail/visibility.txt +++ b/tests/snaps/vine/fail/visibility.txt @@ -1,8 +1,8 @@ error tests/programs/fail/visibility.vi:22:3 - subitems must be private error tests/programs/fail/visibility.vi:26:7 - invalid visibility; expected the name of an ancestor module -error tests/programs/fail/visibility.vi:27:5 - `::visibility::lib::a::b` is only visible within `::visibility::lib::a` -error tests/programs/fail/visibility.vi:28:5 - `::visibility::lib::c` is only visible within `::visibility::lib` -error tests/programs/fail/visibility.vi:29:5 - `::visibility::lib::d::e` is only visible within `::visibility::lib` +error tests/programs/fail/visibility.vi:26:3 - `::visibility::lib::a::b` is only visible within `::visibility::lib::a` +error tests/programs/fail/visibility.vi:26:3 - `::visibility::lib::c` is only visible within `::visibility::lib` +error tests/programs/fail/visibility.vi:26:3 - `::visibility::lib::d::e` is only visible within `::visibility::lib` error - `::visibility::main` is only visible within `::visibility` error tests/programs/fail/visibility.vi:21:24 - `::visibility::lib::y` is only visible within `::visibility::lib` error tests/programs/fail/visibility.vi:21:7 - `::visibility::lib::y` is only visible within `::visibility::lib` diff --git a/tests/snaps/vine/fmt/uses.fmt.vi b/tests/snaps/vine/fmt/uses.fmt.vi new file mode 100644 index 00000000..404ab87e --- /dev/null +++ b/tests/snaps/vine/fmt/uses.fmt.vi @@ -0,0 +1,2 @@ + +use {a::{a, b::{c, d as D}, e::e, f, g as G, h}, x::y}; diff --git a/tests/tests.rs b/tests/tests.rs index 1dd0d722..0820e1b6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -76,6 +76,7 @@ fn tests(t: &mut DynTester) { t.group("fmt", |t| { test_vi_fmt(t, "tests/programs/fmt/objects.vi"); + test_vi_fmt(t, "tests/programs/fmt/uses.vi"); }); t.group("fail", |t| { diff --git a/vine/examples/fib_repl.vi b/vine/examples/fib_repl.vi index a2853179..76ea1200 100644 --- a/vine/examples/fib_repl.vi +++ b/vine/examples/fib_repl.vi @@ -1,5 +1,5 @@ -use std::option::Option::{Some, None}; +use std::option::Option::{None, Some}; pub fn main(&io: &IO) { while io.prompt("> ") is Some(line) { diff --git a/vine/examples/guessing_game.vi b/vine/examples/guessing_game.vi index 2faf2f9c..b1d92482 100644 --- a/vine/examples/guessing_game.vi +++ b/vine/examples/guessing_game.vi @@ -1,5 +1,5 @@ -use std::{rng::Rng, option::Option::Some}; +use std::{option::Option::Some, rng::Rng}; pub fn main(&io: &IO) { let seed = io.prompt("Enter a seed: ").unwrap(); diff --git a/vine/examples/primeness.vi b/vine/examples/primeness.vi index e86ef7db..176f9c82 100644 --- a/vine/examples/primeness.vi +++ b/vine/examples/primeness.vi @@ -1,5 +1,5 @@ -use std::result::Result::{Result, Ok, Err}; +use std::result::Result::{Result, Err, Ok}; const end: N32 = 46; diff --git a/vine/examples/sub_min.vi b/vine/examples/sub_min.vi index eba0b277..fc640c41 100644 --- a/vine/examples/sub_min.vi +++ b/vine/examples/sub_min.vi @@ -1,5 +1,5 @@ -use std::option::Option::{Some, None}; +use std::option::Option::{None, Some}; pub fn main(&io: &IO) { let list = [4, 3, 7, 9]; diff --git a/vine/src/ast.rs b/vine/src/ast.rs index 68a7535f..e3d30e43 100644 --- a/vine/src/ast.rs +++ b/vine/src/ast.rs @@ -1,4 +1,5 @@ use std::{ + collections::BTreeMap, fmt::{self, Debug, Display, Write}, mem::take, path::PathBuf, @@ -99,11 +100,17 @@ pub struct UseItem<'core> { pub tree: UseTree<'core>, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct UseTree<'core> { - pub span: Span, - pub path: Path<'core>, - pub children: Option>>, + pub aliases: Vec>, + pub children: BTreeMap, UseTree<'core>>, +} + +impl<'core> UseTree<'core> { + pub fn prune(&mut self) -> bool { + self.children.retain(|_, tree| tree.prune()); + !self.aliases.is_empty() || !self.children.is_empty() + } } #[derive(Debug, Clone)] diff --git a/vine/src/fmt.rs b/vine/src/fmt.rs index 2baf8c5f..98b01284 100644 --- a/vine/src/fmt.rs +++ b/vine/src/fmt.rs @@ -120,7 +120,7 @@ impl<'core: 'src, 'src> Formatter<'src> { ]), ItemKind::Use(u) => Doc::concat([ Doc(if u.absolute { "use ::" } else { "use " }), - self.fmt_use_tree(&u.tree), + Self::fmt_use_tree(None, &u.tree), Doc(";"), ]), ItemKind::Ivy(_) => return self.fmt_verbatim(item.span), @@ -248,15 +248,27 @@ impl<'core: 'src, 'src> Formatter<'src> { } } - fn fmt_use_tree(&self, use_tree: &UseTree<'core>) -> Doc<'src> { - if let Some(children) = &use_tree.children { - Doc::concat([ - self.fmt_path(&use_tree.path), - Doc("::"), - Doc::brace_comma(children.iter().map(|x| self.fmt_use_tree(x))), - ]) + fn fmt_use_tree(name: Option>, tree: &UseTree<'core>) -> Doc<'src> { + let prefix = name.iter().map(|&name| Doc::concat([Doc(name), Doc("::")])); + let aliases = tree.aliases.iter().map(|&alias| { + if Some(alias) == name { + Doc(alias) + } else { + Doc::concat([Doc(name.unwrap()), Doc(" as "), Doc(alias)]) + } + }); + let children = tree.children.iter().map(|(&name, child)| Self::fmt_use_tree(Some(name), child)); + let len = aliases.len() + children.len(); + if len == 1 { + if aliases.len() == 1 { + Doc::concat(aliases) + } else { + Doc::concat(prefix.chain(children)) + } } else { - self.fmt_path(&use_tree.path) + Doc::concat( + prefix.chain([Doc::brace_comma(aliases.chain(children).collect::>().into_iter())]), + ) } } diff --git a/vine/src/lexer.rs b/vine/src/lexer.rs index 3fd9ab3c..f077e84e 100644 --- a/vine/src/lexer.rs +++ b/vine/src/lexer.rs @@ -98,6 +98,8 @@ pub enum Token { Mod, #[token("use")] Use, + #[token("as")] + As, #[token("fn")] Fn, #[token("pattern")] diff --git a/vine/src/parser.rs b/vine/src/parser.rs index ef6ff941..fcea8139 100644 --- a/vine/src/parser.rs +++ b/vine/src/parser.rs @@ -265,24 +265,48 @@ impl<'core, 'src> VineParser<'core, 'src> { fn parse_use_item(&mut self) -> Parse<'core, UseItem<'core>> { self.expect(Token::Use)?; let absolute = self.eat(Token::ColonColon)?; - let tree = self.parse_use_tree()?; - self.expect(Token::Semi)?; + let mut tree = UseTree::default(); + loop { + self.parse_use_tree(None, &mut tree)?; + if !self.eat(Token::Comma)? { + break; + } + } + tree.prune(); + self.eat(Token::Semi)?; Ok(UseItem { absolute, tree }) } - fn parse_use_tree(&mut self) -> Parse<'core, UseTree<'core>> { - let span = self.start_span(); - let mut path = Path { segments: Vec::new(), absolute: false, resolved: None }; - while self.check(Token::Ident) { - path.segments.push(self.parse_ident()?); - if !self.eat(Token::ColonColon)? { - let span = self.end_span(span); - return Ok(UseTree { span, path, children: None }); + fn parse_use_tree( + &mut self, + cur_name: Option>, + tree: &mut UseTree<'core>, + ) -> Parse<'core> { + if self.check(Token::Ident) { + let ident = self.parse_ident()?; + if cur_name == Some(ident) { + if self.eat(Token::As)? { + let alias = self.parse_ident()?; + tree.aliases.push(alias); + } else { + tree.aliases.push(ident); + } + } else { + let child = tree.children.entry(ident).or_default(); + if self.eat(Token::ColonColon)? { + let is_group = self.check(Token::OpenBrace); + self.parse_use_tree(is_group.then_some(ident), child)?; + } else if self.eat(Token::As)? { + let alias = self.parse_ident()?; + child.aliases.push(alias); + } else { + child.aliases.push(ident); + } } + } else { + self.parse_delimited(BRACE_COMMA, |self_| self_.parse_use_tree(cur_name, tree))?; } - let children = self.parse_delimited(BRACE_COMMA, Self::parse_use_tree)?; - let span = self.end_span(span); - Ok(UseTree { span, path, children: Some(children) }) + Ok(()) } fn parse_ivy_item(&mut self) -> Parse<'core, InlineIvy<'core>> { diff --git a/vine/src/resolver/build_graph.rs b/vine/src/resolver/build_graph.rs index 7255f5af..1c6e1e8c 100644 --- a/vine/src/resolver/build_graph.rs +++ b/vine/src/resolver/build_graph.rs @@ -18,7 +18,7 @@ use super::{ impl<'core> Resolver<'core> { pub fn build_graph(&mut self, root: ModKind<'core>) { - let _root_def = self.new_def(Path::ROOT, None, DefId::ROOT); + let _root_def = self.new_def(Path::ROOT, None); debug_assert_eq!(_root_def, DefId::ROOT); self.build_mod(DefId::ROOT, root, DefId::ROOT); if let Some(&prelude) = self.builtins.get(&Builtin::Prelude) { @@ -92,6 +92,7 @@ impl<'core> Resolver<'core> { ItemKind::Use(u) => { Self::build_imports( self.use_id.next(), + item.span, self.core, u.tree, &mut self.defs[parent], @@ -254,6 +255,9 @@ impl<'core> Resolver<'core> { ) -> &mut Def<'core> { let next_child = self.defs.next_index(); let parent_def = &mut self.defs[parent]; + if parent_def.canonical.segments.last() == Some(&name) { + return &mut self.defs[parent]; + } let mut new = false; let member = parent_def.members.entry(name).or_insert_with(|| { new = true; @@ -269,38 +273,36 @@ impl<'core> Resolver<'core> { member.vis = member.vis.min(vis); if new { let path = parent_def.canonical.extend(&[name]); - self.new_def(path, Some(parent), vis); + self.new_def(path, Some(parent)); } &mut self.defs[child] } fn build_imports( use_id: UseId, + span: Span, core: &Core<'core>, tree: UseTree<'core>, def: &mut Def<'core>, path: &mut Path<'core>, vis: DefId, ) { - let initial_len = path.segments.len(); - path.segments.extend(&tree.path.segments); - if let Some(children) = tree.children { - for child in children { - Self::build_imports(use_id, core, child, def, path, vis); - } - } else { - let name = *path.segments.last().unwrap(); - let path = path.clone(); + for name in tree.aliases { if let Entry::Vacant(e) = def.members.entry(name) { - e.insert(Member { vis, kind: MemberKind::UnresolvedImport(tree.span, Some(path), use_id) }); + let path = path.clone(); + e.insert(Member { vis, kind: MemberKind::UnresolvedImport(span, Some(path), use_id) }); } else { - core.report(Diag::DuplicateItem { span: tree.span, name }); + core.report(Diag::DuplicateItem { span, name }); } } - path.segments.truncate(initial_len); + for (ident, child) in tree.children { + path.segments.push(ident); + Self::build_imports(use_id, span, core, child, def, path, vis); + path.segments.pop(); + } } - fn new_def(&mut self, mut canonical: Path<'core>, parent: Option, vis: DefId) -> DefId { + fn new_def(&mut self, mut canonical: Path<'core>, parent: Option) -> DefId { let id = self.defs.next_index(); canonical.resolved = Some(id); let mut def = Def { @@ -317,9 +319,6 @@ impl<'core> Resolver<'core> { if let Some(parent) = parent { def.ancestors = self.defs[parent].ancestors.iter().copied().chain([parent]).collect(); } - if let Some(&name) = def.canonical.segments.last() { - def.members.insert(name, Member { vis, kind: MemberKind::Child(id) }); - } self.defs.push(def); id } diff --git a/vine/src/resolver/resolve_path.rs b/vine/src/resolver/resolve_path.rs index 83b02d01..eb961858 100644 --- a/vine/src/resolver/resolve_path.rs +++ b/vine/src/resolver/resolve_path.rs @@ -15,15 +15,11 @@ impl<'core> Resolver<'core> { base: DefId, path: &Path<'core>, ) -> Result> { - let base = if path.absolute { DefId::ROOT } else { base }; - let mut cur = base; + let mut cur = if path.absolute { DefId::ROOT } else { base }; for &segment in &path.segments { - let (base, vis, resolved) = - self.resolve_one(cur, segment, from == base).ok_or_else(|| Diag::CannotResolve { - span, - name: segment, - module: self.defs[cur].canonical.clone(), - })?; + let (base, vis, resolved) = self.resolve_one(cur, segment, from == cur).ok_or_else(|| { + Diag::CannotResolve { span, name: segment, module: self.defs[cur].canonical.clone() } + })?; if !self.visible(vis, from) { let mut path = self.defs[base].canonical.clone(); path.segments.push(segment); diff --git a/vine/std/array.vi b/vine/std/array.vi index a42720e2..2a238baf 100644 --- a/vine/std/array.vi +++ b/vine/std/array.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, list::Buf}; +use std::{list::Buf, option::Option::{Option, None, Some}}; pub struct Array[T](N32, Node[T]); diff --git a/vine/std/io.vi b/vine/std/io.vi index 997d5829..1eb5f436 100644 --- a/vine/std/io.vi +++ b/vine/std/io.vi @@ -1,5 +1,5 @@ -use std::{list::Buf, option::Option::{Option, Some, None}}; +use std::{list::Buf, option::Option::{Option, None, Some}}; #[builtin = "IO"] pub mod IO { diff --git a/vine/std/list.vi b/vine/std/list.vi index a0eee81d..bc8fc948 100644 --- a/vine/std/list.vi +++ b/vine/std/list.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}, map::{Cmp, Ord}, result::Result::{Result, Ok, Err}}; +use std::{map::{Cmp, Ord}, option::Option::{Option, None, Some}, result::Result::{Result, Err, Ok}}; #[builtin = "List"] pub struct List[T](N32, Buf[T], ~Buf[T]); diff --git a/vine/std/map.vi b/vine/std/map.vi index 37f397e0..b845166d 100644 --- a/vine/std/map.vi +++ b/vine/std/map.vi @@ -1,5 +1,5 @@ -use std::{option::Option::{Option, Some, None}}; +use std::option::Option::{Option, None, Some}; pub type Cmp[K] = fn(&K, &K) -> Ord; diff --git a/vine/std/n32.vi b/vine/std/n32.vi index 476357d2..2b9be31f 100644 --- a/vine/std/n32.vi +++ b/vine/std/n32.vi @@ -1,5 +1,5 @@ -use std::{list::Buf, option::Option::{Option, Some, None}, map::Ord}; +use std::{list::Buf, map::Ord, option::Option::{Option, None, Some}}; #[builtin = "N32"] pub mod N32 { diff --git a/vine/std/n64.vi b/vine/std/n64.vi index f51b9ee2..1de41127 100644 --- a/vine/std/n64.vi +++ b/vine/std/n64.vi @@ -1,5 +1,5 @@ -use std::{list::Buf, option::Option::{Option, Some, None}, map::Ord}; +use std::{list::Buf, map::Ord, option::Option::{Option, None, Some}}; pub struct N64(N32, N32); diff --git a/vine/std/std.vi b/vine/std/std.vi index 1a477f4a..7a478077 100644 --- a/vine/std/std.vi +++ b/vine/std/std.vi @@ -15,5 +15,5 @@ pub mod tuple = "./tuple.vi"; #[builtin = "prelude"] pub mod prelude { - pub use ::std::{bool::Bool, n32::N32, f32::F32, char::Char, io::IO, list::{List, String}}; + pub use ::std::{bool::Bool, char::Char, f32::F32, io::IO, list::{List, String}, n32::N32}; }