unisonweb / unison

A friendly programming language from the future
https://unison-lang.org
Other
5.81k stars 271 forks source link

feat: namespace directive #5285

Closed mitchellwrosen closed 3 months ago

mitchellwrosen commented 3 months ago

Overview

This PR implements the "namespace directive" feature: a Unison file can contain an optional namespace foo line that affects parsing as follows:

  1. All bound names (type names, constructor names, generated accessor names, term names, and watch expression names) are prefixed with the namespace.
  2. Variables that refer to locally-bound names exactly are prefixed with the namespace.

That is,

namespace a.b.c

type Foo = Bar
type Qux = { quaf : Foo }

baz = ...

honk = ... baz ...

is equivalent to

type a.b.c.Foo = Bar
type a.b.c.Qux = { quaf : a.b.c.Foo }

a.b.c.baz = ...

a.b.c.honk = ... a.b.c.baz ...

Note that the existence of a namespace directive therefore prevents one from referring to a name outside of the file whose suffix matches something in the file.

For example, without a namespace directive, I could write

foo.factorial = ... foo.factorial ... factorial ...

and refer to both my locally-bound foo.factorial as well as a term literally named factorial (no other prefix) in the namespace. (N.B that's not true in trunk today, but it will be fixed soon: https://github.com/unisonweb/unison/issues/5268).

However, with a namespace directive...

namespace foo

factorial = ???

there's no way to write the same function (because factorial resolves to the locally-bound factorial, which will be expanded to foo.factorial during parsing).

For this reason, it would be unsafe to implement edit.namespace foo naively by putting a namespace foo directive at the top of the block.

Test coverage

I've added a transcript to demonstrate the feature.

hojberg commented 3 months ago

Very cool! Can you have multiple namespace directives in a file?

mitchellwrosen commented 3 months ago

@hojberg You cannot – zero or one

mitchellwrosen commented 3 months ago

@pchiusano I looked into this briefly, it really isn't more complicated than we're now parsing namespace as a Reserved lexeme rather than an Identifier lexeme, and go down different error paths from there. This could/should be cleaned up for sure, but I'm inclined to leave it alone for now as it also affects other reserved keywords in the same way.

pchiusano commented 3 months ago

@mitchellwrosen cool. Yeah I wouldn’t sweat it for this PR then.