From f553b8091c4d5d8bbd0189bb91d2b81dd059ff10 Mon Sep 17 00:00:00 2001 From: Yuriy Taraday Date: Thu, 4 May 2023 17:25:16 +0200 Subject: [PATCH] Convert `import` to statement instead of pseudo-fun (#1293) 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 https://github.com/tweag/nickel/issues/329#issuecomment-1531333491 --- RELEASES.md | 1 + benches/mantis/deploy-example.ncl | 2 +- benches/mantis/deploy.ncl | 2 +- doc/manual/merging.md | 2 +- src/parser/grammar.lalrpop | 2 +- src/parser/tests.rs | 20 ++++++++++++++++++++ tests/integration/pass/import.ncl | 5 ++--- tests/integration/pass/typechecking.ncl | 2 +- 8 files changed, 28 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 420048fbcf..d11f92f385 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -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 ----------------- diff --git a/benches/mantis/deploy-example.ncl b/benches/mantis/deploy-example.ncl index 08ab3cc40f..8b55b2fa6f 100644 --- a/benches/mantis/deploy-example.ncl +++ b/benches/mantis/deploy-example.ncl @@ -1,4 +1,4 @@ -import "deploy.ncl" +(import "deploy.ncl") { namespace = "mantis-staging", job = "miner", diff --git a/benches/mantis/deploy.ncl b/benches/mantis/deploy.ncl index fa9b9648d8..1b450e28db 100644 --- a/benches/mantis/deploy.ncl +++ b/benches/mantis/deploy.ncl @@ -67,7 +67,7 @@ fun vars => } in let jobDefs = { - Mantis = import "jobs/mantis.ncl" params, + Mantis = (import "jobs/mantis.ncl") params, } in let revisions = { diff --git a/doc/manual/merging.md b/doc/manual/merging.md index 05bac44e7d..3272d4818e 100644 --- a/doc/manual/merging.md +++ b/doc/manual/merging.md @@ -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": { diff --git a/src/parser/grammar.lalrpop b/src/parser/grammar.lalrpop index 85a5988b25..0c34a0dbdd 100644 --- a/src/parser/grammar.lalrpop +++ b/src/parser/grammar.lalrpop @@ -244,6 +244,7 @@ UniTerm: UniTerm = { => { UniTerm::from(err) }, + "import" => UniTerm::from(Term::Import(OsString::from(s))), }; AnnotatedInfixExpr: UniTerm = { @@ -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" => UniTerm::from(Term::Import(OsString::from(s))), AsUniTerm>, > > => UniTerm::from(mk_app!(t1, t2)), diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 25c8bdee54..8a8aca1e52 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -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") + ) + ); +} diff --git a/tests/integration/pass/import.ncl b/tests/integration/pass/import.ncl index b8290a4fba..bfec78bc88 100644 --- a/tests/integration/pass/import.ncl +++ b/tests/integration/pass/import.ncl @@ -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) diff --git a/tests/integration/pass/typechecking.ncl b/tests/integration/pass/typechecking.ncl index ad3decf1e6..4bfa2e7b3c 100644 --- a/tests/integration/pass/typechecking.ncl +++ b/tests/integration/pass/typechecking.ncl @@ -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"