mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Use UppercaseIdent over PlatformRigids
This commit is contained in:
parent
620e3f2913
commit
c1c0ffb25f
10 changed files with 157 additions and 51 deletions
|
@ -12,10 +12,11 @@ use roc_parse::ast::{
|
|||
};
|
||||
use roc_parse::header::{
|
||||
AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
||||
PackageName, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
|
||||
PackageName, PlatformHeader, PlatformRequires, To, TypedIdent,
|
||||
};
|
||||
use roc_parse::{
|
||||
ast::{Def, Module},
|
||||
ident::UppercaseIdent,
|
||||
module::{self, module_defs},
|
||||
parser::{Parser, SyntaxError},
|
||||
state::State,
|
||||
|
@ -285,7 +286,7 @@ impl<'a> RemoveSpaces<'a> for PlatformRequires<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for PlatformRigid<'a> {
|
||||
impl<'a> RemoveSpaces<'a> for UppercaseIdent<'a> {
|
||||
fn remove_spaces(&self, _arena: &'a Bump) -> Self {
|
||||
*self
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
|||
Buf,
|
||||
};
|
||||
use roc_parse::ast::{AliasHeader, AssignedField, Expr, Tag, TypeAnnotation};
|
||||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
||||
/// Does an AST node need parens around it?
|
||||
|
@ -107,6 +108,22 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for UppercaseIdent<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn format_with_options<'buf>(
|
||||
&self,
|
||||
buf: &mut Buf<'buf>,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
_indent: u16,
|
||||
) {
|
||||
buf.push_str((*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for TypeAnnotation<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
use roc_parse::ast::TypeAnnotation::*;
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::Buf;
|
|||
use roc_parse::ast::{Collection, Module, Spaced};
|
||||
use roc_parse::header::{
|
||||
AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
||||
PackageName, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
|
||||
PackageName, PlatformHeader, PlatformRequires, To, TypedIdent,
|
||||
};
|
||||
use roc_region::all::Loc;
|
||||
|
||||
|
@ -206,18 +206,6 @@ impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for PlatformRigid<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn format<'buf>(&self, buf: &mut Buf<'buf>, _indent: u16) {
|
||||
buf.push_str(self.rigid);
|
||||
buf.push_str("=>");
|
||||
buf.push_str(self.alias);
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_imports<'a, 'buf>(
|
||||
buf: &mut Buf<'buf>,
|
||||
loc_entries: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ast::{Collection, CommentOrNewline, Spaced, StrLiteral, TypeAnnotation};
|
||||
use crate::blankspace::space0_e;
|
||||
use crate::ident::lowercase_ident;
|
||||
use crate::ident::{lowercase_ident, UppercaseIdent};
|
||||
use crate::parser::Progress::*;
|
||||
use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
|
||||
use crate::state::State;
|
||||
|
@ -126,15 +126,9 @@ pub struct PackageHeader<'a> {
|
|||
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct PlatformRigid<'a> {
|
||||
pub rigid: &'a str,
|
||||
pub alias: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PlatformRequires<'a> {
|
||||
pub rigids: Collection<'a, Loc<Spaced<'a, PlatformRigid<'a>>>>,
|
||||
pub rigids: Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>,
|
||||
pub signature: Loc<Spaced<'a, TypedIdent<'a>>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,23 @@ use bumpalo::collections::vec::Vec;
|
|||
use bumpalo::Bump;
|
||||
use roc_region::all::Position;
|
||||
|
||||
/// A global tag, for example. Must start with an uppercase letter
|
||||
/// and then contain only letters and numbers afterwards - no dots allowed!
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct UppercaseIdent<'a>(&'a str);
|
||||
|
||||
impl<'a> From<&'a str> for UppercaseIdent<'a> {
|
||||
fn from(string: &'a str) -> Self {
|
||||
UppercaseIdent(string)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<UppercaseIdent<'a>> for &'a str {
|
||||
fn from(ident: UppercaseIdent<'a>) -> Self {
|
||||
ident.0
|
||||
}
|
||||
}
|
||||
|
||||
/// The parser accepts all of these in any position where any one of them could
|
||||
/// appear. This way, canonicalization can give more helpful error messages like
|
||||
/// "you can't redefine this tag!" if you wrote `Foo = ...` or
|
||||
|
@ -91,6 +108,21 @@ pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This could be:
|
||||
///
|
||||
/// * A module name
|
||||
/// * A type name
|
||||
/// * A global tag
|
||||
pub fn uppercase<'a>() -> impl Parser<'a, UppercaseIdent<'a>, ()> {
|
||||
move |_, state: State<'a>| match chomp_uppercase_part(state.bytes()) {
|
||||
Err(progress) => Err((progress, (), state)),
|
||||
Ok(ident) => {
|
||||
let width = ident.len();
|
||||
Ok((MadeProgress, ident.into(), state.advance(width)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This could be:
|
||||
///
|
||||
/// * A module name
|
||||
|
|
|
@ -2,13 +2,13 @@ use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced};
|
|||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::header::{
|
||||
package_entry, package_name, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader,
|
||||
ModuleName, PackageEntry, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
|
||||
ModuleName, PackageEntry, PlatformHeader, PlatformRequires, To, TypedIdent,
|
||||
};
|
||||
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
|
||||
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase_ident, UppercaseIdent};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, specialize, specialize_region, word1, word2, EEffects, EExposes, EHeader,
|
||||
EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SyntaxError,
|
||||
backtrackable, specialize, specialize_region, word1, EEffects, EExposes, EHeader, EImports,
|
||||
EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SyntaxError,
|
||||
};
|
||||
use crate::state::State;
|
||||
use crate::string_literal;
|
||||
|
@ -439,10 +439,13 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a
|
|||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, PlatformRigid<'a>>>>, ERequires<'a>> {
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
specialize(|_, pos| ERequires::Rigid(pos), loc!(requires_rigid())),
|
||||
specialize(
|
||||
|_, pos| ERequires::Rigid(pos),
|
||||
loc!(map!(ident::uppercase(), Spaced::Item))
|
||||
),
|
||||
word1(b',', ERequires::ListEnd),
|
||||
word1(b'}', ERequires::ListEnd),
|
||||
min_indent,
|
||||
|
@ -453,17 +456,6 @@ fn requires_rigids<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_rigid<'a>() -> impl Parser<'a, Spaced<'a, PlatformRigid<'a>>, ()> {
|
||||
map!(
|
||||
and!(
|
||||
lowercase_ident(),
|
||||
skip_first!(word2(b'=', b'>', |_| ()), uppercase_ident())
|
||||
),
|
||||
|(rigid, alias)| Spaced::Item(PlatformRigid { rigid, alias })
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
|
||||
skip_first!(
|
||||
|
|
|
@ -5,15 +5,14 @@ Platform {
|
|||
),
|
||||
requires: PlatformRequires {
|
||||
rigids: [
|
||||
@36-48 PlatformRigid {
|
||||
rigid: "model",
|
||||
alias: "Model",
|
||||
},
|
||||
@36-41 UppercaseIdent(
|
||||
"Model",
|
||||
),
|
||||
],
|
||||
signature: @52-61 TypedIdent {
|
||||
ident: @52-56 "main",
|
||||
signature: @45-54 TypedIdent {
|
||||
ident: @45-49 "main",
|
||||
spaces_before_colon: [],
|
||||
ann: @59-61 Record {
|
||||
ann: @52-54 Record {
|
||||
fields: [],
|
||||
ext: None,
|
||||
},
|
||||
|
@ -21,17 +20,17 @@ Platform {
|
|||
},
|
||||
exposes: [],
|
||||
packages: [
|
||||
@94-106 PackageEntry {
|
||||
@87-99 PackageEntry {
|
||||
shorthand: "foo",
|
||||
spaces_after_shorthand: [],
|
||||
package_name: @99-106 PackageName(
|
||||
package_name: @92-99 PackageName(
|
||||
"./foo",
|
||||
),
|
||||
},
|
||||
],
|
||||
imports: [],
|
||||
provides: [
|
||||
@139-150 ExposedName(
|
||||
@132-143 ExposedName(
|
||||
"mainForHost",
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
platform "foo/barbaz"
|
||||
requires {model=>Model} { main : {} }
|
||||
requires {Model} { main : {} }
|
||||
exposes []
|
||||
packages { foo: "./foo" }
|
||||
imports []
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
Platform {
|
||||
header: PlatformHeader {
|
||||
name: @9-21 PackageName(
|
||||
"test/types",
|
||||
),
|
||||
requires: PlatformRequires {
|
||||
rigids: [
|
||||
@37-42 UppercaseIdent(
|
||||
"Flags",
|
||||
),
|
||||
@44-49 UppercaseIdent(
|
||||
"Model",
|
||||
),
|
||||
],
|
||||
signature: @55-77 TypedIdent {
|
||||
ident: @55-59 "main",
|
||||
spaces_before_colon: [],
|
||||
ann: @62-77 Apply(
|
||||
"",
|
||||
"App",
|
||||
[
|
||||
@66-71 Apply(
|
||||
"",
|
||||
"Flags",
|
||||
[],
|
||||
),
|
||||
@72-77 Apply(
|
||||
"",
|
||||
"Model",
|
||||
[],
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
},
|
||||
exposes: [],
|
||||
packages: [],
|
||||
imports: [],
|
||||
provides: [
|
||||
@141-152 ExposedName(
|
||||
"mainForHost",
|
||||
),
|
||||
],
|
||||
effects: Effects {
|
||||
spaces_before_effects_keyword: [
|
||||
Newline,
|
||||
],
|
||||
spaces_after_effects_keyword: [],
|
||||
spaces_after_type_name: [],
|
||||
effect_shortname: "fx",
|
||||
effect_type_name: "Effect",
|
||||
entries: [],
|
||||
},
|
||||
before_header: [],
|
||||
after_platform_keyword: [],
|
||||
before_requires: [
|
||||
Newline,
|
||||
],
|
||||
after_requires: [],
|
||||
before_exposes: [
|
||||
Newline,
|
||||
],
|
||||
after_exposes: [],
|
||||
before_packages: [
|
||||
Newline,
|
||||
],
|
||||
after_packages: [],
|
||||
before_imports: [
|
||||
Newline,
|
||||
],
|
||||
after_imports: [],
|
||||
before_provides: [
|
||||
Newline,
|
||||
],
|
||||
after_provides: [],
|
||||
},
|
||||
}
|
|
@ -266,8 +266,14 @@ mod test_parse {
|
|||
let result = func(&input);
|
||||
|
||||
let actual_result = if should_pass {
|
||||
eprintln!("The source code for this test did not successfully parse!\n");
|
||||
|
||||
result.unwrap()
|
||||
} else {
|
||||
eprintln!(
|
||||
"The source code for this test successfully parsed, but it was not expected to!\n"
|
||||
);
|
||||
|
||||
result.unwrap_err()
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue