Fix a bug with compiler metadata (#838)

1.  The metadata objects weren't being duplicated when duplicating
    the IR. This meant that the later passes would write metadata
    multiples times into one store (reference), causing wrong
    behaviour at codegen time.
This commit is contained in:
Ara Adkins 2020-06-16 13:52:11 +01:00 committed by GitHub
parent 1f46a3f9a1
commit 2f404b7f08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 795 additions and 445 deletions

View File

@ -29,6 +29,8 @@ The various components of Enso's syntax are described below:
- [**Encoding:**](./encoding.md) The source encoding of Enso files.
- [**Naming:**](./naming.md) The naming of Enso language constructs.
- [**Layout Rules:**](./layout.md) The layout rules for Enso code.
- [**Imports and Exports:**](./imports.md) The syntax and rules for importing
modules and exporting module functions.
- [**Literals:**](./literals.md) The syntax for Enso literals.
- [**Assignment:**](./assignment.md) The syntax for various forms of assignment
expression in Enso.

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Assignment Expressions
category: syntax
tags: [syntax, assignment]
order: 5
order: 6
---
# Assignment Expressions

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Comments
category: syntax
tags: [syntax, comments]
order: 12
order: 13
---
# Comments

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Function Arguments
category: syntax
tags: [syntax, functions]
order: 10
order: 11
---
# Function Arguments

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Defining Functions
category: syntax
tags: [syntax, functions]
order: 9
order: 10
---
# Defining Functions

118
docs/syntax/imports.md Normal file
View File

@ -0,0 +1,118 @@
---
layout: developer-doc
title: Imports and Exports
category: syntax
tags: [syntax, imports, modules]
order: 4
---
# Imports and Exports
In order to properly modularise and work with Enso code, the language provides
a robust mechanism for importing code from modules, and also re-exporting that
code from modules.
<!-- MarkdownTOC levels="2,3" autolink="true" -->
- [Import Syntax](#import-syntax)
- [Visibility of Imported Bindings](#visibility-of-imported-bindings)
- [Export Syntax](#export-syntax)
- [Visibility of Export Bindings](#visibility-of-export-bindings)
<!-- /MarkdownTOC -->
## Import Syntax
Importing a module is a way to bring its contents into scope in the current
module. Imports in Enso appear as follows:
- They start with the `import` keyword.
- The `import` keyword is followed by a module path (e.g. `Base.Vector.Unsafe`).
From there, Enso imports are broken up into four main categories:
1. **Unqualified Imports:** These import all symbols from the module into the
current scope, and consist only of the `import` keyword and a module path.
Imported items are imported accessible without qualification.
2. **Qualified Imports:** These import all symbols from the module into the
current scope with symbols qualified under a name _different_ from the
module name. It consists of the `import` keyword followed by a module path
followed by the `as` keyword, followed by a referent name.
3. **Restricted Imports:** These import only the specific symbols from the
module into the current scope. They consist of the `import` keyword, followed
by a module path, followed by the `only` keyword, followed by a
space-separated list of symbols.
4. **Hiding Imports:** These are the inverse of restricted imports, and import
_all_ symbols other than the named ones into the current scope. They consist
of the `import` keyword, followed by a module path, followed by the keyword
`only`, followed by a space-separated list of symbols.
The qualified import syntax can be combined with the restricted and hiding
import syntaxes.
By way of example, the following code uses a variety of import types:
```ruby
import A # unqualified
import B as T # qualified
import C only symbol_1 symbol_2 # restricted
import D hiding symbol_1 symbol_2 # hiding
import E as U only symbol_3 # qualified + restricted
import F as V hiding symbol_4 # qualified + hiding
```
Imports in Enso _may_ introduce ambiguous symbols, but this is not an error
until one of the ambiguous symbols is _used_ in Enso code.
### Visibility of Imported Bindings
When importing a module `X` into the current module `Y`, the bindings from `X`
made available by the import (see above) become available in `Y`. However, Enso
does not re-export imported bindings from a module by default, so the imported
bindings from `X` are not visible in a module _importing_ `Y`.
## Export Syntax
In order to allow for easy composition and aggregation of code, Enso provides
its users with a mechanism to _export_ imported elements from modules. They
appear in Enso as follows:
- They start with the `export` keyword.
- The `export` keyword is followed by a module name (e.g. `My_Module`) that is
available in the current scope.
- The _current_ module is implicitly exported unqualified.
From there, Enso exports are broken up into four main categories:
1. **Unqualified Exports:** These export all symbols from the named module as
if they were defined in the exporting module. They consist of the `export`
keyword, followed by a visible module name.
2. **Qualified Exports:** These export all symbols from the module as if they
were defined in a module nested within the exporting module. It consists of
the `export` keyword, followed by a module name, followed by the `as`
keyword, followed by another module name.
3. **Restricted Exports:** These export only the specified symbols from the
exporting module, as if they were defined in the exporting module. It
consists of the `export` keyword, followed by a module name, followed by the
`only` keyword, and then a space-separated list of symbols.
4. **Hiding Exports:** These export all symbols from the module _except_ those
explicitly specified. It consists of the `export` keyword, followed by a
module name, followed by the `hiding` keyword, and then a space-separated
list of symbols.
The qualified export syntax can be combined with the restricted and hiding
export syntaxes.
By way of example, the following code uses a variety of export types:
```ruby
export A
export B as X
export C only symbol_1
export D hiding symbol_1
export E as Y only symbol_1
export F as Y hiding symbol_1
```
In essence, an export allows the user to `paste` the contents of the module
being exported into the module declaring the export. This means that exports
that create name clashes need to be resolved at the _export_ site.
### Visibility of Export Bindings
Bindings exported from a module `X` are available in an identical fashion to
bindings that are _defined_ in the module `X`.

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Literals
category: syntax
tags: [syntax, literals]
order: 4
order: 5
---
# Literals

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: The Enso Macro Syntax
category: syntax
tags: [syntax, macro]
order: 7
order: 8
---
# The Enso Macro Syntax

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Projections and Field Access
category: syntax
tags: [syntax, projections, field-access, pattern-matching]
order: 11
order: 12
---
# Projections and Field Access

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Enso Top-Level Syntax
category: syntax
tags: [syntax, top-level, file]
order: 8
order: 9
---
# Enso Top-Level Syntax

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Types and Type Signatures
category: syntax
tags: [syntax, types]
order: 6
order: 7
---
# Types and Type Signatures
@ -319,18 +319,48 @@ sometimes the case that it is necessary to indicate that certain fields should
not be touched (as this might break invariants and such like). To this end, we
propose an explicit mechanism for access modification that works as follows:
- We provide explicit access modifiers that, at the definition site, start an
indented block. These are `private` and `unsafe`.
- All members in the block have the access modifier attributed to them.
- By default, accessing any member under an access modifier will be an error.
- To use members under an access modifier, you use the syntax `use <mod>`, where
`<mod>` is a modifier. This syntax 'takes' an expression, including blocks,
within which the user may access members qualified by the modifier `<mod>`.
- We have a set of access modifiers, namely `private` and `unsafe`.
- We can place these modifiers before a top-level definition.
```ruby
type MyAtomType
type MyAtom a
is_foo : Boolean
is_foo = ...
private private_method a b = ...
unsafe unsafe_method a b = ...
```
- By default, accessing any member under an access modifier is an error when
performed from another module.
- To use members protected by an access modifier, you must _import_ that access
modifier from the file in which you want to access those elements.
```ruby
import private Base.Vector
import unsafe Base.Atom
```
- These modified imports are available in _all_ scopes, so it is possible to
limit the scope in which you have access to the modified definitions.
```ruby
function_using_modifiers v x =
import private Base.Vector
import unsafe Base.Atom
v.mutate_at_index 0 (_ -> x)
x = MyAtom.mutate_field name="sum" (with = x -> x + 20)
x + 20
```
While `private` works as you might expect, coming from other languages, the
`unsafe` annotation has additional restrictions:
- It must be explicitly imported from `Std.Unsafe`.
- It must be explicitly imported from `Base.Unsafe`.
- When you use `unsafe`, you must write a documentation comment on its usage
that contains a section `Safety` that describes why this usage of unsafe is
valid.

View File

@ -23,13 +23,43 @@ provides an explicit mechanism for access modification.
## Access Modification
Access modifiers in Enso work as follows:
- We provide explicit access modifiers that, at the definition site, start an
indented block.
- All members in the block have the access modifier attributed to them.
- By default, accessing any member under an access modifier will be an error.
- To use members under an access modifier, you use the syntax `use <mod>`, where
`<mod>` is a modifier. This syntax 'takes' an expression, including blocks,
within which the user may access members qualified by the modifier `<mod>`.
- We have a set of access modifiers, namely `private` and `unsafe`.
- We can place these modifiers before a top-level definition.
```ruby
type MyAtomType
type MyAtom a
is_foo : Boolean
is_foo = ...
private private_method a b = ...
unsafe unsafe_method a b = ...
```
- By default, accessing any member under an access modifier is an error when
performed from another module.
- To use members protected by an access modifier, you must _import_ that access
modifier from the file in which you want to access those elements.
```ruby
import private Base.Vector
import unsafe Base.Atom
```
- These modified imports are available in _all_ scopes, so it is possible to
limit the scope in which you have access to the modified definitions.
```ruby
function_using_modifiers v x =
import private Base.Vector
import unsafe Base.Atom
v.mutate_at_index 0 (_ -> x)
x = MyAtom.mutate_field name="sum" (with = x -> x + 20)
x + 20
```
> The actionables for this section are:
>
@ -40,13 +70,13 @@ The `private` modifier acts to hide implementation details from clients of the
API. It is:
- Available by default in the `Base` library.
- Able to be overridden using the above-described mechanism.
- Able to be avoided using the above-described mechanism.
## Unsafe
While `private` works as you might expect, coming from other languages, the
`unsafe` annotation has additional restrictions:
- It must be explicitly imported from `Std.Unsafe`.
- It must be explicitly imported from `Base.Unsafe`.
- When you use `unsafe`, you must write a documentation comment on its usage
that contains a section `Safety` that describes why this usage of unsafe is
valid.

View File

@ -37,16 +37,16 @@ most languages, Enso provides an _import_ mechanism for this. Enso has four
different kinds of imports that may be combined freely, all of which take a
module path as their first argument.
1. **Unqualified Imports:** These import all symbols from the module into the
current scope (`import M`).
2. **Qualified Imports:** These import all symbols from the module into the
current scope with symbols qualified under a name _different_ from the
module name (`import M as T`).
3. **Restricted Imports:** These import only the specific symbols from the
module into the current scope (`import M only sym1 sym2`).
4. **Hiding Imports:** These are the inverse of restricted imports, and import
_all_ symbols other than the named ones into the current scope
(`import M hiding sym1 sym2`),
1. **Unqualified Imports:** These import all symbols from the module into the
current scope (`import M`).
2. **Qualified Imports:** These import all symbols from the module into the
current scope with symbols qualified under a name _different_ from the
module name (`import M as T`).
3. **Restricted Imports:** These import only the specific symbols from the
module into the current scope (`import M only sym1 sym2`).
4. **Hiding Imports:** These are the inverse of restricted imports, and import
_all_ symbols other than the named ones into the current scope
(`import M hiding sym1 sym2`),
Imports may introduce ambiguous symbols, but this is not an error until one of
the ambiguous symbols is used in user code.
@ -58,15 +58,15 @@ mechanism. Similarly to imports, this has four kinds, all of which take a module
path as their first argument, and all of which _may_ introduce the module it
exports into scope (if it is not already imported).
1. **Unqualified Exports:** These export all symbols from the module as if they
were defined in the exporting module (`export X`).
2. **Qualified Exports:** These export all symbols from the module as if they
were defined in another module accessible in the exporting module
(`export X as Y`).
3. **Restricted Exports:** These export only the specified symbols from the
module as if they were defined in the exporting module (`export X only sym`)
4. **Hiding Exports:** These export all symbols from the module except those
explicitly specified (`export X hiding sym1 sym2`).
1. **Unqualified Exports:** These export all symbols from the module as if they
were defined in the exporting module (`export X`).
2. **Qualified Exports:** These export all symbols from the module as if they
were defined in another module accessible in the exporting module
(`export X as Y`).
3. **Restricted Exports:** These export only the specified symbols from the
module as if they were defined in the exporting module (`export X only sym`)
4. **Hiding Exports:** These export all symbols from the module except those
explicitly specified (`export X hiding sym1 sym2`).
Exports effectively act to 'paste' the contents of the exported module into the
module declaring the export. This means that exports that create name clashes

View File

@ -818,11 +818,16 @@ object AstToIr {
* @param imp the import to translate
* @return the [[IR]] representation of `imp`
*/
def translateImport(imp: AST.Import): Module.Scope.Import.Module = {
Module.Scope.Import.Module(
imp.path.map(t => t.name).reduceLeft((l, r) => l + "." + r),
getIdentifiedLocation(imp)
)
def translateImport(imp: AST.Import): Module.Scope.Import = {
imp.path match {
case AstView.ModulePath(segments) =>
IR.Module.Scope.Import.Module(
segments.map(_.name).mkString("."),
getIdentifiedLocation(imp.path)
)
case _ =>
IR.Error.Syntax(imp, IR.Error.Syntax.InvalidImport)
}
}
/** Translates an arbitrary invalid expression from the [[AST]] representation

View File

@ -405,6 +405,23 @@ object AstView {
}
}
object ModulePath {
/** Matches on a module path of the form `A.B.C...`, as seen in an import.
*
* @param ast the structure to try and match on
* @return the list of segments in the module path
*/
def unapply(ast: AST): Option[List[AST.Ident]] = ast match {
case AST.Ident.Cons.any(name) => Some(List(name))
case OperatorDot(left, AST.Ident.Cons.any(name)) => left match {
case ModulePath(elems) => Some(elems :+ name)
case _ => None
}
case _ => None
}
}
object SuspendDefaultsOperator {
/** Matches on a usage of the `...` 'suspend defaults' operator.

View File

@ -147,6 +147,7 @@ class IrToTruffle(
)
case i: Import.Module =>
this.moduleScope.addImport(context.getCompiler.processImport(i.name))
case _: Error =>
}
// Register the atoms and their constructors in scope

View File

@ -2,12 +2,8 @@ package org.enso.compiler.core
import java.util.UUID
import org.enso.compiler.core.IR.{
DiagnosticStorage,
Expression,
IdentifiedLocation
}
import org.enso.compiler.core.ir.MetadataStorage
import org.enso.compiler.core.IR.{Expression, IdentifiedLocation}
import org.enso.compiler.core.ir.{DiagnosticStorage, MetadataStorage}
import org.enso.compiler.core.ir.MetadataStorage.MetadataPair
import org.enso.compiler.exception.CompilerError
import org.enso.compiler.pass.IRPass
@ -228,10 +224,11 @@ object IR {
keepDiagnostics: Boolean = true
): Empty =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Empty =
@ -315,10 +312,11 @@ object IR {
bindings = bindings.map(
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Module =
@ -440,9 +438,10 @@ object IR {
): Module =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -540,9 +539,10 @@ object IR {
): Polyglot =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -637,9 +637,10 @@ object IR {
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -742,9 +743,10 @@ object IR {
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -858,9 +860,11 @@ object IR {
body =
body.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy
else DiagnosticStorage(),
id = randomId
)
@ -970,9 +974,11 @@ object IR {
body =
body.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy
else DiagnosticStorage(),
id = randomId
)
@ -1119,9 +1125,10 @@ object IR {
returnValue =
returnValue.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1215,9 +1222,10 @@ object IR {
expression =
expression.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1304,9 +1312,10 @@ object IR {
): Number =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1373,9 +1382,10 @@ object IR {
): Text =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1495,10 +1505,11 @@ object IR {
typePointer.duplicate(keepLocations, keepMetadata, keepDiagnostics),
methodName =
methodName.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def mapExpressions(
@ -1633,9 +1644,10 @@ object IR {
): Blank =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1703,9 +1715,10 @@ object IR {
): Literal =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1770,9 +1783,10 @@ object IR {
): This =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1837,9 +1851,10 @@ object IR {
): Here =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -1934,9 +1949,10 @@ object IR {
signature =
signature.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2020,9 +2036,10 @@ object IR {
context =
context.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2099,12 +2116,13 @@ object IR {
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): Error = copy(
typed = typed.duplicate(keepLocations, keepMetadata, keepDiagnostics),
error = error.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
typed = typed.duplicate(keepLocations, keepMetadata, keepDiagnostics),
error = error.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Error =
@ -2201,9 +2219,10 @@ object IR {
memberType.duplicate(keepLocations, keepMetadata, keepDiagnostics),
value = value.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2294,9 +2313,10 @@ object IR {
right =
right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2379,9 +2399,10 @@ object IR {
left = left.duplicate(keepLocations, keepMetadata, keepDiagnostics),
right = right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2462,9 +2483,10 @@ object IR {
left = left.duplicate(keepLocations, keepMetadata, keepDiagnostics),
right = right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2544,9 +2566,10 @@ object IR {
left = left.duplicate(keepLocations, keepMetadata, keepDiagnostics),
right = right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2628,9 +2651,10 @@ object IR {
right =
right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2715,9 +2739,10 @@ object IR {
right =
right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -2843,11 +2868,12 @@ object IR {
arguments = arguments.map(
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
body = body.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
body = body.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Lambda =
@ -2951,11 +2977,12 @@ object IR {
arguments = arguments.map(
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
body = body.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
body = body.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Binding =
@ -3092,10 +3119,11 @@ object IR {
defaultValue = defaultValue.map(
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(
@ -3212,10 +3240,11 @@ object IR {
arguments = arguments.map(
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Prefix =
@ -3289,11 +3318,12 @@ object IR {
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): Force = copy(
target = target.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
target = target.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Force =
@ -3384,9 +3414,10 @@ object IR {
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -3465,9 +3496,10 @@ object IR {
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -3563,9 +3595,10 @@ object IR {
operator.duplicate(keepLocations, keepMetadata, keepDiagnostics),
right = right.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -3660,9 +3693,10 @@ object IR {
operator =
operator.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -3738,9 +3772,10 @@ object IR {
operator =
operator.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -3818,9 +3853,10 @@ object IR {
operator.duplicate(keepLocations, keepMetadata, keepDiagnostics),
arg = arg.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -3950,11 +3986,12 @@ object IR {
): Specified = copy(
name =
name.map(_.duplicate(keepLocations, keepMetadata, keepDiagnostics)),
value = value.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
value = value.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(
@ -4053,12 +4090,14 @@ object IR {
): Expr = copy(
scrutinee =
scrutinee.duplicate(keepLocations, keepMetadata, keepDiagnostics),
branches =
branches.map(_.duplicate(keepLocations, keepMetadata, keepDiagnostics)),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
branches = branches.map(
_.duplicate(keepLocations, keepMetadata, keepDiagnostics)
),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Expr =
@ -4146,10 +4185,11 @@ object IR {
pattern.duplicate(keepLocations, keepMetadata, keepDiagnostics),
expression =
expression.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(location: Option[IdentifiedLocation]): Branch =
@ -4244,11 +4284,12 @@ object IR {
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): Name = copy(
name = name.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
name = name.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def mapExpressions(fn: Expression => Expression): Name = {
@ -4327,10 +4368,11 @@ object IR {
constructor.duplicate(keepLocations, keepMetadata, keepDiagnostics),
fields =
fields.map(_.duplicate(keepLocations, keepMetadata, keepDiagnostics)),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
/** Checks if the constructor pattern has been desugared.
@ -4457,9 +4499,10 @@ object IR {
): Documentation =
copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -4549,10 +4592,11 @@ object IR {
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): Definition = copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(
@ -4749,6 +4793,7 @@ object IR {
) extends Error
with Diagnostic.Kind.Interactive
with IR.Module.Scope.Definition
with IR.Module.Scope.Import
with IRKind.Primitive {
override protected var id: Identifier = randomId
@ -4779,9 +4824,10 @@ object IR {
keepDiagnostics: Boolean = true
): Syntax =
copy(
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -4834,6 +4880,11 @@ object IR {
s"Cannot define a pattern outside a pattern context."
}
case object InvalidImport extends Reason {
override def explanation: String =
s"Imports must have a valid module path."
}
case object InvalidStandaloneSignature extends Reason {
override def explanation: String =
s"Invalid stand-alone signature expression."
@ -4938,10 +4989,11 @@ object IR {
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): InvalidIR = copy(
ir = ir.duplicate(keepLocations, keepMetadata, keepDiagnostics),
passData = if (keepMetadata) passData else MetadataStorage(),
diagnostics = if (keepDiagnostics) diagnostics else DiagnosticStorage(),
id = randomId
ir = ir.duplicate(keepLocations, keepMetadata, keepDiagnostics),
passData = if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
override def setLocation(
@ -5027,9 +5079,10 @@ object IR {
keepDiagnostics: Boolean = true
): ThisArg = copy(
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -5106,9 +5159,10 @@ object IR {
methodName =
methodName.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -5190,9 +5244,10 @@ object IR {
atomName =
atomName.duplicate(keepLocations, keepMetadata, keepDiagnostics),
location = if (keepLocations) location else None,
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -5266,9 +5321,10 @@ object IR {
): Binding = copy(
invalidBinding = invalidBinding
.duplicate(keepLocations, keepMetadata, keepDiagnostics),
passData = if (keepMetadata) passData else MetadataStorage(),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -5376,10 +5432,11 @@ object IR {
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): TypeSignature = copy(
ir = ir.duplicate(keepLocations, keepMetadata, keepDiagnostics),
passData = if (keepMetadata) passData else MetadataStorage(),
ir = ir.duplicate(keepLocations, keepMetadata, keepDiagnostics),
passData =
if (keepMetadata) passData.duplicate else MetadataStorage(),
diagnostics =
if (keepDiagnostics) diagnostics else DiagnosticStorage(),
if (keepDiagnostics) diagnostics.copy else DiagnosticStorage(),
id = randomId
)
@ -5463,130 +5520,6 @@ object IR {
}
}
// ==========================================================================
// === Diagnostics Storage ==================================================
// ==========================================================================
/** Storage for diagnostics in IR nodes.
*
* @param initDiagnostics the initial diagnostics
*/
sealed class DiagnosticStorage(initDiagnostics: Seq[Diagnostic] = Seq()) {
private var diagnostics: List[Diagnostic] = initDiagnostics.toList
/** Adds a new diagnostic to the storage
*
* @param diagnostic the new diagnostic to store
*/
def add(diagnostic: Diagnostic): Unit = {
diagnostics = diagnostic :: diagnostics
}
/** Adds new diagnostics to the storage.
*
* @param newDiagnostics the new diagnostics to store
*/
def add(newDiagnostics: Seq[Diagnostic]): Unit = {
diagnostics = newDiagnostics.toList ::: diagnostics
}
/** Applies the function `f` across the diagnostic storage, producing a
* result sequence.
*
* @param f the function to apply
* @tparam R the result type of `f`
* @return the sequence that results from applying `f` over the storage
*/
def map[R](f: IR.Diagnostic => R): Seq[R] = {
diagnostics.map(f)
}
/** Applies the function `f` across the diagnostic storage in place.
*
* @param f the function to apply
*/
def mapInPlace(f: IR.Diagnostic => IR.Diagnostic): Unit = {
diagnostics = diagnostics.map(f)
}
/** Performs a collection operation on the diagnostics storage, producing
* a new sequence.
*
* @param pf the partial function to apply
* @tparam R the result type of the partial function
* @return the result of collecting across the storage with `pf`
*/
def collect[R](pf: PartialFunction[IR.Diagnostic, R]): Seq[R] = {
diagnostics.collect(pf)
}
/** Filters the elements of the diagnostic storage using the predicate.
*
* @param pred the predicate to filter with
* @return a new diagnostic storage instance containing elements matching
* `pred`
*/
def filter(pred: IR.Diagnostic => Boolean): DiagnosticStorage = {
new DiagnosticStorage(diagnostics.filter(pred))
}
/** Filters the elements of the diagnostic storage in place using the
* predicate.
*
* @param pred the predicate to filter with
*/
def filterInPlace(pred: IR.Diagnostic => Boolean): Unit = {
diagnostics = diagnostics.filter(pred)
}
/** Performs a left fold over the diagnostic storage to produce a result.
*
* @param init the starting value
* @param op the operator to use to fold
* @tparam L the result type of the fold
* @return the result of folding over the storage using `op` starting wit
* `init`
*/
def foldLeft[L](init: L)(op: (L, IR.Diagnostic) => L): L = {
diagnostics.foldLeft(init)(op)
}
/** Checks two diagnostics storages for equality.
*
* @param obj the object to check against `this`
* @return `true` if `this == obj`, otherwise `false`
*/
override def equals(obj: Any): Boolean = obj match {
case that: DiagnosticStorage => this.diagnostics == that.diagnostics
case _ => false
}
/** Creates a string representation of `this` diagnostic storage.
*
* @return the string representation of `this`
*/
override def toString: String =
s"DiagnosticStorage(diagnostics = $diagnostics)"
/** Creates a list of the diagnostics contained in the diagnostics storage.
*
* @return a list of the diagnostics in the storage
*/
def toList: List[IR.Diagnostic] = {
diagnostics
}
}
object DiagnosticStorage {
/** Creates a new instance of the diagnostics storage.
*
* @param initDiagnostics the initial diagnostics to construct it with
* @return a new diagnostics storage instance
*/
def apply(initDiagnostics: Seq[Diagnostic] = Seq()): DiagnosticStorage =
new DiagnosticStorage(initDiagnostics)
}
// ==========================================================================
// === Useful Extension Methods =============================================
// ==========================================================================
@ -5658,12 +5591,12 @@ object IR {
/** Adds extension methods for working with lists of [[IR]].
*
* @param sequence the list
* @param list the list
* @tparam T the concrete IR type
*/
implicit class ListAsIr[T <: IR](sequence: List[T]) {
implicit class ListAsIr[T <: IR](list: List[T]) {
/** Calls [[IR.duplicate]] on the elemtsn in [[sequence]].
/** Calls [[IR.duplicate]] on the elements in [[list]].
*
* @param keepLocations whether or not locations should be kept in the
* duplicated IR
@ -5671,14 +5604,14 @@ object IR {
* the duplicated IR
* @param keepDiagnostics whether or not the diagnostics should be kept in
* the duplicated IR
* @return a duplicate of [[sequence]]
* @return a duplicate of [[list]]
*/
def duplicate(
keepLocations: Boolean = true,
keepMetadata: Boolean = true,
keepDiagnostics: Boolean = true
): List[T] = {
sequence
list
.map(_.duplicate(keepLocations, keepMetadata, keepDiagnostics))
.asInstanceOf[List[T]]
}

View File

@ -0,0 +1,134 @@
package org.enso.compiler.core.ir
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.Diagnostic
/** Storage for diagnostics in IR nodes.
*
* @param initDiagnostics the initial diagnostics
*/
sealed class DiagnosticStorage(initDiagnostics: Seq[Diagnostic] = Seq()) {
private var diagnostics: List[Diagnostic] = initDiagnostics.toList
/** Adds a new diagnostic to the storage
*
* @param diagnostic the new diagnostic to store
*/
def add(diagnostic: Diagnostic): Unit = {
diagnostics = diagnostic :: diagnostics
}
/** Adds new diagnostics to the storage.
*
* @param newDiagnostics the new diagnostics to store
*/
def add(newDiagnostics: Seq[Diagnostic]): Unit = {
diagnostics = newDiagnostics.toList ::: diagnostics
}
/** Applies the function `f` across the diagnostic storage, producing a
* result sequence.
*
* @param f the function to apply
* @tparam R the result type of `f`
* @return the sequence that results from applying `f` over the storage
*/
def map[R](f: IR.Diagnostic => R): Seq[R] = {
diagnostics.map(f)
}
/** Applies the function `f` across the diagnostic storage in place.
*
* @param f the function to apply
*/
def mapInPlace(f: IR.Diagnostic => IR.Diagnostic): Unit = {
diagnostics = diagnostics.map(f)
}
/** Performs a collection operation on the diagnostics storage, producing
* a new sequence.
*
* @param pf the partial function to apply
* @tparam R the result type of the partial function
* @return the result of collecting across the storage with `pf`
*/
def collect[R](pf: PartialFunction[IR.Diagnostic, R]): Seq[R] = {
diagnostics.collect(pf)
}
/** Filters the elements of the diagnostic storage using the predicate.
*
* @param pred the predicate to filter with
* @return a new diagnostic storage instance containing elements matching
* `pred`
*/
def filter(pred: IR.Diagnostic => Boolean): DiagnosticStorage = {
new DiagnosticStorage(diagnostics.filter(pred))
}
/** Filters the elements of the diagnostic storage in place using the
* predicate.
*
* @param pred the predicate to filter with
*/
def filterInPlace(pred: IR.Diagnostic => Boolean): Unit = {
diagnostics = diagnostics.filter(pred)
}
/** Performs a left fold over the diagnostic storage to produce a result.
*
* @param init the starting value
* @param op the operator to use to fold
* @tparam L the result type of the fold
* @return the result of folding over the storage using `op` starting wit
* `init`
*/
def foldLeft[L](init: L)(op: (L, IR.Diagnostic) => L): L = {
diagnostics.foldLeft(init)(op)
}
/** Checks two diagnostics storages for equality.
*
* @param obj the object to check against `this`
* @return `true` if `this == obj`, otherwise `false`
*/
override def equals(obj: Any): Boolean = obj match {
case that: DiagnosticStorage => this.diagnostics == that.diagnostics
case _ => false
}
/** Creates a string representation of `this` diagnostic storage.
*
* @return the string representation of `this`
*/
override def toString: String =
s"DiagnosticStorage(diagnostics = $diagnostics)"
/** Creates a list of the diagnostics contained in the diagnostics storage.
*
* @return a list of the diagnostics in the storage
*/
def toList: List[IR.Diagnostic] = {
diagnostics
}
/** Creates a shallow copy of `this`.
*
* This means that the diagnostic objects contained in `this` and the copy
* are the same objects.
*
* @return a shallow copy of this
*/
def copy: DiagnosticStorage = {
DiagnosticStorage(this.diagnostics)
}
}
object DiagnosticStorage {
/** Creates a new instance of the diagnostics storage.
*
* @param initDiagnostics the initial diagnostics to construct it with
* @return a new diagnostics storage instance
*/
def apply(initDiagnostics: Seq[Diagnostic] = Seq()): DiagnosticStorage =
new DiagnosticStorage(initDiagnostics)
}

View File

@ -13,9 +13,9 @@ import org.enso.compiler.pass.IRPass
class MetadataStorage(
startingMeta: Seq[MetadataPair[_]] = Seq()
) {
private val pairs: Seq[(IRPass, Any)] =
startingMeta.map(_.asPair.asInstanceOf[(IRPass, Any)])
private var metadata: Map[IRPass, Any] = Map(pairs: _*)
private var metadata: Map[IRPass, Any] = Map(
startingMeta.map(_.asPair.asInstanceOf[(IRPass, Any)]): _*
)
/** Adds a metadata pair to the node metadata.
*
@ -112,6 +112,19 @@ class MetadataStorage(
}
override def toString: String = metadata.toString()
/** Creates a deep copy of `this`.
*
* @return a deep copy of `this`
*/
def duplicate: MetadataStorage = {
val res = MetadataStorage()
res.metadata = this.metadata.map {
case (pass, meta) => (pass, meta.asInstanceOf[IRPass.Metadata].duplicate)
}
res
}
}
object MetadataStorage extends MetadataStorageSyntax {

View File

@ -128,12 +128,22 @@ object IRPass {
throw new CompilerError(s"Cannot cast $this to the requested type.")
)
}
/** Creates a duplicate of this metadata.
*
* This method should employ deep-copy semantics where appropriate.
*
* @return a duplicate of this metadata.
*/
def duplicate: Metadata
}
object Metadata {
/** An empty metadata type for passes that do not create any metadata. */
sealed case class Empty() extends Metadata {
override val metadataName: String = "Empty"
override def duplicate: Empty = Empty()
}
}
}

View File

@ -608,6 +608,8 @@ case object AliasAnalysis extends IRPass {
*/
sealed case class Root(override val graph: Graph) extends Scope {
override val metadataName: String = "AliasAnalysis.Info.Scope.Root"
override def duplicate: IRPass.Metadata = this.copy()
}
/** Aliasing information about a child scope.
@ -618,6 +620,8 @@ case object AliasAnalysis extends IRPass {
sealed case class Child(override val graph: Graph, scope: Graph.Scope)
extends Scope {
override val metadataName: String = "AliasAnalysis.Info.Scope.Child"
override def duplicate: IRPass.Metadata = this.copy()
}
}
@ -630,6 +634,8 @@ case object AliasAnalysis extends IRPass {
sealed case class Occurrence(override val graph: Graph, id: Graph.Id)
extends Info {
override val metadataName: String = "AliasAnalysis.Info.Occurrence"
override def duplicate: IRPass.Metadata = this.copy()
}
}

View File

@ -203,6 +203,8 @@ case object CachePreferenceAnalysis extends IRPass {
/** @return weights as the Java collection */
def asJavaWeights: util.Map[IR.ExternalId, java.lang.Double] =
weights.asJava.asInstanceOf[util.Map[IR.ExternalId, java.lang.Double]]
override def duplicate: IRPass.Metadata = copy()
}
/** Weight constants */

View File

@ -726,6 +726,8 @@ case object DataflowAnalysis extends IRPass {
combinedModule
}
override def duplicate: IRPass.Metadata = copy()
}
object DependencyInfo {

View File

@ -68,5 +68,8 @@ case object GatherDiagnostics extends IRPass {
/** The name of the metadata as a string. */
override val metadataName: String = "GatherDiagnostics.Diagnostics"
override def duplicate: IRPass.Metadata =
this.copy(diagnostics.map(identity))
}
}

View File

@ -423,6 +423,8 @@ case object TailCall extends IRPass {
final case object Tail extends TailPosition {
override val metadataName: String = "TailCall.TailPosition.Tail"
override def isTail: Boolean = true
override def duplicate: IRPass.Metadata = Tail
}
/** The expression is not in a tail position and cannot be tail call
@ -431,6 +433,8 @@ case object TailCall extends IRPass {
final case object NotTail extends TailPosition {
override val metadataName: String = "TailCall.TailPosition.NotTail"
override def isTail: Boolean = false
override def duplicate: IRPass.Metadata = NotTail
}
/** Implicitly converts a boolean to a [[TailPosition]] value.

View File

@ -237,18 +237,12 @@ case object ComplexType extends IRPass {
)
val newSig =
signature.map(sig =>
sig
.copy(typed =
methodRef.duplicate(keepMetadata = false, keepDiagnostics = false)
)
.duplicate(keepMetadata = false, keepDiagnostics = false)
)
signature.map(sig => sig.copy(typed = methodRef.duplicate()).duplicate())
val binding = Method.Binding(
methodRef.duplicate(keepMetadata = false, keepDiagnostics = false),
methodRef.duplicate(),
args,
body.duplicate(keepMetadata = false, keepDiagnostics = false),
body.duplicate(),
location
)

View File

@ -180,10 +180,7 @@ case object NestedPatternMatch extends IRPass {
val scrutineeBinding =
IR.Expression.Binding(scrutineeBindingName, scrutineeExpression, None)
val caseExprScrutinee = scrutineeBindingName.duplicate(
keepDiagnostics = false,
keepMetadata = false
)
val caseExprScrutinee = scrutineeBindingName.duplicate()
val processedBranches = branches.zipWithIndex.map {
case (branch, ix) =>
@ -240,7 +237,8 @@ case object NestedPatternMatch extends IRPass {
val newName = freshNameSupply.newName()
val newField = Pattern.Name(newName, None)
val nestedScrutinee =
newName.duplicate(keepDiagnostics = false, keepMetadata = false)
newName.duplicate()
newName.duplicate()
val newFields =
fields.take(nestedPosition) ++ (newField :: fields.drop(
@ -249,7 +247,7 @@ case object NestedPatternMatch extends IRPass {
val newPattern = cons.copy(
fields =
newFields.duplicate(keepDiagnostics = false, keepMetadata = false)
newFields.duplicate()
)
val newExpression = generateNestedCase(
@ -261,10 +259,8 @@ case object NestedPatternMatch extends IRPass {
)
val partDesugaredBranch = IR.Case.Branch(
pattern = newPattern
.duplicate(keepDiagnostics = false, keepMetadata = false),
expression = newExpression
.duplicate(keepDiagnostics = false, keepMetadata = false),
pattern = newPattern.duplicate(),
expression = newExpression.duplicate(),
None
)
@ -321,15 +317,15 @@ case object NestedPatternMatch extends IRPass {
remainingBranches: List[IR.Case.Branch]
): IR.Expression = {
val fallbackCase = IR.Case.Expr(
topLevelScrutineeExpr.duplicate(keepDiagnostics = false),
remainingBranches.duplicate(keepMetadata = false),
topLevelScrutineeExpr.duplicate(),
remainingBranches.duplicate(),
None
)
val patternBranch =
IR.Case.Branch(
pattern.duplicate(keepDiagnostics = false),
currentBranchExpr.duplicate(keepMetadata = false),
pattern.duplicate(),
currentBranchExpr.duplicate(),
None
)
val fallbackBranch = IR.Case.Branch(
@ -339,7 +335,7 @@ case object NestedPatternMatch extends IRPass {
)
IR.Case.Expr(
nestedScrutinee.duplicate(keepDiagnostics = false, keepMetadata = false),
nestedScrutinee.duplicate(),
List(patternBranch, fallbackBranch),
None
)

View File

@ -96,11 +96,7 @@ case object SectionsToBinOp extends IRPass {
val rightCallArg =
IR.CallArgument.Specified(None, rightArgName, None, None)
val rightDefArg = IR.DefinitionArgument.Specified(
rightArgName.duplicate(
keepLocations = false,
keepDiagnostics = false,
keepMetadata = false
),
rightArgName.duplicate(),
None,
suspended = false,
None
@ -111,11 +107,7 @@ case object SectionsToBinOp extends IRPass {
val leftCallArg =
IR.CallArgument.Specified(None, leftArgName, None, None)
val leftDefArg = IR.DefinitionArgument.Specified(
leftArgName.duplicate(
keepLocations = false,
keepDiagnostics = false,
keepMetadata = false
),
leftArgName.duplicate(),
None,
suspended = false,
None
@ -162,11 +154,7 @@ case object SectionsToBinOp extends IRPass {
val leftCallArg =
IR.CallArgument.Specified(None, leftArgName, None, None)
val leftDefArg = IR.DefinitionArgument.Specified(
leftArgName.duplicate(
keepLocations = false,
keepDiagnostics = false,
keepMetadata = false
),
leftArgName.duplicate(),
None,
suspended = false,
None
@ -176,11 +164,7 @@ case object SectionsToBinOp extends IRPass {
val rightCallArg =
IR.CallArgument.Specified(None, rightArgName, None, None)
val rightDefArg = IR.DefinitionArgument.Specified(
rightArgName.duplicate(
keepLocations = false,
keepDiagnostics = false,
keepMetadata = false
),
rightArgName.duplicate(),
None,
suspended = false,
None
@ -232,11 +216,7 @@ case object SectionsToBinOp extends IRPass {
IR.CallArgument.Specified(None, leftArgName, None, None)
val leftDefArg =
IR.DefinitionArgument.Specified(
leftArgName.duplicate(
keepLocations = false,
keepMetadata = false,
keepDiagnostics = false
),
leftArgName.duplicate(),
None,
suspended = false,
None
@ -248,11 +228,7 @@ case object SectionsToBinOp extends IRPass {
val rightCallArg =
IR.CallArgument.Specified(None, rightArgName, None, None)
val rightDefArg = IR.DefinitionArgument.Specified(
rightArgName.duplicate(
keepLocations = false,
keepMetadata = false,
keepDiagnostics = false
),
rightArgName.duplicate(),
None,
suspended = false,
None

View File

@ -197,22 +197,32 @@ case object ApplicationSaturation extends IRPass {
sealed case class Over(additionalArgCount: Int) extends CallSaturation {
override val metadataName: String =
"ApplicationSaturation.CallSaturation.Over"
override def duplicate: IRPass.Metadata = copy()
}
sealed case class Exact(helper: CodegenHelper) extends CallSaturation {
override val metadataName: String =
"ApplicationSaturation.CallSaturation.Exact"
override def duplicate: IRPass.Metadata = copy()
}
sealed case class ExactButByName() extends CallSaturation {
override val metadataName: String =
"ApplicationSaturation.CallSaturation.ExactButByName"
override def duplicate: IRPass.Metadata = ExactButByName()
}
sealed case class Partial(unappliedArgCount: Int) extends CallSaturation {
override val metadataName: String =
"ApplicationSaturation.CallSaturation.Partial"
override def duplicate: IRPass.Metadata = copy()
}
sealed case class Unknown() extends CallSaturation {
override val metadataName: String =
"ApplicationSaturation.CallSaturation.Unknown"
override def duplicate: IRPass.Metadata = Unknown()
}
}

View File

@ -142,5 +142,7 @@ case object DocumentationComments extends IRPass {
*/
sealed case class Doc(documentation: String) extends IRPass.Metadata {
override val metadataName: String = "DocumentationComments.Doc"
override def duplicate: IRPass.Metadata = copy(documentation.map(identity))
}
}

View File

@ -324,12 +324,16 @@ case object IgnoredBindings extends IRPass {
case object Ignored extends State {
override val metadataName: String = "IgnoredBindings.State.Ignored"
override val isIgnored: Boolean = true
override def duplicate: IRPass.Metadata = Ignored
}
/** States that the binding is not ignored. */
case object NotIgnored extends State {
override val metadataName: String = "IgnoredBindings.State.NotIgnored"
override val isIgnored: Boolean = false
override def duplicate: IRPass.Metadata = NotIgnored
}
}
}

View File

@ -205,5 +205,8 @@ case object TypeSignatures extends IRPass {
*/
case class Signature(signature: IR.Expression) extends IRPass.Metadata {
override val metadataName: String = "TypeSignatures.Signature"
override def duplicate: IRPass.Metadata =
this.copy(signature = signature.duplicate())
}
}

View File

@ -1,11 +1,11 @@
package org.enso.compiler.test.core
package org.enso.compiler.test.core.ir
import org.enso.compiler.core
import org.enso.compiler.core.IR
import org.enso.compiler.core.ir.DiagnosticStorage
import org.enso.compiler.test.CompilerTest
import org.enso.syntax.text.AST
class IRTest extends CompilerTest {
class DiagnosticStorageTest extends CompilerTest {
// === Test Configuration ===================================================
@ -22,14 +22,14 @@ class IRTest extends CompilerTest {
"The IR diagnostics storage" should {
"allow adding diagnostic results" in {
val diagnostics = new IR.DiagnosticStorage
val diagnostics = new DiagnosticStorage
diagnostics.add(mkDiagnostic("a"))
diagnostics.toList should contain(mkDiagnostic("a"))
}
"allow adding lists of diagnostic results" in {
val diagnostics = new IR.DiagnosticStorage
val diagnostics = new DiagnosticStorage
diagnostics.add(
List(
@ -44,7 +44,7 @@ class IRTest extends CompilerTest {
}
"mapping across the diagnostics to produce a new sequence" in {
val diagnostics = new IR.DiagnosticStorage(
val diagnostics = new DiagnosticStorage(
List(
mkDiagnostic("a"),
mkDiagnostic("b"),
@ -56,7 +56,7 @@ class IRTest extends CompilerTest {
}
"mapping across the diagnostics in place" in {
val diagnostics = new IR.DiagnosticStorage(
val diagnostics = new DiagnosticStorage(
List(
mkDiagnostic("a"),
mkDiagnostic("b"),
@ -83,7 +83,7 @@ class IRTest extends CompilerTest {
val err =
IR.Error.Syntax(AST.Blank(), IR.Error.Syntax.UnsupportedSyntax("aa"))
val diagnostics = new IR.DiagnosticStorage(
val diagnostics = new DiagnosticStorage(
List(
mkDiagnostic("a"),
mkDiagnostic("b"),
@ -98,7 +98,7 @@ class IRTest extends CompilerTest {
}
"filtering the diagnostics" in {
val diagnostics = new IR.DiagnosticStorage(
val diagnostics = new DiagnosticStorage(
List(
mkDiagnostic("aa"),
mkDiagnostic("ba"),
@ -106,7 +106,7 @@ class IRTest extends CompilerTest {
)
)
val result = new core.IR.DiagnosticStorage(
val result = new DiagnosticStorage(
List(mkDiagnostic("aa"), mkDiagnostic("ba"))
)
@ -118,7 +118,7 @@ class IRTest extends CompilerTest {
}
"filtering the diagnostics in place" in {
val diagnostics = new IR.DiagnosticStorage(
val diagnostics = new DiagnosticStorage(
List(
mkDiagnostic("aa"),
mkDiagnostic("ba"),
@ -138,7 +138,7 @@ class IRTest extends CompilerTest {
}
"folding over the diagnostics" in {
val diagnostics = new IR.DiagnosticStorage(
val diagnostics = new DiagnosticStorage(
List(
mkDiagnostic("a"),
mkDiagnostic("b"),

View File

@ -32,6 +32,8 @@ class MetadataStorageTest extends CompilerTest {
sealed case class Metadata1() extends IRPass.Metadata {
override val metadataName: String = "TestPass1.Metadata1"
override def duplicate: IRPass.Metadata = Metadata1()
}
}
@ -54,6 +56,8 @@ class MetadataStorageTest extends CompilerTest {
sealed case class Metadata2() extends IRPass.Metadata {
override val metadataName: String = "TestPass2.Metadata2"
override def duplicate: IRPass.Metadata = Metadata2()
}
}

View File

@ -47,7 +47,7 @@ class RuntimeServerTest
.allowExperimentalOptions(true)
.allowAllAccess(true)
.option(RuntimeOptions.PACKAGES_PATH, pkg.root.getAbsolutePath)
.option(RuntimeOptions.LOG_LEVEL, "FINE")
.option(RuntimeOptions.LOG_LEVEL, "WARNING")
.option(RuntimeServerInfo.ENABLE_OPTION, "true")
.out(out)
.serverTransport { (uri, peer) =>

View File

@ -339,7 +339,7 @@ object Shape extends ShapeImplicit {
with Phantom
final case class Documented[T](doc: Doc, emptyLinesBetween: Int, ast: T)
extends SpacelessAST[T]
final case class Import[T](path: List1[AST.Cons]) extends SpacelessAST[T]
final case class Import[T](path: AST) extends SpacelessAST[T]
final case class JavaImport[T](path: List1[AST.Ident]) extends SpacelessAST[T]
final case class Mixfix[T](name: List1[AST.Ident], args: List1[T])
extends SpacelessAST[T]
@ -351,6 +351,8 @@ object Shape extends ShapeImplicit {
extends SpacelessAST[T]
final case class Foreign[T](indent: Int, lang: String, code: List[String])
extends SpacelessAST[T]
final case class Modified[T](modifier: String, definition: T)
extends SpacelessAST[T]
//////////////////////////////////////////////////////////////////////////////
// Companion objects /////////////////////////////////////////////////////////
@ -954,7 +956,7 @@ object Shape extends ShapeImplicit {
implicit def ftor: Functor[Import] = semi.functor
implicit def fold: Foldable[Import] = semi.foldable
implicit def repr[T]: Repr[Import[T]] =
t => R + ("import " + t.path.map(_.repr.build()).toList.mkString("."))
t => R + "import" + t.path.repr.build()
// FIXME: How to make it automatic for non-spaced AST?
implicit def ozip[T]: OffsetZip[Import, T] = _.map(Index.Start -> _)
@ -1043,6 +1045,18 @@ object Shape extends ShapeImplicit {
implicit def ozip[T]: OffsetZip[Foreign, T] = _.map(Index.Start -> _)
implicit def span[T]: HasSpan[Foreign[T]] = _ => 0
}
object Modified {
implicit def ftor: Functor[Modified] = semi.functor
implicit def fold: Foldable[Modified] = semi.foldable
implicit def repr[T: Repr]: Repr[Modified[T]] = t => {
R + t.modifier + t.definition.repr.build()
}
// FIXME: How to make it automatic for non-spaced AST?
implicit def ozip[T]: OffsetZip[Modified, T] = _.map(Index.Start -> _)
implicit def span[T]: HasSpan[Modified[T]] = _ => 0
}
//// Implicits ////
object implicits {
@ -1117,6 +1131,7 @@ sealed trait ShapeImplicit {
case s: TypesetLiteral[T] => s.repr
case s: Def[T] => s.repr
case s: Foreign[T] => s.repr
case s: Modified[T] => s.repr
}
implicit def ozip[T: HasSpan]: OffsetZip[Shape, T] = {
case s: Unrecognized[T] => OffsetZip[Unrecognized, T].zipWithOffset(s)
@ -1156,6 +1171,7 @@ sealed trait ShapeImplicit {
case s: TypesetLiteral[T] => OffsetZip[TypesetLiteral, T].zipWithOffset(s)
case s: Def[T] => OffsetZip[Def, T].zipWithOffset(s)
case s: Foreign[T] => OffsetZip[Foreign, T].zipWithOffset(s)
case s: Modified[T] => OffsetZip[Modified, T].zipWithOffset(s)
}
implicit def span[T: HasSpan]: HasSpan[Shape[T]] = {
@ -1196,6 +1212,7 @@ sealed trait ShapeImplicit {
case s: TypesetLiteral[T] => s.span()
case s: Def[T] => s.span()
case s: Foreign[T] => s.span()
case s: Modified[T] => s.span()
}
}
@ -2297,11 +2314,9 @@ object AST {
type Import = ASTOf[Shape.Import]
object Import {
def apply(path: List1[Cons]): Import = Shape.Import[AST](path)
def apply(head: Cons): Import = Import(head, List())
def apply(head: Cons, tail: List[Cons]): Import = Import(List1(head, tail))
def apply(head: Cons, tail: Cons*): Import = Import(head, tail.toList)
def unapply(t: AST): Option[List1[Cons]] =
def apply(path: AST): Import =
Shape.Import[AST](path)
def unapply(t: AST): Option[AST] =
Unapply[Import].run(t => t.path)(t)
val any = UnapplyByType[Import]
}
@ -2399,6 +2414,25 @@ object AST {
val any = UnapplyByType[Foreign]
}
//////////////////////////////////////////////////////////////////////////////
//// Modified ////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
type Modified = ASTOf[Shape.Modified]
object Modified {
def apply(modifier: String, definition: AST): Modified = {
Shape.Modified(modifier, definition)
}
def unapply(t: AST): Option[(String, AST)] = {
Unapply[Modified].run(t => (t.modifier, t.definition))(t)
}
val any = UnapplyByType[Modified]
}
//////////////////////////////////////////////////////////////////////////////
//// Main ////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
def main(): Unit = {
val v1 = Ident.Var("foo")
// val v1_ = v1: AST

View File

@ -1,18 +1,17 @@
package org.enso.syntax.text.ast.meta
import org.enso.data.List1
import org.enso.data.Shifted
import org.enso.data.{List1, Shifted}
import org.enso.syntax.text.AST
import org.enso.syntax.text.AST.Macro.Definition
import org.enso.syntax.text.AST.Opr
import org.enso.syntax.text.AST.Var
import org.enso.syntax.text.AST.{Opr, Var}
import org.enso.syntax.text.ast.Repr
import scala.annotation.tailrec
import scala.annotation.{nowarn, tailrec}
/** It contains definitions of built-in macros, like if-then-else or (-). These
* macros might get moved to stdlib in the future.
*/
@nowarn("cat=unused")
object Builtin {
val registry: Registry = {
@ -119,34 +118,6 @@ object Builtin {
}
}
val imp = Definition(
Var("import") -> Pattern
.SepList(Pattern.Cons(), AST.Opr("."): AST, "expected module name")
) { ctx =>
ctx.body match {
case List(s1) =>
import Pattern.Match._
s1.body match {
case Seq(_, (headMatch, Many(_, tailMatch))) =>
def unwrapSeg(lseg: Pattern.Match): AST.Cons =
lseg.toStream match {
case List(Shifted(_, AST.Cons.any(t))) => t
case _ => internalError
}
val head = unwrapSeg(headMatch)
val tail = tailMatch.map {
case Seq(_, (Tok(_, Shifted(_, AST.Opr("."))), seg)) =>
unwrapSeg(seg)
case _ => internalError
}
AST.Import(head, tail)
case _ => internalError
}
case _ => internalError
}
}
val if_then = Definition(
Var("if") -> Pattern.Expr(allowBlocks = false),
Var("then") -> Pattern.Expr()
@ -201,6 +172,8 @@ object Builtin {
val nonSpacedExpr = Pattern.Any(Some(false)).many1.build
// NOTE: The macro engine currently resolves ahead of all operators, meaning
// that `->` doesn't obey the right precedence (e.g. with respect to `:`).
val arrow = Definition(
Some(nonSpacedExpr.or(Pattern.ExprUntilOpr("->"))),
Opr("->") -> Pattern.NonSpacedExpr().or(Pattern.Expr())
@ -259,7 +232,7 @@ object Builtin {
}
val freeze = Definition(
Var("freeze") -> Pattern.Expr()
Var("freeze") -> (Pattern.Var() :: Pattern.Block())
) { ctx =>
ctx.body match {
case List(s1) =>
@ -293,6 +266,50 @@ object Builtin {
}
}
val `import` = {
Definition(
Var("import") -> Pattern.Expr()
) { ctx =>
ctx.body match {
case List(s1) =>
s1.body.toStream match {
case List(expr) =>
AST.Import(expr.wrapped)
case _ => internalError
}
case _ => internalError
}
}
}
val privateDef = {
Definition(Var("private") -> Pattern.Expr()) { ctx =>
ctx.body match {
case List(s1) =>
s1.body.toStream match {
case List(expr) =>
AST.Modified("private", expr.wrapped)
case _ => internalError
}
case _ => internalError
}
}
}
val unsafeDef = {
Definition(Var("unsafe") -> Pattern.Expr()) { ctx =>
ctx.body match {
case List(s1) =>
s1.body.toStream match {
case List(expr) =>
AST.Modified("unsafe", expr.wrapped)
case _ => internalError
}
case _ => internalError
}
}
}
// TODO
// We may want to better represent empty AST. Moreover, there should be a
// way to generate multiple top-level entities from macros (like multiple
@ -304,6 +321,8 @@ object Builtin {
Definition(Opr("#") -> Pattern.Expr().tag("disable")) { _ => AST.Blank() }
Registry(
privateDef,
unsafeDef,
group,
sequenceLiteral,
typesetLiteral,
@ -311,7 +330,7 @@ object Builtin {
if_then,
if_then_else,
polyglotJavaImport,
imp,
`import`,
defn,
arrow,
foreign,

View File

@ -346,8 +346,6 @@ class ParserTest extends AnyFlatSpec with Matchers {
"(" ?= amb("(", List(List(")")))
"((" ?= amb_group(group_())
"import Std . Math .Vector".stripMargin ?= Import("Std", "Math", "Vector")
"""type Maybe a
| type Just val:a
| type Nothing""".stripMargin ?= {