mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Remove UnqualifiedIdent
This commit is contained in:
parent
db6f80f358
commit
d73b8ca1fc
13 changed files with 35 additions and 119 deletions
|
@ -668,7 +668,7 @@ pub fn canonicalize_expr(
|
|||
|
||||
let mut rec_field_types = SendMap::default();
|
||||
|
||||
rec_field_types.insert(Lowercase::from_unqualified_ident(field), field_type.clone());
|
||||
rec_field_types.insert(Lowercase::from(*field), field_type.clone());
|
||||
|
||||
let record_type = Type::Record(rec_field_types, Box::new(ext_type));
|
||||
let record_expected = Expected::NoExpectation(record_type);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ident::UnqualifiedIdent;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
|
@ -12,18 +11,18 @@ pub struct Lowercase(Box<str>);
|
|||
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Uppercase(Box<str>);
|
||||
|
||||
impl Lowercase {
|
||||
pub fn from_unqualified_ident(ident: &UnqualifiedIdent<'_>) -> Self {
|
||||
Self(ident.as_str().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Box<str>> for Lowercase {
|
||||
fn into(self) -> Box<str> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Lowercase {
|
||||
fn from(string: &'a str) -> Self {
|
||||
Self(string.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Rather than displaying as this:
|
||||
///
|
||||
/// Lowercase("foo")
|
||||
|
|
|
@ -295,7 +295,7 @@ fn desugar_field<'a>(
|
|||
LabelOnly(loc_str) => {
|
||||
// Desugar { x } into { x: x }
|
||||
let loc_expr = Located {
|
||||
value: Var(&[], loc_str.value.as_str()),
|
||||
value: Var(&[], loc_str.value),
|
||||
region: loc_str.region,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ident::UnqualifiedIdent;
|
||||
use crate::module::ModuleName;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -41,11 +40,8 @@ impl Symbol {
|
|||
Symbol(format!("{}.{}", home, tag_name).into())
|
||||
}
|
||||
|
||||
pub fn from_module<'a>(
|
||||
module_name: &'a ModuleName<'a>,
|
||||
ident: &'a UnqualifiedIdent<'a>,
|
||||
) -> Symbol {
|
||||
Symbol(format!("{}.{}", module_name.as_str(), ident.as_str()).into())
|
||||
pub fn from_module<'a>(module_name: &'a ModuleName<'a>, ident: &'a &'a str) -> Symbol {
|
||||
Symbol(format!("{}.{}", module_name.as_str(), ident).into())
|
||||
}
|
||||
|
||||
pub fn from_qualified_ident(module_name: Box<str>, ident: Box<str>) -> Symbol {
|
||||
|
|
|
@ -130,7 +130,7 @@ fn fmt_exposes_entry<'a>(buf: &mut String<'a>, entry: &'a ExposesEntry<'a>, inde
|
|||
use crate::parse::ast::ExposesEntry::*;
|
||||
|
||||
match entry {
|
||||
Ident(ident) => buf.push_str(ident.as_str()),
|
||||
Ident(ident) => buf.push_str(ident),
|
||||
|
||||
SpaceBefore(sub_entry, spaces) => {
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
|
|
40
src/ident.rs
40
src/ident.rs
|
@ -1,45 +1,5 @@
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// An unqualified identifier, possibly capitalized.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct UnqualifiedIdent<'a>(&'a str);
|
||||
|
||||
impl<'a> Into<&'a str> for UnqualifiedIdent<'a> {
|
||||
fn into(self) -> &'a str {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Rather than displaying as this:
|
||||
///
|
||||
/// UnqualifiedIdent("foo")
|
||||
///
|
||||
/// ...instead display as this:
|
||||
///
|
||||
/// 'foo'
|
||||
impl<'a> fmt::Debug for UnqualifiedIdent<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "'{}'", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnqualifiedIdent<'a> {
|
||||
pub fn new(name: &'a str) -> Self {
|
||||
// Unqualified idents must always start with a lowercase character.
|
||||
debug_assert!(name
|
||||
.chars()
|
||||
.next()
|
||||
.expect("UnqualifiedIdent was empty")
|
||||
.is_alphabetic());
|
||||
|
||||
UnqualifiedIdent(name)
|
||||
}
|
||||
|
||||
pub fn as_str(&'a self) -> &'a str {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier, possibly fully-qualified with a module name
|
||||
/// e.g. (Http.Request from http)
|
||||
/// Parameterized on a phantom marker for whether it has been canonicalized
|
||||
|
|
|
@ -338,9 +338,9 @@ fn expose(
|
|||
match entry {
|
||||
Ident(ident) => {
|
||||
// Since this value is exposed, add it to our module's default scope.
|
||||
let symbol = Symbol::from_module(&module_name, &ident);
|
||||
let symbol = Symbol::from_module(&module_name, ident);
|
||||
|
||||
(ident.as_str().into(), (symbol, region))
|
||||
((*ident).into(), (symbol, region))
|
||||
}
|
||||
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
|
||||
// Ignore spaces.
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ident::UnqualifiedIdent;
|
||||
use crate::parse::ast::CommentOrNewline;
|
||||
use crate::region::Loc;
|
||||
use bumpalo::collections::Vec;
|
||||
|
@ -48,7 +47,7 @@ pub struct AppHeader<'a> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Exposes<'a> {
|
||||
/// e.g. `Task`
|
||||
Ident(UnqualifiedIdent<'a>),
|
||||
Ident(&'a str),
|
||||
|
||||
// Spaces
|
||||
SpaceBefore(&'a Exposes<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
@ -58,7 +57,7 @@ pub enum Exposes<'a> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Imports<'a> {
|
||||
/// e.g. `Task` or `Task.{ Task, after }`
|
||||
Ident(UnqualifiedIdent<'a>, Vec<'a, UnqualifiedIdent<'a>>),
|
||||
Ident(&'a str, Vec<'a, &'a str>),
|
||||
|
||||
// Spaces
|
||||
SpaceBefore(&'a Imports<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ident::UnqualifiedIdent;
|
||||
use crate::module::ModuleName;
|
||||
use crate::operator::CalledVia;
|
||||
use crate::operator::{BinOp, UnaryOp};
|
||||
|
@ -40,7 +39,7 @@ pub struct AppHeader<'a> {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ExposesEntry<'a> {
|
||||
/// e.g. `Task`
|
||||
Ident(UnqualifiedIdent<'a>),
|
||||
Ident(&'a str),
|
||||
|
||||
// Spaces
|
||||
SpaceBefore(&'a ExposesEntry<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
@ -125,9 +124,9 @@ pub enum Expr<'a> {
|
|||
Str(&'a str),
|
||||
BlockStr(&'a [&'a str]),
|
||||
/// Look up exactly one field on a record, e.g. (expr).foo.
|
||||
Access(&'a Expr<'a>, UnqualifiedIdent<'a>),
|
||||
Access(&'a Expr<'a>, &'a str),
|
||||
/// e.g. `.foo`
|
||||
AccessorFunction(UnqualifiedIdent<'a>),
|
||||
AccessorFunction(&'a str),
|
||||
|
||||
// Collection Literals
|
||||
List(Vec<'a, &'a Loc<Expr<'a>>>),
|
||||
|
@ -233,14 +232,10 @@ pub enum TypeAnnotation<'a> {
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum AssignedField<'a, Val> {
|
||||
// Both a label and a value, e.g. `{ name: "blah" }`
|
||||
LabeledValue(
|
||||
Loc<UnqualifiedIdent<'a>>,
|
||||
&'a [CommentOrNewline<'a>],
|
||||
&'a Loc<Val>,
|
||||
),
|
||||
LabeledValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc<Val>),
|
||||
|
||||
// A label with no value, e.g. `{ name }` (this is sugar for { name: name })
|
||||
LabelOnly(Loc<UnqualifiedIdent<'a>>),
|
||||
LabelOnly(Loc<&'a str>),
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a AssignedField<'a, Val>, &'a [CommentOrNewline<'a>]),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::collections::arena_join;
|
||||
use crate::ident::UnqualifiedIdent;
|
||||
use crate::parse::ast::{Attempting, MaybeQualified};
|
||||
use crate::parse::parser::{unexpected, unexpected_eof, ParseResult, Parser, State};
|
||||
use bumpalo::collections::string::String;
|
||||
|
@ -378,9 +377,6 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str> {
|
|||
global_tag_or_ident(|first_char| first_char.is_lowercase())
|
||||
}
|
||||
|
||||
pub fn unqualified_ident<'a>() -> impl Parser<'a, UnqualifiedIdent<'a>> {
|
||||
map!(
|
||||
global_tag_or_ident(|first_char| first_char.is_alphabetic()),
|
||||
UnqualifiedIdent::new
|
||||
)
|
||||
pub fn unqualified_ident<'a>() -> impl Parser<'a, &'a str> {
|
||||
global_tag_or_ident(|first_char| first_char.is_alphabetic())
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ pub mod problems;
|
|||
pub mod string_literal;
|
||||
pub mod type_annotation;
|
||||
|
||||
use crate::ident::UnqualifiedIdent;
|
||||
use crate::operator::{BinOp, CalledVia, UnaryOp};
|
||||
use crate::parse::ast::{AssignedField, Attempting, Def, Expr, MaybeQualified, Pattern, Spaceable};
|
||||
use crate::parse::blankspace::{
|
||||
|
@ -224,7 +223,7 @@ pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Ex
|
|||
// Wrap the previous answer in the new one, so we end up
|
||||
// with a nested Expr. That way, `foo.bar.baz` gets represented
|
||||
// in the AST as if it had been written (foo.bar).baz all along.
|
||||
value = Expr::Access(arena.alloc(value), UnqualifiedIdent::new(field));
|
||||
value = Expr::Access(arena.alloc(value), field);
|
||||
}
|
||||
|
||||
Ok((
|
||||
|
@ -1171,12 +1170,12 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
|
|||
// Wrap the previous answer in the new one, so we end up
|
||||
// with a nested Expr. That way, `foo.bar.baz` gets represented
|
||||
// in the AST as if it had been written (foo.bar).baz all along.
|
||||
answer = Expr::Access(arena.alloc(answer), UnqualifiedIdent::new(field));
|
||||
answer = Expr::Access(arena.alloc(answer), field);
|
||||
}
|
||||
|
||||
answer
|
||||
}
|
||||
Ident::AccessorFunction(string) => Expr::AccessorFunction(UnqualifiedIdent::new(string)),
|
||||
Ident::AccessorFunction(string) => Expr::AccessorFunction(string),
|
||||
Ident::Malformed(string) => Expr::MalformedIdent(string),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -827,11 +827,9 @@ macro_rules! record_field {
|
|||
'a,
|
||||
$crate::parse::ast::AssignedField<'a, _>,
|
||||
> {
|
||||
use $crate::ident::UnqualifiedIdent;
|
||||
use $crate::parse::ast::AssignedField::*;
|
||||
use $crate::parse::blankspace::{space0, space0_before};
|
||||
use $crate::parse::ident::lowercase_ident;
|
||||
use $crate::region::Located;
|
||||
|
||||
// You must have a field name, e.g. "email"
|
||||
let (loc_label, state) = loc!(lowercase_ident()).parse(arena, state)?;
|
||||
|
@ -845,30 +843,14 @@ macro_rules! record_field {
|
|||
.parse(arena, state)?;
|
||||
|
||||
let answer = match opt_loc_val {
|
||||
Some(loc_val) => LabeledValue(
|
||||
Located {
|
||||
value: UnqualifiedIdent::new(loc_label.value),
|
||||
region: loc_label.region,
|
||||
},
|
||||
spaces,
|
||||
arena.alloc(loc_val),
|
||||
),
|
||||
Some(loc_val) => LabeledValue(loc_label, spaces, arena.alloc(loc_val)),
|
||||
// If no value was provided, record it as a Var.
|
||||
// Canonicalize will know what to do with a Var later.
|
||||
None => {
|
||||
if !spaces.is_empty() {
|
||||
SpaceAfter(
|
||||
arena.alloc(LabelOnly(Located {
|
||||
value: UnqualifiedIdent::new(loc_label.value),
|
||||
region: loc_label.region,
|
||||
})),
|
||||
spaces,
|
||||
)
|
||||
SpaceAfter(arena.alloc(LabelOnly(loc_label)), spaces)
|
||||
} else {
|
||||
LabelOnly(Located {
|
||||
value: UnqualifiedIdent::new(loc_label.value),
|
||||
region: loc_label.region,
|
||||
})
|
||||
LabelOnly(loc_label)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,7 +17,6 @@ mod test_parse {
|
|||
use crate::helpers::parse_with;
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::{self, Bump};
|
||||
use roc::ident::UnqualifiedIdent;
|
||||
use roc::module::ModuleName;
|
||||
use roc::operator::BinOp::*;
|
||||
use roc::operator::CalledVia;
|
||||
|
@ -696,9 +695,8 @@ mod test_parse {
|
|||
fn basic_field() {
|
||||
let arena = Bump::new();
|
||||
let module_parts = Vec::new_in(&arena).into_bump_slice();
|
||||
let field = UnqualifiedIdent::new("field");
|
||||
let var = Var(module_parts, "rec");
|
||||
let expected = Access(arena.alloc(var), field);
|
||||
let expected = Access(arena.alloc(var), "field");
|
||||
let actual = parse_with(&arena, "rec.field");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
|
@ -708,9 +706,8 @@ mod test_parse {
|
|||
fn parenthetical_basic_field() {
|
||||
let arena = Bump::new();
|
||||
let module_parts = Vec::new_in(&arena).into_bump_slice();
|
||||
let field = UnqualifiedIdent::new("field");
|
||||
let paren_var = ParensAround(arena.alloc(Var(module_parts, "rec")));
|
||||
let expected = Access(arena.alloc(paren_var), field);
|
||||
let expected = Access(arena.alloc(paren_var), "field");
|
||||
let actual = parse_with(&arena, "(rec).field");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
|
@ -720,9 +717,8 @@ mod test_parse {
|
|||
fn parenthetical_field_qualified_var() {
|
||||
let arena = Bump::new();
|
||||
let module_parts = bumpalo::vec![in &arena; "One", "Two"].into_bump_slice();
|
||||
let field = UnqualifiedIdent::new("field");
|
||||
let paren_var = ParensAround(arena.alloc(Var(module_parts, "rec")));
|
||||
let expected = Access(arena.alloc(paren_var), field);
|
||||
let expected = Access(arena.alloc(paren_var), "field");
|
||||
let actual = parse_with(&arena, "(One.Two.rec).field");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
|
@ -732,13 +728,10 @@ mod test_parse {
|
|||
fn multiple_fields() {
|
||||
let arena = Bump::new();
|
||||
let module_parts = Vec::new_in(&arena).into_bump_slice();
|
||||
let abc = UnqualifiedIdent::new("abc");
|
||||
let def = UnqualifiedIdent::new("def");
|
||||
let ghi = UnqualifiedIdent::new("ghi");
|
||||
let var = Var(module_parts, "rec");
|
||||
let expected = Access(
|
||||
arena.alloc(Access(arena.alloc(Access(arena.alloc(var), abc)), def)),
|
||||
ghi,
|
||||
arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")),
|
||||
"ghi",
|
||||
);
|
||||
let actual = parse_with(&arena, "rec.abc.def.ghi");
|
||||
|
||||
|
@ -749,13 +742,10 @@ mod test_parse {
|
|||
fn qualified_field() {
|
||||
let arena = Bump::new();
|
||||
let module_parts = bumpalo::vec![in &arena; "One", "Two"].into_bump_slice();
|
||||
let abc = UnqualifiedIdent::new("abc");
|
||||
let def = UnqualifiedIdent::new("def");
|
||||
let ghi = UnqualifiedIdent::new("ghi");
|
||||
let var = Var(module_parts, "rec");
|
||||
let expected = Access(
|
||||
arena.alloc(Access(arena.alloc(Access(arena.alloc(var), abc)), def)),
|
||||
ghi,
|
||||
arena.alloc(Access(arena.alloc(Access(arena.alloc(var), "abc")), "def")),
|
||||
"ghi",
|
||||
);
|
||||
let actual = parse_with(&arena, "One.Two.rec.abc.def.ghi");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue