New module header

Implements the new `module` header syntax as described in "module and package changes" [1]:

```
module [Request, Response, req]
```

The old syntax should still work fine, and is automatically upgraded to the new one
when running `roc format`.

[1] https://docs.google.com/document/d/1E_77fO-44BtoBtXoVeWyGh1xN2KRTWTu8q6i25RNNx0/edit
This commit is contained in:
Agus Zubiaga 2024-02-18 19:10:54 -03:00
parent 7754dd7ef7
commit 057a18573a
No known key found for this signature in database
92 changed files with 1445 additions and 1563 deletions

View File

@ -8,7 +8,6 @@ use roc_fmt::def::fmt_defs;
use roc_fmt::module::fmt_module;
use roc_fmt::spaces::RemoveSpaces;
use roc_fmt::{Ast, Buf};
use roc_parse::ast::Defs;
use roc_parse::module::parse_module_defs;
use roc_parse::{module, parser::SyntaxError, state::State};
@ -226,7 +225,9 @@ fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'
let (module, state) = module::parse_header(arena, State::new(src.as_bytes()))
.map_err(|e| SyntaxError::Header(e.problem))?;
let defs = parse_module_defs(arena, state, Defs::default())?;
let (module, defs) = module.upgrade_header_imports(arena);
let defs = parse_module_defs(arena, state, defs)?;
Ok(Ast { module, defs })
}

View File

@ -1,6 +1,4 @@
interface Bool
exposes [Bool, Eq, true, false, and, or, not, isEq, isNotEq]
imports []
module [Bool, Eq, true, false, and, or, not, isEq, isNotEq]
## Defines a type that can be compared for total equality.
##

View File

@ -2,9 +2,7 @@
## - Holding unknown Roc types when developing [platforms](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#platform).
## - To improve performance in rare cases.
##
interface Box
exposes [box, unbox]
imports []
module [box, unbox]
## Allocates a value on the heap. Boxing is an expensive process as it copies
## the value from the stack to the heap. This may provide a performance

View File

@ -1,36 +1,34 @@
interface Decode
exposes [
DecodeError,
DecodeResult,
Decoder,
Decoding,
DecoderFormatting,
decoder,
u8,
u16,
u32,
u64,
u128,
i8,
i16,
i32,
i64,
i128,
f32,
f64,
dec,
bool,
string,
list,
record,
tuple,
custom,
decodeWith,
fromBytesPartial,
fromBytes,
mapResult,
]
imports []
module [
DecodeError,
DecodeResult,
Decoder,
Decoding,
DecoderFormatting,
decoder,
u8,
u16,
u32,
u64,
u128,
i8,
i16,
i32,
i64,
i128,
f32,
f64,
dec,
bool,
string,
list,
record,
tuple,
custom,
decodeWith,
fromBytesPartial,
fromBytes,
mapResult,
]
import List
import Result exposing [Result]

View File

@ -1,35 +1,33 @@
interface Dict
exposes [
Dict,
empty,
withCapacity,
single,
clear,
capacity,
reserve,
releaseExcessCapacity,
len,
isEmpty,
get,
contains,
insert,
remove,
update,
walk,
walkUntil,
keepIf,
dropIf,
toList,
fromList,
keys,
values,
insertAll,
keepShared,
removeAll,
map,
joinMap,
]
imports []
module [
Dict,
empty,
withCapacity,
single,
clear,
capacity,
reserve,
releaseExcessCapacity,
len,
isEmpty,
get,
contains,
insert,
remove,
update,
walk,
walkUntil,
keepIf,
dropIf,
toList,
fromList,
keys,
values,
insertAll,
keepShared,
removeAll,
map,
joinMap,
]
import Bool exposing [Bool, Eq]
import Result exposing [Result]

View File

@ -1,34 +1,32 @@
interface Encode
exposes [
Encoder,
Encoding,
toEncoder,
EncoderFormatting,
u8,
u16,
u32,
u64,
u128,
i8,
i16,
i32,
i64,
i128,
f32,
f64,
dec,
bool,
string,
list,
record,
tag,
tuple,
custom,
appendWith,
append,
toBytes,
]
imports []
module [
Encoder,
Encoding,
toEncoder,
EncoderFormatting,
u8,
u16,
u32,
u64,
u128,
i8,
i16,
i32,
i64,
i128,
f32,
f64,
dec,
bool,
string,
list,
record,
tag,
tuple,
custom,
appendWith,
append,
toBytes,
]
import Num exposing [
U8,

View File

@ -1,26 +1,25 @@
interface Hash
exposes [
Hash,
Hasher,
hash,
addBytes,
addU8,
addU16,
addU32,
addU64,
addU128,
hashBool,
hashI8,
hashI16,
hashI32,
hashI64,
hashI128,
hashDec,
complete,
hashStrBytes,
hashList,
hashUnordered,
] imports []
module [
Hash,
Hasher,
hash,
addBytes,
addU8,
addU16,
addU32,
addU64,
addU128,
hashBool,
hashI8,
hashI16,
hashI32,
hashI64,
hashI128,
hashDec,
complete,
hashStrBytes,
hashList,
hashUnordered,
]
import Bool exposing [Bool]
import List

View File

@ -1,41 +1,39 @@
interface Inspect
exposes [
Inspect,
Inspector,
InspectFormatter,
ElemWalker,
KeyValWalker,
inspect,
init,
list,
set,
dict,
tag,
tuple,
record,
bool,
str,
function,
opaque,
u8,
i8,
u16,
i16,
u32,
i32,
u64,
i64,
u128,
i128,
f32,
f64,
dec,
custom,
apply,
toInspector,
toStr,
]
imports []
module [
Inspect,
Inspector,
InspectFormatter,
ElemWalker,
KeyValWalker,
inspect,
init,
list,
set,
dict,
tag,
tuple,
record,
bool,
str,
function,
opaque,
u8,
i8,
u16,
i16,
u32,
i32,
u64,
i64,
u128,
i128,
f32,
f64,
dec,
custom,
apply,
toInspector,
toStr,
]
import Bool exposing [Bool]
import Num exposing [U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec]

View File

@ -1,77 +1,75 @@
interface List
exposes [
isEmpty,
get,
set,
replace,
update,
append,
appendIfOk,
prepend,
prependIfOk,
map,
len,
withCapacity,
walkBackwards,
concat,
first,
single,
repeat,
reverse,
join,
keepIf,
contains,
sum,
walk,
last,
keepOks,
keepErrs,
mapWithIndex,
map2,
map3,
product,
walkWithIndex,
walkUntil,
walkWithIndexUntil,
walkFrom,
walkFromUntil,
range,
sortWith,
swap,
dropAt,
min,
max,
map4,
mapTry,
walkTry,
joinMap,
any,
takeFirst,
takeLast,
dropFirst,
dropLast,
findFirst,
findLast,
findFirstIndex,
findLastIndex,
sublist,
intersperse,
split,
splitFirst,
splitLast,
startsWith,
endsWith,
all,
dropIf,
sortAsc,
sortDesc,
reserve,
releaseExcessCapacity,
walkBackwardsUntil,
countIf,
chunksOf,
]
imports []
module [
isEmpty,
get,
set,
replace,
update,
append,
appendIfOk,
prepend,
prependIfOk,
map,
len,
withCapacity,
walkBackwards,
concat,
first,
single,
repeat,
reverse,
join,
keepIf,
contains,
sum,
walk,
last,
keepOks,
keepErrs,
mapWithIndex,
map2,
map3,
product,
walkWithIndex,
walkUntil,
walkWithIndexUntil,
walkFrom,
walkFromUntil,
range,
sortWith,
swap,
dropAt,
min,
max,
map4,
mapTry,
walkTry,
joinMap,
any,
takeFirst,
takeLast,
dropFirst,
dropLast,
findFirst,
findLast,
findFirstIndex,
findLastIndex,
sublist,
intersperse,
split,
splitFirst,
splitLast,
startsWith,
endsWith,
all,
dropIf,
sortAsc,
sortDesc,
reserve,
releaseExcessCapacity,
walkBackwardsUntil,
countIf,
chunksOf,
]
import Bool exposing [Bool, Eq]
import Result exposing [Result]

View File

@ -1,163 +1,161 @@
interface Num
exposes [
Num,
Int,
Frac,
Integer,
FloatingPoint,
I128,
I64,
I32,
I16,
I8,
U128,
U64,
U32,
U16,
U8,
Signed128,
Signed64,
Signed32,
Signed16,
Signed8,
Unsigned128,
Unsigned64,
Unsigned32,
Unsigned16,
Unsigned8,
Dec,
F64,
F32,
Decimal,
Binary32,
Binary64,
e,
pi,
tau,
abs,
absDiff,
neg,
add,
sub,
mul,
min,
max,
isLt,
isLte,
isGt,
isGte,
isApproxEq,
sin,
cos,
tan,
atan,
acos,
asin,
isZero,
isEven,
isOdd,
toFrac,
isPositive,
isNegative,
isNaN,
isInfinite,
isFinite,
rem,
remChecked,
div,
divChecked,
sqrt,
sqrtChecked,
log,
logChecked,
round,
ceiling,
floor,
compare,
pow,
powInt,
countLeadingZeroBits,
countTrailingZeroBits,
countOneBits,
addWrap,
addChecked,
addSaturated,
bitwiseAnd,
bitwiseXor,
bitwiseOr,
bitwiseNot,
shiftLeftBy,
shiftRightBy,
shiftRightZfBy,
subWrap,
subChecked,
subSaturated,
mulWrap,
mulSaturated,
mulChecked,
intCast,
divCeil,
divCeilChecked,
divTrunc,
divTruncChecked,
toStr,
isMultipleOf,
minI8,
maxI8,
minU8,
maxU8,
minI16,
maxI16,
minU16,
maxU16,
minI32,
maxI32,
minU32,
maxU32,
minI64,
maxI64,
minU64,
maxU64,
minI128,
maxI128,
minU128,
maxU128,
minF32,
maxF32,
minF64,
maxF64,
toI8,
toI8Checked,
toI16,
toI16Checked,
toI32,
toI32Checked,
toI64,
toI64Checked,
toI128,
toI128Checked,
toU8,
toU8Checked,
toU16,
toU16Checked,
toU32,
toU32Checked,
toU64,
toU64Checked,
toU128,
toU128Checked,
toF32,
toF32Checked,
toF64,
toF64Checked,
withoutDecimalPoint,
withDecimalPoint,
f32ToParts,
f64ToParts,
f32FromParts,
f64FromParts,
]
imports []
module [
Num,
Int,
Frac,
Integer,
FloatingPoint,
I128,
I64,
I32,
I16,
I8,
U128,
U64,
U32,
U16,
U8,
Signed128,
Signed64,
Signed32,
Signed16,
Signed8,
Unsigned128,
Unsigned64,
Unsigned32,
Unsigned16,
Unsigned8,
Dec,
F64,
F32,
Decimal,
Binary32,
Binary64,
e,
pi,
tau,
abs,
absDiff,
neg,
add,
sub,
mul,
min,
max,
isLt,
isLte,
isGt,
isGte,
isApproxEq,
sin,
cos,
tan,
atan,
acos,
asin,
isZero,
isEven,
isOdd,
toFrac,
isPositive,
isNegative,
isNaN,
isInfinite,
isFinite,
rem,
remChecked,
div,
divChecked,
sqrt,
sqrtChecked,
log,
logChecked,
round,
ceiling,
floor,
compare,
pow,
powInt,
countLeadingZeroBits,
countTrailingZeroBits,
countOneBits,
addWrap,
addChecked,
addSaturated,
bitwiseAnd,
bitwiseXor,
bitwiseOr,
bitwiseNot,
shiftLeftBy,
shiftRightBy,
shiftRightZfBy,
subWrap,
subChecked,
subSaturated,
mulWrap,
mulSaturated,
mulChecked,
intCast,
divCeil,
divCeilChecked,
divTrunc,
divTruncChecked,
toStr,
isMultipleOf,
minI8,
maxI8,
minU8,
maxU8,
minI16,
maxI16,
minU16,
maxU16,
minI32,
maxI32,
minU32,
maxU32,
minI64,
maxI64,
minU64,
maxU64,
minI128,
maxI128,
minU128,
maxU128,
minF32,
maxF32,
minF64,
maxF64,
toI8,
toI8Checked,
toI16,
toI16Checked,
toI32,
toI32Checked,
toI64,
toI64Checked,
toI128,
toI128Checked,
toU8,
toU8Checked,
toU16,
toU16Checked,
toU32,
toU32Checked,
toU64,
toU64Checked,
toU128,
toU128Checked,
toF32,
toF32Checked,
toF64,
toF64Checked,
withoutDecimalPoint,
withDecimalPoint,
f32ToParts,
f64ToParts,
f32FromParts,
f64FromParts,
]
import Bool exposing [Bool]
import Result exposing [Result]

View File

@ -1,6 +1,4 @@
interface Result
exposes [Result, isOk, isErr, map, mapErr, try, onErr, withDefault]
imports []
module [Result, isOk, isErr, map, mapErr, try, onErr, withDefault]
import Bool exposing [Bool]

View File

@ -1,30 +1,28 @@
interface Set
exposes [
Set,
empty,
withCapacity,
reserve,
releaseExcessCapacity,
single,
walk,
walkUntil,
keepIf,
dropIf,
insert,
len,
isEmpty,
capacity,
remove,
contains,
toList,
fromList,
union,
intersection,
difference,
map,
joinMap,
]
imports []
module [
Set,
empty,
withCapacity,
reserve,
releaseExcessCapacity,
single,
walk,
walkUntil,
keepIf,
dropIf,
insert,
len,
isEmpty,
capacity,
remove,
contains,
toList,
fromList,
union,
intersection,
difference,
map,
joinMap,
]
import List
import Bool exposing [Bool, Eq]

View File

@ -326,50 +326,48 @@
## If a situation like this comes up, a slice can be turned into a separate string by using [`Str.concat`](https://www.roc-lang.org/builtins/Str#concat) to concatenate the slice onto an empty string (or one created with [`Str.withCapacity`](https://www.roc-lang.org/builtins/Str#withCapacity)).
##
## Currently, the only way to get seamless slices of strings is by calling certain `Str` functions which return them. In general, `Str` functions which accept a string and return a subset of that string tend to do this. [`Str.trim`](https://www.roc-lang.org/builtins/Str#trim) is another example of a function which returns a seamless slice.
interface Str
exposes [
Utf8Problem,
Utf8ByteProblem,
concat,
isEmpty,
joinWith,
split,
repeat,
countUtf8Bytes,
toUtf8,
fromUtf8,
startsWith,
endsWith,
trim,
trimStart,
trimEnd,
toDec,
toF64,
toF32,
toU128,
toI128,
toU64,
toI64,
toU32,
toI32,
toU16,
toI16,
toU8,
toI8,
replaceEach,
replaceFirst,
replaceLast,
splitFirst,
splitLast,
walkUtf8,
walkUtf8WithIndex,
reserve,
releaseExcessCapacity,
withCapacity,
withPrefix,
contains,
]
imports []
module [
Utf8Problem,
Utf8ByteProblem,
concat,
isEmpty,
joinWith,
split,
repeat,
countUtf8Bytes,
toUtf8,
fromUtf8,
startsWith,
endsWith,
trim,
trimStart,
trimEnd,
toDec,
toF64,
toF32,
toU128,
toI128,
toU64,
toI64,
toU32,
toI32,
toU16,
toI16,
toU8,
toI8,
replaceEach,
replaceFirst,
replaceLast,
splitFirst,
splitLast,
walkUtf8,
walkUtf8WithIndex,
reserve,
releaseExcessCapacity,
withCapacity,
withPrefix,
contains,
]
import Bool exposing [Bool]
import Result exposing [Result]

View File

@ -1,12 +1,10 @@
## THIS MODULE IS DEPRECATED AND CURRENTLY IN THE PROCESS OF BEING REMOVED
## FROM STD LIBRARY
interface TotallyNotJson
exposes [
Json,
json,
jsonWithOptions,
]
imports []
module [
Json,
json,
jsonWithOptions,
]
import List
import Str

View File

@ -506,7 +506,7 @@ fn canonicalize_claimed_ability_impl<'a>(
// OPTION-1: The implementation identifier is the only identifier of that name in the
// scope. For example,
//
// interface F imports [] exposes []
// module []
//
// Hello := {} implements [Encoding.{ toEncoder }]
//
@ -518,7 +518,9 @@ fn canonicalize_claimed_ability_impl<'a>(
// OPTION-2: The implementation identifier is a unique shadow of the ability member,
// which has also been explicitly imported. For example,
//
// interface F imports [Encoding.{ toEncoder }] exposes []
// module []
//
// import Encoding exposing [toEncoder]
//
// Hello := {} implements [Encoding.{ toEncoder }]
//

View File

@ -8,7 +8,7 @@ use bumpalo::Bump;
use roc_parse::ast::{Collection, Header, Module, Spaced, Spaces};
use roc_parse::header::{
AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword, HostedHeader, ImportsEntry,
ImportsKeyword, InterfaceHeader, Keyword, KeywordItem, ModuleName, PackageEntry, PackageHeader,
ImportsKeyword, Keyword, KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader,
PackageKeyword, PackageName, PackagesKeyword, PlatformHeader, PlatformRequires,
ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword, TypedIdent, WithKeyword,
};
@ -18,8 +18,8 @@ use roc_region::all::Loc;
pub fn fmt_module<'a>(buf: &mut Buf<'_>, module: &'a Module<'a>) {
fmt_comments_only(buf, module.comments.iter(), NewlineAt::Bottom, 0);
match &module.header {
Header::Interface(header) => {
fmt_interface_header(buf, header);
Header::Module(header) => {
fmt_module_header(buf, header);
}
Header::App(header) => {
fmt_app_header(buf, header);
@ -171,20 +171,19 @@ impl<'a, K: Formattable, V: Formattable> Formattable for KeywordItem<'a, K, V> {
}
}
pub fn fmt_interface_header<'a>(buf: &mut Buf, header: &'a InterfaceHeader<'a>) {
pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
buf.indent(0);
buf.push_str("interface");
let indent = INDENT;
fmt_default_spaces(buf, header.before_name, indent);
buf.push_str("module");
// module name
buf.indent(indent);
buf.push_str(header.name.value.as_str());
if header.before_exposes.iter().all(|c| c.is_newline()) {
buf.spaces(1);
fmt_exposes(buf, header.exposes, 0);
} else {
let indent = INDENT;
header.exposes.keyword.format(buf, indent);
fmt_exposes(buf, header.exposes.item, indent);
header.imports.keyword.format(buf, indent);
fmt_imports(buf, header.imports.item, indent);
fmt_default_spaces(buf, header.before_exposes, indent);
fmt_exposes(buf, header.exposes, indent);
};
}
pub fn fmt_hosted_header<'a>(buf: &mut Buf, header: &'a HostedHeader<'a>) {

View File

@ -10,9 +10,9 @@ use roc_parse::{
StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef, WhenBranch,
},
header::{
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, KeywordItem,
ModuleName, PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires,
ProvidesTo, To, TypedIdent,
AppHeader, ExposedName, HostedHeader, ImportsEntry, KeywordItem, ModuleHeader, ModuleName,
PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To,
TypedIdent,
},
ident::{BadIdent, UppercaseIdent},
};
@ -283,11 +283,10 @@ impl<'a> RemoveSpaces<'a> for ProvidesTo<'a> {
impl<'a> RemoveSpaces<'a> for Module<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
let header = match &self.header {
Header::Interface(header) => Header::Interface(InterfaceHeader {
before_name: &[],
name: header.name.remove_spaces(arena),
Header::Module(header) => Header::Module(ModuleHeader {
before_exposes: &[],
exposes: header.exposes.remove_spaces(arena),
imports: header.imports.remove_spaces(arena),
interface_imports: header.interface_imports.remove_spaces(arena),
}),
Header::App(header) => Header::App(AppHeader {
before_name: &[],

View File

@ -6109,9 +6109,7 @@ In roc, functions are always written as a lambda, like{}
report_header_problem_as(
indoc!(
r"
interface Foobar
exposes [main, @Foo]
imports [pf.Task, Base64]
module [main, @Foo]
"
),
indoc!(
@ -6120,39 +6118,12 @@ In roc, functions are always written as a lambda, like{}
I am partway through parsing an `exposes` list, but I got stuck here:
1 interface Foobar
2 exposes [main, @Foo]
^
1 module [main, @Foo]
^
I was expecting a type name, value name or function name next, like
exposes [Animal, default, tame]
"
),
)
}
#[test]
fn invalid_module_name() {
report_header_problem_as(
indoc!(
r"
interface foobar
exposes [main, @Foo]
imports [pf.Task, Base64]
"
),
indoc!(
r"
WEIRD MODULE NAME in /code/proj/Main.roc
I am partway through parsing a header, but got stuck here:
1 interface foobar
^
I am expecting a module name next, like BigNum or Main. Module names
must start with an uppercase letter.
[Animal, default, tame]
"
),
)

View File

@ -49,8 +49,8 @@ use roc_mono::{drop_specialization, inc_dec};
use roc_packaging::cache::RocCacheDir;
use roc_parse::ast::{self, CommentOrNewline, ExtractSpaces, Spaced, ValueDef};
use roc_parse::header::{
ExposedName, HeaderType, ImportsKeywordItem, PackageEntry, PackageHeader, PlatformHeader, To,
TypedIdent,
self, ExposedName, HeaderType, ImportsKeywordItem, PackageEntry, PackageHeader, PlatformHeader,
To, TypedIdent,
};
use roc_parse::module::parse_module_defs;
use roc_parse::parser::{FileError, SourceError, SyntaxError};
@ -644,7 +644,7 @@ struct CanAndCon {
enum PlatformPath<'a> {
NotSpecified,
Valid(To<'a>),
RootIsInterface,
RootIsModule,
RootIsHosted,
RootIsPlatformModule,
}
@ -1204,8 +1204,9 @@ fn adjust_header_paths<'a>(
{
debug_assert_eq!(*header_id, header_output.module_id);
if let HeaderType::Interface { name, .. } = header_type {
// Interface modules can have names like Foo.Bar.Baz,
if let HeaderType::Module { name, .. } = header_type {
// [modules-revamp] TODO: Privacy changes
// Modules can have names like Foo.Bar.Baz,
// in which case we need to adjust the src_dir to
// remove the "Bar/Baz" directories in order to correctly
// resolve this interface module's imports!
@ -2313,13 +2314,13 @@ fn update<'a>(
state.exposed_modules = exposes_ids;
}
}
Builtin { .. } | Interface { .. } => {
Builtin { .. } | Module { .. } => {
if header.is_root_module {
debug_assert!(matches!(
state.platform_path,
PlatformPath::NotSpecified
));
state.platform_path = PlatformPath::RootIsInterface;
state.platform_path = PlatformPath::RootIsModule;
}
}
Hosted { .. } => {
@ -2956,7 +2957,7 @@ fn update<'a>(
// This happens due to abilities. In detail, consider
//
// # Default module
// interface Default exposes [default, getDefault]
// module [default, getDefault]
//
// Default implements default : {} -> a where a implements Default
//
@ -3198,7 +3199,7 @@ fn finish_specialization<'a>(
let module_id = state.root_id;
let uses_prebuilt_platform = match platform_data {
Some(data) => data.is_prebuilt,
// If there's no platform data (e.g. because we're building an interface module)
// If there's no platform data (e.g. because we're building a module)
// then there's no prebuilt platform either!
None => false,
};
@ -3346,12 +3347,12 @@ fn load_package_from_disk<'a>(
match parsed {
Ok((
ast::Module {
header: ast::Header::Interface(header),
header: ast::Header::Module(header),
..
},
_parse_state,
)) => Err(LoadingProblem::UnexpectedHeader(format!(
"expected platform/package module, got Interface with header\n{header:?}"
"expected platform/package module, got Module with header\n{header:?}"
))),
Ok((
ast::Module {
@ -3477,23 +3478,25 @@ fn load_builtin_module_help<'a>(
match parsed {
Ok((
ast::Module {
header: ast::Header::Interface(header),
header: ast::Header::Module(header),
comments,
},
parse_state,
)) => {
let name_stem = arena.alloc_str(filename.file_stem().unwrap().to_str().unwrap());
let info = HeaderInfo {
filename,
is_root_module,
opt_shorthand,
packages: &[],
header_type: HeaderType::Builtin {
name: header.name.value,
exposes: unspace(arena, header.exposes.item.items),
name: header::ModuleName::new(name_stem),
exposes: unspace(arena, header.exposes.items),
generates_with: &[],
},
module_comments: comments,
header_imports: Some(header.imports),
header_imports: header.interface_imports,
};
(info, parse_state)
@ -3693,45 +3696,6 @@ fn find_task<T>(local: &Worker<T>, global: &Injector<T>, stealers: &[Stealer<T>]
})
}
fn verify_interface_matches_file_path<'a>(
interface_name: Loc<roc_parse::header::ModuleName<'a>>,
path: &Path,
state: &roc_parse::state::State<'a>,
) -> Result<(), LoadingProblem<'a>> {
let module_parts = interface_name.value.as_str().split(MODULE_SEPARATOR).rev();
let mut is_mismatched = false;
let mut opt_path = Some(path);
for part in module_parts {
match opt_path.and_then(|path| path.file_stem().map(|fi| (path, fi))) {
None => {
is_mismatched = true;
break;
}
Some((path, fi)) => {
if fi != part {
is_mismatched = true;
break;
}
opt_path = path.parent();
}
}
}
if !is_mismatched {
return Ok(());
}
use roc_parse::parser::EHeader;
let syntax_problem =
SyntaxError::Header(EHeader::InconsistentModuleName(interface_name.region));
let problem = LoadingProblem::ParsingFailed(FileError {
problem: SourceError::new(syntax_problem, state),
filename: path.to_path_buf(),
});
Err(problem)
}
#[derive(Debug)]
struct HeaderOutput<'a> {
module_id: ModuleId,
@ -3798,48 +3762,35 @@ fn parse_header<'a>(
match parsed {
Ok((
ast::Module {
header: ast::Header::Interface(header),
header: ast::Header::Module(header),
comments,
},
parse_state,
)) => {
verify_interface_matches_file_path(header.name, &filename, &parse_state)?;
let module_name = match opt_expected_module_name {
Some(pq_name) => arena.alloc_str(pq_name.as_inner().as_str()),
None => {
// [modules-revamp] [privacy-changes] TODO: Support test/check on nested modules
arena.alloc_str(filename.file_stem().unwrap().to_str().unwrap())
}
};
let header_name_region = header.name.region;
let info = HeaderInfo {
filename,
is_root_module,
opt_shorthand,
packages: &[],
header_type: HeaderType::Interface {
name: header.name.value,
exposes: unspace(arena, header.exposes.item.items),
header_type: HeaderType::Module {
name: roc_parse::header::ModuleName::new(module_name),
exposes: unspace(arena, header.exposes.items),
},
module_comments: comments,
header_imports: Some(header.imports),
header_imports: header.interface_imports,
};
let (module_id, module_name, header) =
let (module_id, _, header) =
build_header(info, parse_state.clone(), module_ids, module_timing)?;
if let Some(expected_module_name) = opt_expected_module_name {
if expected_module_name != module_name {
let problem = SourceError::new(
IncorrectModuleName {
module_id,
found: Loc::at(header_name_region, module_name),
expected: expected_module_name,
},
&parse_state,
);
let problem = LoadingProblem::IncorrectModuleName(FileError {
problem,
filename: header.module_path,
});
return Err(problem);
}
}
Ok(HeaderOutput {
module_id,
msg: Msg::Header(header),
@ -4217,14 +4168,9 @@ fn build_header<'a>(
// Package modules do not have names.
String::new().into()
}
HeaderType::Interface { name, .. }
HeaderType::Module { name, .. }
| HeaderType::Builtin { name, .. }
| HeaderType::Hosted { name, .. } => {
// TODO check to see if name is consistent with filename.
// If it isn't, report a problem!
name.as_str().into()
}
| HeaderType::Hosted { name, .. } => name.as_str().into(),
};
let (name, home) = {
@ -5172,7 +5118,7 @@ fn parse<'a>(
}
HeaderType::App { .. }
| HeaderType::Package { .. }
| HeaderType::Interface { .. }
| HeaderType::Module { .. }
| HeaderType::Builtin { .. }
| HeaderType::Hosted { .. } => {}
};
@ -6408,12 +6354,12 @@ fn report_cannot_run(
severity: Severity::RuntimeError,
}
}
RootIsInterface => {
RootIsModule => {
let doc = alloc.stack([
alloc.reflow(
r"The input file is an `interface` module, but only `app` modules can be run.",
r"The input file is a module, but only `app` modules can be run.",
),
alloc.reflow(r"Tip: You can use `roc check` or `roc test` to verify an interface module like this one."),
alloc.reflow(r"Tip: You can use `roc check` or `roc test` to verify a module like this one."),
]);
Report {

View File

@ -339,7 +339,7 @@ fn import_transitive_alias() {
"RBTree.roc",
indoc!(
r"
interface RBTree exposes [RedBlackTree, empty] imports []
module [RedBlackTree, empty]
# The color of a node. Leaves are considered Black.
NodeColor : [Red, Black]
@ -357,7 +357,7 @@ fn import_transitive_alias() {
"Other.roc",
indoc!(
r"
interface Other exposes [empty] imports []
module [empty]
import RBTree
@ -372,9 +372,9 @@ fn import_transitive_alias() {
}
#[test]
fn interface_with_deps() {
fn module_with_deps() {
let subs_by_module = Default::default();
let src_dir = fixtures_dir().join("interface_with_deps");
let src_dir = fixtures_dir().join("module_with_deps");
let filename = src_dir.join("Primary.roc");
let arena = Bump::new();
let loaded = load_and_typecheck(
@ -488,7 +488,7 @@ fn load_docs() {
#[test]
fn import_alias() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "ImportAlias", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "ImportAlias", subs_by_module);
expect_types(
loaded_module,
@ -501,7 +501,7 @@ fn import_alias() {
#[test]
fn import_inside_def() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "ImportInsideDef", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "ImportInsideDef", subs_by_module);
expect_types(
loaded_module,
@ -517,7 +517,7 @@ fn import_inside_def() {
fn exposed_used_outside_scope() {
let subs_by_module = Default::default();
load_fixture(
"interface_with_deps",
"module_with_deps",
"ExposedUsedOutsideScope",
subs_by_module,
);
@ -527,17 +527,13 @@ fn exposed_used_outside_scope() {
#[should_panic(expected = "MODULE NOT IMPORTED")]
fn import_used_outside_scope() {
let subs_by_module = Default::default();
load_fixture(
"interface_with_deps",
"ImportUsedOutsideScope",
subs_by_module,
);
load_fixture("module_with_deps", "ImportUsedOutsideScope", subs_by_module);
}
#[test]
fn test_load_and_typecheck() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "WithBuiltins", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "WithBuiltins", subs_by_module);
expect_types(
loaded_module,
@ -558,7 +554,7 @@ fn test_load_and_typecheck() {
#[test]
fn iface_quicksort() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "Quicksort", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "Quicksort", subs_by_module);
expect_types(
loaded_module,
@ -574,7 +570,7 @@ fn iface_quicksort() {
#[test]
fn load_astar() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "AStar", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "AStar", subs_by_module);
expect_types(
loaded_module,
@ -606,7 +602,7 @@ fn load_principal_types() {
#[test]
fn iface_dep_types() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "Primary", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "Primary", subs_by_module);
expect_types(
loaded_module,
@ -650,7 +646,7 @@ fn app_dep_types() {
#[test]
fn imported_dep_regression() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "OneDep", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "OneDep", subs_by_module);
expect_types(
loaded_module,
@ -663,7 +659,7 @@ fn imported_dep_regression() {
#[test]
fn ingested_file() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "IngestedFile", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "IngestedFile", subs_by_module);
expect_types(
loaded_module,
@ -678,7 +674,7 @@ fn ingested_file() {
#[test]
fn ingested_file_bytes() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "IngestedFileBytes", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "IngestedFileBytes", subs_by_module);
expect_types(
loaded_module,
@ -695,7 +691,7 @@ fn parse_problem() {
"Main.roc",
indoc!(
r"
interface Main exposes [main] imports []
module [main]
main = [
"
@ -732,7 +728,7 @@ fn parse_problem() {
#[should_panic(expected = "FILE NOT FOUND")]
fn file_not_found() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "invalid$name", subs_by_module);
let loaded_module = load_fixture("module_with_deps", "invalid$name", subs_by_module);
expect_types(
loaded_module,
@ -887,7 +883,7 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
"Age.roc",
indoc!(
r"
interface Age exposes [Age] imports []
module [Age]
Age := U32
"
@ -897,7 +893,7 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
"Main.roc",
indoc!(
r"
interface Main exposes [twenty, readAge] imports []
module [twenty, readAge]
import Age exposing [Age]
@ -965,7 +961,8 @@ fn unused_imports() {
"Dep1.roc",
indoc!(
r#"
interface Dep1 exposes [one] imports []
module [one]
one = 1
"#
),
@ -974,7 +971,8 @@ fn unused_imports() {
"Dep2.roc",
indoc!(
r#"
interface Dep2 exposes [two] imports []
module [two]
two = 2
"#
),
@ -983,7 +981,7 @@ fn unused_imports() {
"Dep3.roc",
indoc!(
r#"
interface Dep3 exposes [Three, three] imports []
module [Three, three]
Three : [Three]
@ -995,7 +993,7 @@ fn unused_imports() {
"Main.roc",
indoc!(
r#"
interface Main exposes [usedModule, unusedModule, unusedExposed, unusedWithAlias, usingThreeValue] imports []
module [usedModule, unusedModule, unusedExposed, usingThreeValue, unusedWithAlias]
import Dep1
import Dep3 exposing [Three]
@ -1663,48 +1661,13 @@ fn import_builtin_in_platform_and_check_app() {
assert!(result.is_ok(), "should check");
}
#[test]
fn module_doesnt_match_file_path() {
let modules = vec![(
"Age.roc",
indoc!(
r"
interface NotAge exposes [Age] imports []
Age := U32
"
),
)];
let err = multiple_modules("module_doesnt_match_file_path", modules).unwrap_err();
assert_eq!(
err,
indoc!(
r"
WEIRD MODULE NAME in tmp/module_doesnt_match_file_path/Age.roc
This module name does not correspond with the file path it is defined
in:
1 interface NotAge exposes [Age] imports []
^^^^^^
Module names must correspond with the file paths they are defined in.
For example, I expect to see BigNum defined in BigNum.roc, or Math.Sin
defined in Math/Sin.roc."
),
"\n{}",
err
);
}
#[test]
fn module_cyclic_import_itself() {
let modules = vec![(
"Age.roc",
indoc!(
r"
interface Age exposes [] imports []
module []
import Age
"
@ -1742,7 +1705,8 @@ fn module_cyclic_import_transitive() {
"Age.roc",
indoc!(
r"
interface Age exposes [] imports []
module []
import Person
"
),
@ -1751,7 +1715,8 @@ fn module_cyclic_import_transitive() {
"Person.roc",
indoc!(
r"
interface Person exposes [] imports []
module []
import Age
"
),

View File

@ -1,7 +1,7 @@
use std::fmt::Debug;
use crate::header::{
self, AppHeader, HostedHeader, InterfaceHeader, ModuleName, PackageHeader, PlatformHeader,
self, AppHeader, HostedHeader, ModuleHeader, ModuleName, PackageHeader, PlatformHeader,
};
use crate::ident::Accessor;
use crate::parser::ESingleQuote;
@ -99,6 +99,21 @@ pub struct Module<'a> {
}
impl<'a> Module<'a> {
pub fn upgrade_header_imports(self, arena: &'a Bump) -> (Self, Defs<'a>) {
let (header, defs) = match self.header {
Header::Module(header) => (
Header::Module(ModuleHeader {
interface_imports: None,
..header
}),
Self::header_imports_to_defs(arena, header.interface_imports),
),
header => (header, Defs::default()),
};
(Module { header, ..self }, defs)
}
pub fn header_imports_to_defs(
arena: &'a Bump,
imports: Option<
@ -209,7 +224,7 @@ impl<'a> Module<'a> {
#[derive(Clone, Debug, PartialEq)]
pub enum Header<'a> {
Interface(InterfaceHeader<'a>),
Module(ModuleHeader<'a>),
App(AppHeader<'a>),
Package(PackageHeader<'a>),
Platform(PlatformHeader<'a>),
@ -2272,7 +2287,7 @@ impl<'a> Malformed for Module<'a> {
impl<'a> Malformed for Header<'a> {
fn is_malformed(&self) -> bool {
match self {
Header::Interface(header) => header.is_malformed(),
Header::Module(header) => header.is_malformed(),
Header::App(header) => header.is_malformed(),
Header::Package(header) => header.is_malformed(),
Header::Platform(header) => header.is_malformed(),

View File

@ -19,7 +19,7 @@ impl<'a> HeaderType<'a> {
}
| HeaderType::Hosted { exposes, .. }
| HeaderType::Builtin { exposes, .. }
| HeaderType::Interface { exposes, .. } => exposes,
| HeaderType::Module { exposes, .. } => exposes,
HeaderType::Platform { .. } | HeaderType::Package { .. } => &[],
}
}
@ -30,7 +30,7 @@ impl<'a> HeaderType<'a> {
HeaderType::Builtin { .. } => "builtin",
HeaderType::Package { .. } => "package",
HeaderType::Platform { .. } => "platform",
HeaderType::Interface { .. } => "interface",
HeaderType::Module { .. } => "module",
}
}
}
@ -73,7 +73,7 @@ pub enum HeaderType<'a> {
/// usually `pf`
config_shorthand: &'a str,
},
Interface {
Module {
name: ModuleName<'a>,
exposes: &'a [Loc<ExposedName<'a>>],
},
@ -82,9 +82,9 @@ pub enum HeaderType<'a> {
impl<'a> HeaderType<'a> {
pub fn get_name(self) -> Option<&'a str> {
match self {
Self::Interface { name, .. }
| Self::Builtin { name, .. }
| Self::Hosted { name, .. } => Some(name.into()),
Self::Module { name, .. } | Self::Builtin { name, .. } | Self::Hosted { name, .. } => {
Some(name.into())
}
Self::App {
output_name: StrLiteral::PlainLine(name),
..
@ -106,13 +106,11 @@ impl<'a> HeaderType<'a> {
pub fn to_maybe_builtin(self, module_id: ModuleId) -> Self {
match self {
HeaderType::Interface { name, exposes } if module_id.is_builtin() => {
HeaderType::Builtin {
name,
exposes,
generates_with: &[],
}
}
HeaderType::Module { name, exposes } if module_id.is_builtin() => HeaderType::Builtin {
name,
exposes,
generates_with: &[],
},
_ => self,
}
}
@ -246,12 +244,12 @@ pub struct KeywordItem<'a, K, V> {
}
#[derive(Clone, Debug, PartialEq)]
pub struct InterfaceHeader<'a> {
pub before_name: &'a [CommentOrNewline<'a>],
pub name: Loc<ModuleName<'a>>,
pub struct ModuleHeader<'a> {
pub before_exposes: &'a [CommentOrNewline<'a>],
pub exposes: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
pub exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
pub imports: KeywordItem<'a, ImportsKeyword, Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>>,
// Keeping this so we can format old interface header into module headers
pub interface_imports: Option<KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>>,
}
pub type ImportsKeywordItem<'a> = KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>;
@ -430,7 +428,7 @@ where
}
}
impl<'a> Malformed for InterfaceHeader<'a> {
impl<'a> Malformed for ModuleHeader<'a> {
fn is_malformed(&self) -> bool {
false
}

View File

@ -1,10 +1,11 @@
use crate::ast::{Collection, Defs, Header, Module, Spaced, Spaces};
use crate::ast::{Collection, CommentOrNewline, Defs, Header, Module, Spaced, Spaces};
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::header::{
package_entry, package_name, AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword,
HostedHeader, ImportsEntry, ImportsKeyword, InterfaceHeader, Keyword, KeywordItem, ModuleName,
PackageEntry, PackageHeader, PackagesKeyword, PlatformHeader, PlatformRequires,
ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword, TypedIdent, WithKeyword,
HostedHeader, ImportsEntry, ImportsKeyword, ImportsKeywordItem, Keyword, KeywordItem,
ModuleHeader, ModuleName, PackageEntry, PackageHeader, PackagesKeyword, PlatformHeader,
PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword, TypedIdent,
WithKeyword,
};
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
use crate::parser::Progress::{self, *};
@ -60,12 +61,20 @@ pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
record!(Module {
comments: space0_e(EHeader::IndentStart),
header: one_of![
map!(
skip_first!(
keyword("module", EHeader::Start),
increment_min_indent(module_header())
),
Header::Module
),
// Old headers
map!(
skip_first!(
keyword("interface", EHeader::Start),
increment_min_indent(interface_header())
),
Header::Interface
Header::Module
),
map!(
skip_first!(
@ -100,22 +109,65 @@ pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
}
#[inline(always)]
fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>, EHeader<'a>> {
record!(InterfaceHeader {
before_name: space0_e(EHeader::IndentStart),
name: loc!(module_name_help(EHeader::ModuleName)),
exposes: specialize_err(EHeader::Exposes, exposes_values()),
imports: specialize_err(EHeader::Imports, imports()),
fn module_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
record!(ModuleHeader {
before_exposes: space0_e(EHeader::IndentStart),
exposes: specialize_err(EHeader::Exposes, exposes_list()),
interface_imports: succeed!(None)
})
.trace("module_header")
}
/// Parse old interface headers so we can format them into module headers
#[inline(always)]
fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
use bumpalo::collections::Vec;
let before_exposes = map_with_arena!(
and!(
skip_second!(
space0_e(EHeader::IndentStart),
loc!(module_name_help(EHeader::ModuleName))
),
specialize_err(EHeader::Exposes, exposes_kw())
),
|arena: &'a bumpalo::Bump,
(before_name, kw): (&'a [CommentOrNewline<'a>], Spaces<'a, ExposesKeyword>)| {
let mut combined: Vec<CommentOrNewline> =
Vec::with_capacity_in(before_name.len() + kw.before.len() + kw.after.len(), arena);
combined.extend(before_name);
combined.extend(kw.before);
combined.extend(kw.after);
arena.alloc(combined)
}
);
record!(ModuleHeader {
before_exposes: before_exposes,
exposes: specialize_err(EHeader::Exposes, exposes_list()).trace("exposes_list"),
interface_imports: map!(
specialize_err(EHeader::Imports, imports()),
imports_none_if_empty
)
.trace("imports"),
})
.trace("interface_header")
}
fn imports_none_if_empty(value: ImportsKeywordItem<'_>) -> Option<ImportsKeywordItem<'_>> {
if value.item.is_empty() {
None
} else {
Some(value)
}
}
#[inline(always)]
fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
record!(HostedHeader {
before_name: space0_e(EHeader::IndentStart),
name: loc!(module_name_help(EHeader::ModuleName)),
exposes: specialize_err(EHeader::Exposes, exposes_values()),
exposes: specialize_err(EHeader::Exposes, exposes_values_kw()),
imports: specialize_err(EHeader::Imports, imports()),
generates: specialize_err(EHeader::Generates, generates()),
generates_with: specialize_err(EHeader::GeneratesWith, generates_with()),
@ -388,28 +440,39 @@ fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>
}
#[inline(always)]
fn exposes_values<'a>() -> impl Parser<
fn exposes_values_kw<'a>() -> impl Parser<
'a,
KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
EExposes,
> {
record!(KeywordItem {
keyword: spaces_around_keyword(
ExposesKeyword,
EExposes::Exposes,
EExposes::IndentExposes,
EExposes::IndentListStart
),
item: collection_trailing_sep_e!(
byte(b'[', EExposes::ListStart),
exposes_entry(EExposes::Identifier),
byte(b',', EExposes::ListEnd),
byte(b']', EExposes::ListEnd),
Spaced::SpaceBefore
)
keyword: exposes_kw(),
item: exposes_list()
})
}
#[inline(always)]
fn exposes_kw<'a>() -> impl Parser<'a, Spaces<'a, ExposesKeyword>, EExposes> {
spaces_around_keyword(
ExposesKeyword,
EExposes::Exposes,
EExposes::IndentExposes,
EExposes::IndentListStart,
)
}
#[inline(always)]
fn exposes_list<'a>() -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>, EExposes>
{
collection_trailing_sep_e!(
byte(b'[', EExposes::ListStart),
exposes_entry(EExposes::Identifier),
byte(b',', EExposes::ListEnd),
byte(b']', EExposes::ListEnd),
Spaced::SpaceBefore
)
}
pub fn spaces_around_keyword<'a, K: Keyword, E>(
keyword_item: K,
expectation: fn(Position) -> E,

View File

@ -37,4 +37,4 @@
":="
":"
"@"
"->"
"->"

View File

@ -1 +0,0 @@
interface Foo exposes [] imports []

View File

@ -1,27 +0,0 @@
Module {
comments: [],
header: Interface(
InterfaceHeader {
before_name: [],
name: @10-13 ModuleName(
"Foo",
),
exposes: KeywordItem {
keyword: Spaces {
before: [],
item: ExposesKeyword,
after: [],
},
item: [],
},
imports: KeywordItem {
keyword: Spaces {
before: [],
item: ImportsKeyword,
after: [],
},
item: [],
},
},
),
}

View File

@ -1 +0,0 @@
interface Foo exposes [] imports []

View File

@ -0,0 +1,10 @@
Module {
comments: [],
header: Module(
ModuleHeader {
before_exposes: [],
exposes: [],
interface_imports: None,
},
),
}

View File

@ -1 +0,0 @@
interface T exposes [] imports []

View File

@ -1,27 +0,0 @@
Module {
comments: [],
header: Interface(
InterfaceHeader {
before_name: [],
name: @10-11 ModuleName(
"T",
),
exposes: KeywordItem {
keyword: Spaces {
before: [],
item: ExposesKeyword,
after: [],
},
item: [],
},
imports: KeywordItem {
keyword: Spaces {
before: [],
item: ImportsKeyword,
after: [],
},
item: [],
},
},
),
}

View File

@ -1 +0,0 @@
interface T exposes [] imports []

View File

@ -0,0 +1,25 @@
Module {
comments: [],
header: Module(
ModuleHeader {
before_exposes: [],
exposes: [
@8-9 ExposedName(
"a",
),
@11-12 ExposedName(
"b",
),
@18-19 SpaceBefore(
ExposedName(
"c",
),
[
Newline,
],
),
],
interface_imports: None,
},
),
}

View File

@ -0,0 +1,2 @@
module [a, b,
c]

View File

@ -0,0 +1,10 @@
Module {
comments: [],
header: Module(
ModuleHeader {
before_exposes: [],
exposes: [],
interface_imports: None,
},
),
}

View File

@ -1 +0,0 @@
interface Foo.Bar.Baz exposes [] imports []

View File

@ -1,27 +0,0 @@
Module {
comments: [],
header: Interface(
InterfaceHeader {
before_name: [],
name: @10-21 ModuleName(
"Foo.Bar.Baz",
),
exposes: KeywordItem {
keyword: Spaces {
before: [],
item: ExposesKeyword,
after: [],
},
item: [],
},
imports: KeywordItem {
keyword: Spaces {
before: [],
item: ImportsKeyword,
after: [],
},
item: [],
},
},
),
}

View File

@ -1 +0,0 @@
interface Foo.Bar.Baz exposes [] imports []

View File

@ -0,0 +1 @@
module [Foo, foo, bar]

View File

@ -0,0 +1,20 @@
Module {
comments: [],
header: Module(
ModuleHeader {
before_exposes: [],
exposes: [
@23-26 ExposedName(
"Foo",
),
@28-31 ExposedName(
"foo",
),
@33-36 ExposedName(
"bar",
),
],
interface_imports: None,
},
),
}

View File

@ -0,0 +1 @@
interface Foo exposes [Foo, foo, bar] imports []

View File

@ -4768,10 +4768,10 @@ mod test_fmt {
// MODULES
#[test]
fn single_line_interface() {
fn single_line_module() {
module_formats_same(indoc!(
r"
interface Foo exposes [] imports []"
module []"
));
}
@ -4781,12 +4781,14 @@ mod test_fmt {
module_formats_to(
indoc!(
r"
interface Foo exposes [] imports []
module []
a = 42 # Yay greetings"
),
indoc!(
r"
interface Foo exposes [] imports []
module []
a = 42 # Yay greetings
"
),
@ -4794,49 +4796,25 @@ mod test_fmt {
}
#[test]
fn multiline_interface() {
fn module_exposing() {
module_formats_same(indoc!(
r"
interface Foo
exposes []
imports []"
module [Bar, Baz, a, b]"
));
}
#[test]
fn interface_exposing() {
fn module_exposing_multiline() {
module_formats_same(indoc!(
r"
interface Foo
exposes [Bar, Baz, a, b]
imports []"
));
}
module [
Stuff,
Things,
somethingElse,
]
#[test]
fn interface_importing() {
module_formats_same(indoc!(
r"
interface Foo
exposes [Bar, Baz, a, b]
imports [Blah, Thing.{ foo, bar }, Stuff]"
));
}
#[test]
fn multi_line_interface() {
module_formats_same(indoc!(
r"
interface Foo
exposes [
Stuff,
Things,
somethingElse,
]
imports [
Blah,
Baz.{ stuff, things },
]"
import Blah
import Baz exposing [stuff, things]"
));
}
@ -4866,9 +4844,7 @@ mod test_fmt {
&format!(
indoc!(
r#"
interface Foo
exposes []
imports []
module []
# comment 1{space}
def = "" # comment 2{space}
@ -4879,9 +4855,7 @@ mod test_fmt {
),
indoc!(
r#"
interface Foo
exposes []
imports []
module []
# comment 1
def = "" # comment 2
@ -5700,7 +5674,7 @@ mod test_fmt {
module_formats_same(indoc!(
r"
interface Foo exposes [] imports []
module []
expect x == y
@ -5727,7 +5701,7 @@ mod test_fmt {
module_formats_same(indoc!(
r"
interface Foo exposes [] imports []
module []
expect
foo bar
@ -5831,7 +5805,7 @@ mod test_fmt {
fn ability_member_doc_comments() {
module_formats_same(indoc!(
r"
interface Foo exposes [] imports []
module []
A implements
## This is member ab
@ -5850,9 +5824,7 @@ mod test_fmt {
module_formats_same(indoc!(
r"
# hello world
interface Foo
exposes []
imports []
module []
"
));
@ -5876,6 +5848,17 @@ mod test_fmt {
));
}
#[test]
fn comments_before_exposes_preserved() {
module_formats_same(indoc!(
r"
module
# comment
[a, b]
"
));
}
#[test]
fn clauses_with_multiple_abilities() {
expr_formats_same(indoc!(

View File

@ -301,8 +301,8 @@ mod test_snapshots {
pass/def_without_newline.expr,
pass/destructure_tag_assignment.expr,
pass/empty_app_header.header,
pass/empty_module_header.header,
pass/empty_hosted_header.header,
pass/empty_interface_header.header,
pass/empty_list.expr,
pass/empty_package_header.header,
pass/empty_platform_header.header,
@ -333,7 +333,7 @@ mod test_snapshots {
pass/inline_import.expr,
pass/inline_ingested_file.expr,
pass/int_with_underscore.expr,
pass/interface_with_newline.header,
pass/module_with_newline.header,
pass/lambda_in_chain.expr,
pass/lambda_indent.expr,
pass/list_closing_indent_not_enough.expr,
@ -348,6 +348,7 @@ mod test_snapshots {
pass/minus_twelve_minus_five.expr,
pass/mixed_docs.expr,
pass/module_def_newline.moduledefs,
pass/module_multiline_exposes.header,
pass/multi_backpassing.expr,
pass/multi_backpassing_in_def.moduledefs,
pass/multi_backpassing_with_apply.expr,
@ -369,7 +370,6 @@ mod test_snapshots {
pass/nested_def_annotation.moduledefs,
pass/nested_def_without_newline.expr,
pass/nested_if.expr,
pass/nested_module.header,
pass/newline_after_equals.expr, // Regression test for https://github.com/roc-lang/roc/issues/51
pass/newline_after_mul.expr,
pass/newline_after_paren.expr,
@ -409,6 +409,7 @@ mod test_snapshots {
pass/outdented_colon_in_record.expr,
pass/outdented_list.expr,
pass/outdented_record.expr,
pass/old_interface_header.header,
pass/packed_singleton_list.expr,
pass/parens_in_type_def_apply.expr,
pass/parens_in_value_def_annotation.expr,

View File

@ -11,9 +11,8 @@ use roc_parse::{
WhenBranch,
},
header::{
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName,
PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To,
TypedIdent,
AppHeader, ExposedName, HostedHeader, ImportsEntry, ModuleHeader, ModuleName, PackageEntry,
PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To, TypedIdent,
},
ident::{Accessor, UppercaseIdent},
};
@ -202,7 +201,7 @@ impl IterTokens for Module<'_> {
impl IterTokens for Header<'_> {
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
match self {
Header::Interface(ih) => ih.iter_tokens(arena),
Header::Module(mh) => mh.iter_tokens(arena),
Header::App(app) => app.iter_tokens(arena),
Header::Package(pkg) => pkg.iter_tokens(arena),
Header::Platform(pf) => pf.iter_tokens(arena),
@ -211,19 +210,15 @@ impl IterTokens for Header<'_> {
}
}
impl IterTokens for InterfaceHeader<'_> {
impl IterTokens for ModuleHeader<'_> {
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
let Self {
before_name: _,
name,
before_exposes: _,
exposes,
imports,
interface_imports: _,
} = self;
(name.iter_tokens(arena).into_iter())
.chain(exposes.item.iter_tokens(arena))
.chain(imports.item.iter_tokens(arena))
.collect_in(arena)
exposes.iter_tokens(arena)
}
}

View File

@ -128,7 +128,7 @@ fn write_archive<W: Write>(path: &Path, writer: W) -> io::Result<()> {
// TODO use this when finding .roc files by discovering them from the root module.
// let other_modules: &[Module<'_>] =
match read_header(&arena, &mut buf, path)?.header {
Header::Interface(_) => {
Header::Module(_) => {
todo!();
// TODO report error
}

View File

@ -3621,7 +3621,7 @@ fn to_exposes_report<'a>(
"I was expecting a type name, value name or function name next, like",
)]),
alloc
.parser_suggestion("exposes [Animal, default, tame]")
.parser_suggestion("[Animal, default, tame]")
.indent(4),
]);
@ -3646,7 +3646,7 @@ fn to_exposes_report<'a>(
alloc.reflow(" keyword next, like"),
]),
alloc
.parser_suggestion("exposes [Animal, default, tame]")
.parser_suggestion("[Animal, default, tame]")
.indent(4),
]);

View File

@ -102,7 +102,7 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe
- [Unisonweb](https://www.unisonweb.org), definition based [editor](https://twitter.com/shojberg/status/1364666092598288385) as opposed to file based.
- [Utopia](https://utopia.app/) integrated design and development environment for React. Design and code update each other, in real time.
- [Paredit](https://calva.io/paredit/) structural clojure editing, navigation and selection. [Another overview](http://danmidwood.com/content/2014/11/21/animated-paredit.html)
- [tylr](https://tylr.fun/) projectional editor UX that helps you make it easier to do edits that are typically difficult with projectional editors but are easy with classic editors.
- [tylr](https://tylr.fun/) projectional editor UX that helps you make it easier to do edits that are typically difficult with projectional editors but are easy with classic editors.
### Project exploration

View File

@ -1,13 +1,11 @@
interface Community
exposes [
Community,
empty,
addPerson,
addFriend,
Person,
walkFriendNames,
]
imports []
module [
Community,
empty,
addPerson,
addFriend,
Person,
walkFriendNames,
]
## Datatype representing a community for demonstration purposes in inspect-gui.roc and inspect-logging.roc

View File

@ -1,9 +1,7 @@
interface GuiFormatter
exposes [
GuiFormatter,
toGui,
]
imports []
module [
GuiFormatter,
toGui,
]
## Creates GUI representations of Roc values, for use in inspect-gui.roc

View File

@ -1,6 +1,8 @@
interface Context
exposes [Context, Data, with, getChar, Option, pushStack, popStack, toStr, inWhileScope]
imports [pf.File, pf.Task.{ Task }, Variable.{ Variable }]
module [Context, Data, with, getChar, Option, pushStack, popStack, toStr, inWhileScope]
import pf.File
import pf.Task exposing [Task]
import Variable exposing [Variable]
Option a : [Some a, None]

View File

@ -1,6 +1,4 @@
interface Variable
exposes [Variable, fromUtf8, toIndex, totalCount, toStr]
imports []
module [Variable, fromUtf8, toIndex, totalCount, toStr]
# Variables in False can only be single letters. Thus, the valid variables are "a" to "z".
# This opaque type deals with ensure we always have valid variables.

View File

@ -1,6 +1,7 @@
interface File
exposes [line, Handle, withOpen, chunk]
imports [pf.Effect, Task.{ Task }]
module [line, Handle, withOpen, chunk]
import pf.Effect
import Task exposing [Task]
Handle := U64

View File

@ -1,6 +1,7 @@
interface Stdin
exposes [char]
imports [pf.Effect, Task]
module [char]
import pf.Effect
import Task
# line : Task.Task Str *
# line = Effect.after Effect.getLine Task.succeed # TODO FIXME Effect.getLine should suffice

View File

@ -1,6 +1,7 @@
interface Stdout
exposes [line, raw]
imports [pf.Effect, Task.{ Task }]
module [line, raw]
import pf.Effect
import Task exposing [Task]
line : Str -> Task {} *
line = \str -> Effect.map (Effect.putLine str) (\_ -> Ok {})

View File

@ -1,6 +1,6 @@
interface Task
exposes [Task, succeed, fail, await, map, onFail, attempt, fromResult, loop]
imports [pf.Effect]
module [Task, succeed, fail, await, map, onFail, attempt, fromResult, loop]
import pf.Effect
Task ok err : Effect.Effect (Result ok err)

View File

@ -1,6 +1,4 @@
interface Program
exposes [Program]
imports []
module [Program]
Program model : {
init : {} -> model,

View File

@ -1,6 +1,4 @@
interface Action
exposes [Action, none, update, map]
imports []
module [Action, none, update, map]
Action state : [None, Update state]

View File

@ -1,6 +1,6 @@
interface Elem
exposes [Elem, PressEvent, row, col, text, button, none, translate, list]
imports [Action.{ Action }]
module [Elem, PressEvent, row, col, text, button, none, translate, list]
import Action exposing [Action]
Elem state : [
# PERFORMANCE NOTE:

View File

@ -1,6 +1,4 @@
interface Game
exposes [Bounds, Elem, Event]
imports []
module [Bounds, Elem, Event]
Rgba : { r : F32, g : F32, b : F32, a : F32 }

View File

@ -1,6 +1,4 @@
interface Action
exposes [Action, none, update, map]
imports []
module [Action, none, update, map]
Action state : [None, Update state]

View File

@ -1,6 +1,6 @@
interface Elem
exposes [Elem, PressEvent, row, col, text, button, none, translate, list]
imports [Action.{ Action }]
module [Elem, PressEvent, row, col, text, button, none, translate, list]
import Action exposing [Action]
Elem state : [
# PERFORMANCE NOTE:

View File

@ -1,128 +1,128 @@
interface Html
exposes [
Node,
Attribute,
render,
renderWithoutDocType,
element,
unclosedElem,
text,
attribute,
html,
base,
head,
link,
meta,
style,
title,
body,
address,
article,
aside,
footer,
header,
h1,
h2,
h3,
h4,
h5,
h6,
main,
nav,
section,
blockquote,
dd,
div,
dl,
dt,
figcaption,
figure,
hr,
li,
menu,
ol,
p,
pre,
ul,
a,
abbr,
b,
bdi,
bdo,
br,
cite,
code,
data,
dfn,
em,
i,
kbd,
mark,
q,
rp,
rt,
ruby,
s,
samp,
small,
span,
strong,
sub,
sup,
time,
u,
var,
wbr,
area,
audio,
img,
map,
track,
video,
embed,
iframe,
object,
picture,
portal,
source,
svg,
math,
canvas,
noscript,
script,
del,
ins,
caption,
col,
colgroup,
table,
tbody,
td,
tfoot,
th,
thead,
tr,
button,
datalist,
fieldset,
form,
input,
label,
legend,
meter,
optgroup,
option,
output,
progress,
select,
textarea,
details,
dialog,
summary,
slot,
template,
]
imports [Html.Attributes]
module [
Node,
Attribute,
render,
renderWithoutDocType,
element,
unclosedElem,
text,
attribute,
html,
base,
head,
link,
meta,
style,
title,
body,
address,
article,
aside,
footer,
header,
h1,
h2,
h3,
h4,
h5,
h6,
main,
nav,
section,
blockquote,
dd,
div,
dl,
dt,
figcaption,
figure,
hr,
li,
menu,
ol,
p,
pre,
ul,
a,
abbr,
b,
bdi,
bdo,
br,
cite,
code,
data,
dfn,
em,
i,
kbd,
mark,
q,
rp,
rt,
ruby,
s,
samp,
small,
span,
strong,
sub,
sup,
time,
u,
var,
wbr,
area,
audio,
img,
map,
track,
video,
embed,
iframe,
object,
picture,
portal,
source,
svg,
math,
canvas,
noscript,
script,
del,
ins,
caption,
col,
colgroup,
table,
tbody,
td,
tfoot,
th,
thead,
tr,
button,
datalist,
fieldset,
form,
input,
label,
legend,
meter,
optgroup,
option,
output,
progress,
select,
textarea,
details,
dialog,
summary,
slot,
template,
]
import Html.Attributes
Node : [
Text Str,

View File

@ -1,144 +1,142 @@
interface Html.Attributes
exposes [
Attribute,
attribute,
accept,
acceptCharset,
accesskey,
action,
align,
allow,
alt,
ariaLabel,
ariaLabelledBy,
ariaHidden,
async,
autocapitalize,
autocomplete,
autofocus,
autoplay,
background,
bgcolor,
border,
buffered,
capture,
challenge,
charset,
checked,
cite,
class,
code,
codebase,
color,
cols,
colspan,
content,
contenteditable,
contextmenu,
controls,
coords,
crossorigin,
csp,
data,
dataAttr,
datetime,
decoding,
default,
defer,
dir,
dirname,
disabled,
download,
draggable,
enctype,
enterkeyhint,
for,
form,
formaction,
formenctype,
formmethod,
formnovalidate,
formtarget,
headers,
height,
hidden,
high,
href,
hreflang,
httpEquiv,
icon,
id,
importance,
integrity,
intrinsicsize,
inputmode,
ismap,
itemprop,
keytype,
kind,
label,
lang,
language,
loading,
list,
loop,
low,
manifest,
max,
maxlength,
minlength,
media,
method,
min,
multiple,
muted,
name,
novalidate,
open,
optimum,
pattern,
ping,
placeholder,
poster,
preload,
radiogroup,
readonly,
referrerpolicy,
rel,
required,
reversed,
role,
rows,
rowspan,
sandbox,
scope,
scoped,
selected,
shape,
size,
sizes,
slot,
span,
spellcheck,
src,
srcdoc,
srclang,
srcset,
start,
step,
style,
summary,
tabindex,
target,
title,
translate,
type,
usemap,
value,
width,
wrap,
]
imports []
module [
Attribute,
attribute,
accept,
acceptCharset,
accesskey,
action,
align,
allow,
alt,
ariaLabel,
ariaLabelledBy,
ariaHidden,
async,
autocapitalize,
autocomplete,
autofocus,
autoplay,
background,
bgcolor,
border,
buffered,
capture,
challenge,
charset,
checked,
cite,
class,
code,
codebase,
color,
cols,
colspan,
content,
contenteditable,
contextmenu,
controls,
coords,
crossorigin,
csp,
data,
dataAttr,
datetime,
decoding,
default,
defer,
dir,
dirname,
disabled,
download,
draggable,
enctype,
enterkeyhint,
for,
form,
formaction,
formenctype,
formmethod,
formnovalidate,
formtarget,
headers,
height,
hidden,
high,
href,
hreflang,
httpEquiv,
icon,
id,
importance,
integrity,
intrinsicsize,
inputmode,
ismap,
itemprop,
keytype,
kind,
label,
lang,
language,
loading,
list,
loop,
low,
manifest,
max,
maxlength,
minlength,
media,
method,
min,
multiple,
muted,
name,
novalidate,
open,
optimum,
pattern,
ping,
placeholder,
poster,
preload,
radiogroup,
readonly,
referrerpolicy,
rel,
required,
reversed,
role,
rows,
rowspan,
sandbox,
scope,
scoped,
selected,
shape,
size,
sizes,
slot,
span,
spellcheck,
src,
srcdoc,
srclang,
srcset,
start,
step,
style,
summary,
tabindex,
target,
title,
translate,
type,
usemap,
value,
width,
wrap,
]
Attribute : [Attribute Str Str]

View File

@ -1,8 +1,6 @@
interface ExampleApp
exposes [exampleApp, State]
imports [
pf.Html.{ App, Html, html, head, body, div, text, h1 },
]
module [exampleApp, State]
import pf.Html exposing [App, Html, html, head, body, div, text, h1]
State : {
answer : U32,

View File

@ -1,6 +1,4 @@
interface Action
exposes [Action, none, update, map]
imports []
module [Action, none, update, map]
Action state : [None, Update state]

View File

@ -1,129 +1,130 @@
interface Html
exposes [
App,
Html,
Attribute,
renderStatic,
renderStaticWithoutDocType,
translate,
translateStatic,
text,
none,
html,
base,
head,
link,
meta,
style,
title,
body,
address,
article,
aside,
footer,
header,
h1,
h2,
h3,
h4,
h5,
h6,
main,
nav,
section,
blockquote,
dd,
div,
dl,
dt,
figcaption,
figure,
hr,
li,
menu,
ol,
p,
pre,
ul,
a,
abbr,
b,
bdi,
bdo,
br,
cite,
code,
data,
dfn,
em,
i,
kbd,
mark,
q,
rp,
rt,
ruby,
s,
samp,
small,
span,
strong,
sub,
sup,
time,
u,
var,
wbr,
area,
audio,
img,
map,
track,
video,
embed,
iframe,
object,
picture,
portal,
source,
svg,
math,
canvas,
noscript,
script,
del,
ins,
caption,
col,
colgroup,
table,
tbody,
td,
tfoot,
th,
thead,
tr,
button,
datalist,
fieldset,
form,
input,
label,
legend,
meter,
optgroup,
option,
output,
progress,
select,
textarea,
details,
dialog,
summary,
slot,
template,
]
imports [Html.Internal.Shared, Html.Internal.Server]
module [
App,
Html,
Attribute,
renderStatic,
renderStaticWithoutDocType,
translate,
translateStatic,
text,
none,
html,
base,
head,
link,
meta,
style,
title,
body,
address,
article,
aside,
footer,
header,
h1,
h2,
h3,
h4,
h5,
h6,
main,
nav,
section,
blockquote,
dd,
div,
dl,
dt,
figcaption,
figure,
hr,
li,
menu,
ol,
p,
pre,
ul,
a,
abbr,
b,
bdi,
bdo,
br,
cite,
code,
data,
dfn,
em,
i,
kbd,
mark,
q,
rp,
rt,
ruby,
s,
samp,
small,
span,
strong,
sub,
sup,
time,
u,
var,
wbr,
area,
audio,
img,
map,
track,
video,
embed,
iframe,
object,
picture,
portal,
source,
svg,
math,
canvas,
noscript,
script,
del,
ins,
caption,
col,
colgroup,
table,
tbody,
td,
tfoot,
th,
thead,
tr,
button,
datalist,
fieldset,
form,
input,
label,
legend,
meter,
optgroup,
option,
output,
progress,
select,
textarea,
details,
dialog,
summary,
slot,
template,
]
import Html.Internal.Shared
import Html.Internal.Server
App state initData : Html.Internal.Shared.App state initData
Html state : Html.Internal.Shared.Html state

View File

@ -1,140 +1,140 @@
interface Html.Attributes
exposes [
attribute,
accept,
acceptCharset,
accesskey,
action,
align,
allow,
alt,
async,
autocapitalize,
autocomplete,
autofocus,
autoplay,
background,
bgcolor,
border,
buffered,
capture,
challenge,
charset,
checked,
cite,
class,
code,
codebase,
color,
cols,
colspan,
content,
contenteditable,
contextmenu,
controls,
coords,
crossorigin,
csp,
data,
# dataAttr, TODO
datetime,
decoding,
default,
defer,
dir,
dirname,
disabled,
download,
draggable,
enctype,
enterkeyhint,
for,
form,
formaction,
formenctype,
formmethod,
formnovalidate,
formtarget,
headers,
height,
hidden,
high,
href,
hreflang,
httpEquiv,
icon,
id,
importance,
integrity,
intrinsicsize,
inputmode,
ismap,
itemprop,
keytype,
kind,
label,
lang,
language,
loading,
list,
loop,
low,
manifest,
max,
maxlength,
minlength,
media,
method,
min,
multiple,
muted,
name,
novalidate,
open,
optimum,
pattern,
ping,
placeholder,
poster,
preload,
radiogroup,
readonly,
referrerpolicy,
rel,
required,
reversed,
role,
rows,
rowspan,
sandbox,
scope,
scoped,
selected,
shape,
size,
sizes,
slot,
span,
spellcheck,
src,
srcdoc,
srclang,
srcset,
start,
step,
style,
summary,
tabindex,
target,
title,
translate,
type,
usemap,
value,
width,
wrap,
]
imports [Html.Internal.Shared.{ Attribute }]
module [
attribute,
accept,
acceptCharset,
accesskey,
action,
align,
allow,
alt,
async,
autocapitalize,
autocomplete,
autofocus,
autoplay,
background,
bgcolor,
border,
buffered,
capture,
challenge,
charset,
checked,
cite,
class,
code,
codebase,
color,
cols,
colspan,
content,
contenteditable,
contextmenu,
controls,
coords,
crossorigin,
csp,
data,
# dataAttr, TODO
datetime,
decoding,
default,
defer,
dir,
dirname,
disabled,
download,
draggable,
enctype,
enterkeyhint,
for,
form,
formaction,
formenctype,
formmethod,
formnovalidate,
formtarget,
headers,
height,
hidden,
high,
href,
hreflang,
httpEquiv,
icon,
id,
importance,
integrity,
intrinsicsize,
inputmode,
ismap,
itemprop,
keytype,
kind,
label,
lang,
language,
loading,
list,
loop,
low,
manifest,
max,
maxlength,
minlength,
media,
method,
min,
multiple,
muted,
name,
novalidate,
open,
optimum,
pattern,
ping,
placeholder,
poster,
preload,
radiogroup,
readonly,
referrerpolicy,
rel,
required,
reversed,
role,
rows,
rowspan,
sandbox,
scope,
scoped,
selected,
shape,
size,
sizes,
slot,
span,
spellcheck,
src,
srcdoc,
srclang,
srcset,
start,
step,
style,
summary,
tabindex,
target,
title,
translate,
type,
usemap,
value,
width,
wrap,
]
import Html.Internal.Shared exposing [Attribute]
attribute : Str -> (Str -> Attribute state)
attribute = \attrType ->

View File

@ -1,27 +1,25 @@
interface Html.Event
exposes [
Handler,
CyclicStructureAccessor,
on,
custom,
onClick,
onDoubleClick,
onMouseDown,
onMouseUp,
onMouseEnter,
onMouseLeave,
onMouseOver,
onMouseOut,
onCheck,
onBlur,
onFocus,
onInput,
onSubmit,
]
imports [
Action.{ Action },
Html.Internal.Shared.{ Attribute },
]
module [
Handler,
CyclicStructureAccessor,
on,
custom,
onClick,
onDoubleClick,
onMouseDown,
onMouseUp,
onMouseEnter,
onMouseLeave,
onMouseOver,
onMouseOut,
onCheck,
onBlur,
onFocus,
onInput,
onSubmit,
]
import Action exposing [Action]
import Html.Internal.Shared exposing [Attribute]
Handler state : Html.Internal.Shared.Handler state
CyclicStructureAccessor : Html.Internal.Shared.CyclicStructureAccessor

View File

@ -1,29 +1,27 @@
interface Html.Internal.Client
exposes [
PlatformState,
initClientApp,
dispatchEvent,
]
imports [
Effect.{
Effect,
NodeId,
HandlerId,
TagName,
AttrType,
EventType,
},
Html.Internal.Shared.{
App,
Html,
Attribute,
CyclicStructureAccessor,
Handler,
translateStatic,
},
TotallyNotJson,
Action,
]
module [
PlatformState,
initClientApp,
dispatchEvent,
]
import Effect exposing [
Effect,
NodeId,
HandlerId,
TagName,
AttrType,
EventType,
]
import Html.Internal.Shared exposing [
App,
Html,
Attribute,
CyclicStructureAccessor,
Handler,
translateStatic,
]
import TotallyNotJson
import Action
PlatformState state initData : {
app : App state initData,

View File

@ -1,12 +1,10 @@
interface Html.Internal.Server
exposes [
appendRenderedStatic,
initServerApp,
]
imports [
Html.Internal.Shared.{ Html, Attribute, App, translateStatic, text, element },
TotallyNotJson,
]
module [
appendRenderedStatic,
initServerApp,
]
import Html.Internal.Shared exposing [Html, Attribute, App, translateStatic, text, element]
import TotallyNotJson
# -------------------------------
# STATIC HTML

View File

@ -1,21 +1,19 @@
interface Html.Internal.Shared
exposes [
App,
Html,
Attribute,
CyclicStructureAccessor,
Handler,
Size,
element,
text,
none,
translate,
translateStatic,
nodeSize,
]
imports [
Action.{ Action },
]
module [
App,
Html,
Attribute,
CyclicStructureAccessor,
Handler,
Size,
element,
text,
none,
translate,
translateStatic,
nodeSize,
]
import Action exposing [Action]
App state initData : {
init : DecodingResult initData -> state,