Skip to content

Commit

Permalink
feat(compiler)!: Require module prefix on use/provide for modul…
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-snezhko committed Jul 1, 2023
1 parent 973f3f3 commit 5efb54c
Show file tree
Hide file tree
Showing 17 changed files with 87 additions and 42 deletions.
10 changes: 6 additions & 4 deletions compiler/src/formatting/format.re
Original file line number Diff line number Diff line change
Expand Up @@ -3956,8 +3956,9 @@ and print_expression_inner =
};

switch (item) {
| PUseValue({name, alias})
| PUseModule({name, alias}) => item_name(name, alias)
| PUseValue({name, alias}) => item_name(name, alias)
| PUseModule({name, alias}) =>
Doc.concat([Doc.text("module "), item_name(name, alias)])
| PUseType({name, alias}) =>
Doc.concat([Doc.text("type "), item_name(name, alias)])
};
Expand Down Expand Up @@ -5106,8 +5107,9 @@ let rec toplevel_print =
};

switch (item) {
| PProvideValue({name, alias})
| PProvideModule({name, alias}) => item_name(name, alias)
| PProvideValue({name, alias}) => item_name(name, alias)
| PProvideModule({name, alias}) =>
Doc.concat([Doc.text("module "), item_name(name, alias)])
| PProvideType({name, alias}) =>
Doc.concat([Doc.text("type "), item_name(name, alias)])
};
Expand Down
40 changes: 29 additions & 11 deletions compiler/src/parsing/parser.messages
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ program: MODULE UIDENT EOL INCLUDE STRING AS YIELD
## The known suffix of the stack is as follows:
## AS
##
program: MODULE UIDENT EOL PROVIDE LBRACE MODULE YIELD
##
## Ends in an error in state: 829.
##
## provide_item -> MODULE . aliasable(uid) [ RBRACE EOL COMMA ]
##
## The known suffix of the stack is as follows:
## MODULE
##

Expected an uppercase module identifier.

Expand Down Expand Up @@ -269,22 +278,21 @@ program: MODULE UIDENT EOL FOREIGN WASM LIDENT COLON UIDENT AS YIELD
## The known suffix of the stack is as follows:
## AS
##
program: MODULE UIDENT EOL PROVIDE LBRACE UIDENT AS EOL YIELD
program: MODULE UIDENT EOL PROVIDE LBRACE MODULE UIDENT AS EOL YIELD
##
## Ends in an error in state: 51.
## Ends in an error in state: 52.
##
## as_prefix(uid) -> AS option(eols) . uid [ RBRACE EOL COMMA ]
## as_prefix(uid) -> AS eols . uid [ RBRACE EOL COMMA ]
##
## The known suffix of the stack is as follows:
## AS option(eols)
## AS eols
##
## WARNING: This example involves spurious reductions.
## This implies that, although the LR(1) items shown above provide an
## accurate view of the past (what has been recognized so far), they
## may provide an INCOMPLETE view of the future (what was expected next).
## In state 3, spurious reduction of production nonempty_list(eol) -> EOL
## In state 6, spurious reduction of production eols -> nonempty_list(eol)
## In state 53, spurious reduction of production option(eols) -> eols
##
program: MODULE UIDENT EOL PROVIDE LBRACE LIDENT AS EOL YIELD
##
Expand Down Expand Up @@ -424,7 +432,7 @@ program: MODULE UIDENT EOL FROM UIDENT USE LBRACE YIELD
## In state 31, spurious reduction of production lbrace -> LBRACE
##

Expected a lowercase identifier to use a value, an uppercase identifier to use a module, or the keyword `type` followed by an uppercase identifier to use a type.
Expected a lowercase identifier to use a value, the keyword `module` followed by an uppercase identifier to use a module, or the keyword `type` followed by an uppercase identifier to use a type.

program: MODULE UIDENT EOL FROM UIDENT USE LBRACE TYPE YIELD
##
Expand All @@ -435,10 +443,19 @@ program: MODULE UIDENT EOL FROM UIDENT USE LBRACE TYPE YIELD
## The known suffix of the stack is as follows:
## TYPE
##
program: MODULE UIDENT EOL FROM UIDENT USE LBRACE MODULE YIELD
##
## Ends in an error in state: 57.
##
## use_item -> MODULE . aliasable(uid) [ RBRACE EOL COMMA ]
##
## The known suffix of the stack is as follows:
## MODULE
##

Expected an uppercase type identifier.

program: MODULE UIDENT EOL PROVIDE LBRACE UIDENT YIELD
program: MODULE UIDENT EOL PROVIDE LBRACE MODULE UIDENT YIELD
##
## Ends in an error in state: 49.
##
Expand All @@ -450,11 +467,12 @@ program: MODULE UIDENT EOL PROVIDE LBRACE UIDENT YIELD

Expected the keyword `as` followed by a module alias, a comma followed by more items to use, or `}` to end the statement.

program: MODULE UIDENT EOL PROVIDE LBRACE UIDENT AS YIELD
program: MODULE UIDENT EOL PROVIDE LBRACE MODULE UIDENT AS YIELD
##
## Ends in an error in state: 50.
##
## as_prefix(uid) -> AS . uid [ RBRACE EOL COMMA ]
## as_prefix(uid) -> AS . eols uid [ RBRACE EOL COMMA ]
##
## The known suffix of the stack is as follows:
## AS
Expand Down Expand Up @@ -508,7 +526,7 @@ program: MODULE UIDENT EOL PROVIDE LBRACE LIDENT COMMA YIELD
## In state 63, spurious reduction of production comma -> COMMA
##

Expected more items to provide or `}` to end the provide statement.
Expected a lowercase identifier to provide a value, the keyword `module` followed by an uppercase identifier to provide a module, the keyword `type` followed by an uppercase identifier to provide a type, or `}` to end the provide statement.

program: MODULE UIDENT EOL PROVIDE LBRACE YIELD
##
Expand All @@ -526,7 +544,7 @@ program: MODULE UIDENT EOL PROVIDE LBRACE YIELD
## In state 31, spurious reduction of production lbrace -> LBRACE
##

Expected a comma-separated list of items to provide.
Expected a lowercase identifier to provide a value, the keyword `module` followed by an uppercase identifier to provide a module, or the keyword `type` followed by an uppercase identifier to provide a type.

program: MODULE UIDENT EOL PROVIDE LBRACE TYPE YIELD
##
Expand Down Expand Up @@ -594,7 +612,7 @@ program: MODULE UIDENT EOL FROM UIDENT USE LBRACE LIDENT COMMA YIELD
## In state 63, spurious reduction of production comma -> COMMA
##

Expected more items to use or `}` to end the statement.
Expected a lowercase identifier to use a value, the keyword `module` followed by an uppercase identifier to use a module, the keyword `type` followed by an uppercase identifier to use a type, or `}` to end the use statement.

program: MODULE UIDENT EOL ASSERT WHEN
##
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/parsing/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ aliasable(X):

use_item:
| TYPE aliasable(uid) { PUseType { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| aliasable(uid) { PUseModule { name=fst $1; alias = snd $1; loc=to_loc $loc} }
| MODULE aliasable(uid) { PUseModule { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| aliasable(lid) { PUseValue { name=fst $1; alias = snd $1; loc=to_loc $loc} }

use_items:
Expand Down Expand Up @@ -371,7 +371,7 @@ data_declaration_stmts:

provide_item:
| TYPE aliasable(uid) { PProvideType { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| aliasable(uid) { PProvideModule { name=fst $1; alias = snd $1; loc=to_loc $loc} }
| MODULE aliasable(uid) { PProvideModule { name=fst $2; alias = snd $2; loc=to_loc $loc} }
| aliasable(lid) { PProvideValue { name=fst $1; alias = snd $1; loc=to_loc $loc} }

provide_items:
Expand Down
11 changes: 8 additions & 3 deletions compiler/test/grainfmt/includes.expected.gr
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ include "option" as Opt
include "array"
include "array" as Foo
from List use { length, map, forEach as each }
from Opt use { MutableOpt, ImmutableOpt as Imm, type Opt, type Opt as OptAlias }
from Opt use {
module MutableOpt,
module ImmutableOpt as Imm,
type Opt,
type Opt as OptAlias,
}
from Opt use { /* comment1 */ /* comment2 */ /* comment3 */ /* comment4 */ /* comment5 */ /* comment6 */ /* comment7 */
MutableOpt,
ImmutableOpt as Imm,
module MutableOpt,
module ImmutableOpt as Imm,
type Opt,
type Opt as OptAlias,
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/test/grainfmt/includes.input.gr
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ include "option" as
include /* special include */ "array"
include "array" as /* special include */ Foo
from List use { length, map, forEach as each }
from Opt use { MutableOpt, ImmutableOpt as Imm, type Opt, type Opt as OptAlias }
from Opt use { MutableOpt, /* comment1 */ ImmutableOpt /* comment2 */ as /* comment3 */ Imm /* comment4 */, /* comment5 */ type /* comment6 */ Opt, type Opt as /* comment7 */ OptAlias }
from Opt use { module MutableOpt, module ImmutableOpt as Imm, type Opt, type Opt as OptAlias }
from Opt use { module MutableOpt, /* comment1 */ module ImmutableOpt /* comment2 */ as /* comment3 */ Imm /* comment4 */, /* comment5 */ type /* comment6 */ Opt, type Opt as /* comment7 */ OptAlias }

include "runtime/unsafe/wasmi32"
from WasmI32 use {
Expand Down
6 changes: 3 additions & 3 deletions compiler/test/input/modules/provideIncludedModule.gr
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module ProvideIncludedModule
include "option" as Option
include "array" as Array

provide { Option as Smoption }
provide { module Option as Smoption }

module Qux {
provide let val = 9
provide module Quux {
provide { Array }
provide { module Array }
}
}

provide { Qux }
provide { module Qux }
2 changes: 1 addition & 1 deletion compiler/test/input/nestedModules.gr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Foo {
provide let foo = "hello from foo"
provide module Bar {
provide let bar = "hello from bar"
provide { List }
provide { module List }
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/array.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ assert Array.chunk(3, [> 1, 2, 3, 4, 5, 6, 7, 8]) ==
assert Array.chunk(10, [> 1, 2, 3, 4, 5]) == [> [> 1, 2, 3, 4, 5]]

module Immutable {
from Array use { Immutable as Array }
from Array use { module Immutable as Array }

let fromList = Array.fromList
let arr = fromList([1, 2, 3])
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/map.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ Map.update(
assert Map.contains("c", toUpdate) == false

module Immutable {
from Map use { Immutable as Map }
from Map use { module Immutable as Map }

let strKeys = Map.fromList([("🌾", 1), ("🐑", 2), ("🧱", 3)])
let numKeys = Map.fromList([(1, "🌾"), (2, "🐑"), (3, "🧱")])
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/priorityqueue.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ assert PriorityQueue.fromList(Array.toList(lotsOfVals), compare) ==
PriorityQueue.fromArray(lotsOfVals, compare)

module Immutable {
from PriorityQueue use { Immutable as PriorityQueue }
from PriorityQueue use { module Immutable as PriorityQueue }

// formatter-ignore
let lotsOfVals = [>
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/queue.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ assert Queue.pop(queue) == Some(10)
assert Queue.pop(queue) == None

module Immutable {
from Queue use { Immutable as Queue }
from Queue use { module Immutable as Queue }

// 1 <- 2 <- 3
let sampleQueue = Queue.push(3, Queue.push(2, Queue.push(1, Queue.empty)))
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/range.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ assert Range.map(toString, exclusiveDescendingRange) == ["5", "4", "3", "2"]
assert Range.map(toString, exclusiveSameRange) == []

module Inclusive {
from Range use { Inclusive as Range }
from Range use { module Inclusive as Range }

let inclusiveAscendingRange = { rangeStart: 1, rangeEnd: 5 }
let inclusiveDescendingRange = { rangeStart: 5, rangeEnd: 1 }
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/set.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ let largeSet = Set.fromArray(Array.init(128, i => i))
assert Set.getInternalStats(largeSet) == (128, 64)

module Immutable {
from Set use { Immutable as Set }
from Set use { module Immutable as Set }

// Set.isEmpty

Expand Down
2 changes: 1 addition & 1 deletion compiler/test/stdlib/stack.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Stack.push(0, stack2)
assert stack == stack2

module Immutable {
from Stack use { Immutable as Stack }
from Stack use { module Immutable as Stack }

// 1 <- 2 <- 3
let sampleStack = Stack.push(3, Stack.push(2, Stack.push(1, Stack.empty)))
Expand Down
20 changes: 15 additions & 5 deletions compiler/test/suites/includes.re
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,24 @@ describe("includes", ({test, testSkip}) => {
);
assertCompileError(
"include_some_error3",
"include \"provideAll\" as ProvideAll; from ProvideAll use {Foo}; a",
"include \"provideAll\" as ProvideAll; from ProvideAll use {module Foo}",
"Unbound module Foo in module ProvideAll",
);
assertCompileError(
"include_some_error3",
"include \"provideAll\" as ProvideAll; from ProvideAll use {x, Foo}; a",
"include_some_error4",
"include \"provideAll\" as ProvideAll; from ProvideAll use {x, module Foo}",
"Unbound module Foo in module ProvideAll",
);
assertCompileError(
"include_some_error5",
"include \"provideAll\" as ProvideAll; from ProvideAll use {Foo}",
"Expected a lowercase identifier to use a value, the keyword `module` followed by an uppercase identifier to use a module, or the keyword `type` followed by an uppercase identifier to use a type.",
);
assertCompileError(
"include_some_error6",
"include \"provideAll\" as ProvideAll; from ProvideAll use {a, Foo}",
"Expected a lowercase identifier to use a value, the keyword `module` followed by an uppercase identifier to use a module, the keyword `type` followed by an uppercase identifier to use a type, or `}` to end the use statement.",
);
/* include module tests */
assertSnapshot("include_module", "include \"provideAll\" as Foo; Foo.x");
assertSnapshot(
Expand All @@ -94,12 +104,12 @@ describe("includes", ({test, testSkip}) => {
/* use well-formedness errors */
assertCompileError(
"include_alias_illegal_renaming",
"include \"list\" as List; from List use {Cons as cons, Empty}; cons(3, Empty)",
"include \"list\" as List; from List use {module Cons as cons, module Empty}; cons(3, Empty)",
"Expected an uppercase module alias",
);
assertCompileError(
"include_alias_illegal_renaming2",
"include \"list\" as List; from List use {sum as Sum, Empty}; sum(Empty)",
"include \"list\" as List; from List use {sum as Sum, module Empty}; sum(Empty)",
"Expected a lowercase alias",
);
assertCompileError(
Expand Down
4 changes: 2 additions & 2 deletions compiler/test/suites/modules.re
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe("modules", ({test, testSkip}) => {
provide let foo = "foo2"
}
}
from Foo use { foo, type Foo, Foo }
from Foo use { foo, type Foo, module Foo }
print(foo)
print(Foo.foo)
print(Foo)
Expand Down Expand Up @@ -137,7 +137,7 @@ describe("modules", ({test, testSkip}) => {
module ReprovidedSimple
include "simpleModule"
provide { Simple }
provide { module Simple }
|},
);
let ic = open_in_bin(outfile);
Expand Down
14 changes: 12 additions & 2 deletions compiler/test/suites/provides.re
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe("provides", ({test, testSkip}) => {
);
assertCompileError(
"provide11",
"enum Foo { Bar }; provide { Bar }",
"enum Foo { Bar }; provide { module Bar }",
"Unbound module Bar",
);
assertSnapshot(
Expand All @@ -99,6 +99,16 @@ describe("provides", ({test, testSkip}) => {
ProvidedType.apply((arg) => print("ok"))
|},
);
assertCompileError(
"provide13",
"module Nested { let val = 1 }; provide { Nested }",
"Expected a lowercase identifier to provide a value, the keyword `module` followed by an uppercase identifier to provide a module, or the keyword `type` followed by an uppercase identifier to provide a type.",
);
assertCompileError(
"provide13",
"let a = 1; module Nested { let val = 1 }; provide { a, Nested }",
"Expected a lowercase identifier to provide a value, the keyword `module` followed by an uppercase identifier to provide a module, the keyword `type` followed by an uppercase identifier to provide a type, or `}` to end the provide statement.",
);
assertCompileError(
"regression_issue_1489",
"provide { foo }",
Expand Down Expand Up @@ -131,7 +141,7 @@ describe("provides", ({test, testSkip}) => {
);
assertCompileError(
"multiple_provides_6",
"provide module Foo {void}; provide {Foo}",
"provide module Foo {void}; provide {module Foo}",
"provided multiple times",
);
assertCompileError(
Expand Down

0 comments on commit 5efb54c

Please sign in to comment.