Skip to content

Commit

Permalink
Convert import to statement instead of pseudo-fun
Browse files Browse the repository at this point in the history
Currently `import` is treated as a very special function that only
accepts literal string as its first argument. It has following
downsides:

* Special handling of `import` is hidden. User can assume that its
  just a function while it's a special keyword. User might expect to
  be able to pass variables to it while it is only handled before
  typechecking and evaluation.
* We can't extend `import` functionality without introducing new
  keywords which is not backward-compatible.

This change makes `import` into another statement like `let` or `fun`,
which means it cannot be confused with a function anymore. It also means
that expressions like `import "foo.ncl" bar` and
`import "foo.ncl" & {..}` are invalid, and `import` statement need to be
put in parethesis: `(import "foo.ncl") bar`.

For more context, see discussion in
#329 (comment)
  • Loading branch information
YorikSar committed May 4, 2023
1 parent 9ba6a37 commit a0d463f
Show file tree
Hide file tree
Showing 8 changed files with 28 additions and 8 deletions.
1 change: 1 addition & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Breaking changes
- Stdlib `string.Stringingable` -> `string.Stringable` by @vkleen in https://github.com/tweag/nickel/pull/1180
- Fix the type of `array.elem` by @yannham in https://github.com/tweag/nickel/pull/1223
- Change the enum tag start delimiter from backtick to single-quote by @vkleen in https://github.com/tweag/nickel/pull/1279
- `import` is now a statement, `import "foo.ncl" arg1 arg2` requires parenthesis now: `(import "foo.ncl") arg1 arg2`, see https://github.com/tweag/nickel/pull/1293

Language features
-----------------
Expand Down
2 changes: 1 addition & 1 deletion benches/mantis/deploy-example.ncl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "deploy.ncl"
(import "deploy.ncl")
{
namespace = "mantis-staging",
job = "miner",
Expand Down
2 changes: 1 addition & 1 deletion benches/mantis/deploy.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ fun vars =>
}
in
let jobDefs = {
Mantis = import "jobs/mantis.ncl" params,
Mantis = (import "jobs/mantis.ncl") params,
}
in
let revisions = {
Expand Down
2 changes: 1 addition & 1 deletion doc/manual/merging.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ configuration, from which other fields are derived:
`greeter` can then be customized without interfering with the final output:

```console
$ nickel export <<< 'import "hello-service.ncl" & {greeter = "country"}'
$ nickel export <<< '(import "hello-service.ncl") & {greeter = "country"}'
{
"systemd": {
"services": {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ UniTerm: UniTerm = {
<err: Error> => {
UniTerm::from(err)
},
"import" <s: StandardStaticString> => UniTerm::from(Term::Import(OsString::from(s))),
};

AnnotatedInfixExpr: UniTerm = {
Expand Down Expand Up @@ -276,7 +277,6 @@ Forall: Types =
// A n-ary application-like expression (n may be 0, in the sense that this rule
// also includes previous levels).
Applicative: UniTerm = {
"import" <s: StandardStaticString> => UniTerm::from(Term::Import(OsString::from(s))),
AsUniTerm<WithPos<TypeArray>>,
<t1: AsTerm<Applicative>> <t2: AsTerm<RecordOperand>> =>
UniTerm::from(mk_app!(t1, t2)),
Expand Down
20 changes: 20 additions & 0 deletions src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,3 +571,23 @@ fn ty_var_kind_mismatch() {
)
}
}

#[test]
fn import() {
assert_eq!(
parse_without_pos("import \"file.ncl\""),
mk_term::import("file.ncl")
);
assert_matches!(
parse("import \"file.ncl\" some args"),
Err(ParseError::UnexpectedToken(_, _))
);
assert_eq!(
parse_without_pos("(import \"file.ncl\") some args"),
mk_app!(
mk_term::import("file.ncl"),
mk_term::var("some"),
mk_term::var("args")
)
);
}
5 changes: 2 additions & 3 deletions tests/integration/pass/import.ncl
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
let {Assert, ..} = import "lib/assert.ncl" in

(import "lib/imported.ncl" 3 == 3 | Assert)
let { Assert, .. } = import "lib/assert.ncl" in
((import "lib/imported.ncl") 3 == 3 | Assert)
2 changes: 1 addition & 1 deletion tests/integration/pass/typechecking.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ let typecheck = [
(let x = {val : Number | doc "some" | default = 1}.val in x + 1) : Number,

# Typed import
import "lib/typed-import.ncl" : Number,
(import "lib/typed-import.ncl") : Number,

# Regression test for #430 (https://github.com/tweag/nickel/issues/430)
let x = import "lib/typed-import.ncl"
Expand Down

0 comments on commit a0d463f

Please sign in to comment.