From 91048efa3e6798700d9be4e2fb895f2a968496c9 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Mon, 6 Jun 2022 16:48:15 +0200 Subject: [PATCH 1/4] Minor compilation improvements Drop Core implementation (replacement for IR) as it looks increasingly unlikely this effort will be (sadly) continued. Also, it heavily relies on implicits which increases some compilation time. --- .../scala/org/enso/compiler/core/Core.scala | 1981 ----------------- 1 file changed, 1981 deletions(-) delete mode 100644 engine/runtime/src/main/scala/org/enso/compiler/core/Core.scala diff --git a/engine/runtime/src/main/scala/org/enso/compiler/core/Core.scala b/engine/runtime/src/main/scala/org/enso/compiler/core/Core.scala deleted file mode 100644 index cbce041095e4..000000000000 --- a/engine/runtime/src/main/scala/org/enso/compiler/core/Core.scala +++ /dev/null @@ -1,1981 +0,0 @@ -package org.enso.compiler.core - -import cats.data.NonEmptyList -import com.oracle.truffle.api.nodes.UnexpectedResultException -import org.enso.core.CoreGraph.DefinitionGen.Node.{ - LocationVal, - Shape => NodeShape -} -import org.enso.core.CoreGraph.{DefinitionGen => CoreDef} -import org.enso.graph.{Graph => PrimGraph} -import org.enso.syntax.text.{AST, Location => AstLocation} - -import scala.annotation.tailrec -import scala.collection.mutable - -// TODO [AA] Detailed semantic descriptions for each node shape in future. -// TODO [AA] Refactor over time to remove as much boilerplate as possible. -// TODO [AA] Eventually refactor graph macro generation so as to allow the -// trait-extension based approach to implicit imports. -// TODO [AA] Need to present a nice interface -// - Copy subsection of graph -// - Check equality for subsection of graph -// - These need to be _very_ careful about cycles - -/** [[Core]] is the sophisticated internal representation supported by the - * compiler. - * - * It is a structure designed to be amenable to program analysis and - * transformation and features: - * - High performance on a mutable graph structure. - * - Mutable links to represent program structure. - * - * To use core properly you will need to have the following imports in scope. - * These serve to bring the correct set of implicits into scope: - * - * {{{ - * import Core._ - * import CoreDef.Link.Shape._ - * import CoreDef.Node.Location._ - * import CoreDef.Node.ParentLinks._ - * import CoreDef.Node.Shape._ - * import org.enso.core.CoreGraph.{DefinitionGen => CoreDef} - * import org.enso.graph.{Graph => PrimGraph} - * import PrimGraph.Component.Refined._ - * }}} - * - * Please note that the smart constructor functions are _intentionally_ named - * using upper-case so as to signify that they construct a value. - */ -class Core { - - // ========================================================================== - // === Graph Storage ======================================================== - // ========================================================================== - - implicit val graph: Core.GraphData = PrimGraph[Core.Graph]() - - implicit val literalStorage: Core.LiteralStorage = CoreDef.LiteralStorage() - implicit val nameStorage: Core.NameStorage = CoreDef.NameStorage() - implicit val parentStorage: Core.ParentStorage = CoreDef.ParentStorage() - implicit val astStorage: Core.AstStorage = CoreDef.AstStorage() -} -object Core { - - import CoreDef.Link.Shape._ - import CoreDef.Node.Location._ - import CoreDef.Node.ParentLinks._ - import CoreDef.Node.Shape._ - import PrimGraph.Component.Refined._ - - // ========================================================================== - // === Useful Type Aliases ================================================== - // ========================================================================== - - // === Graph ================================================================ - - type Graph = CoreDef.CoreGraph - type GraphData = PrimGraph.GraphData[Graph] - - // === Components =========================================================== - - type Node = CoreDef.Node[Graph] - type Nodes = CoreDef.Nodes - type Link = CoreDef.Link[Graph] - type Links = CoreDef.Links - type RefinedNode[V <: CoreDef.Node.Shape] = - PrimGraph.Component.Refined[NodeShape, V, Node] - - // === Errors =============================================================== - - type ErrorOrRefined[Err <: CoreDef.Node.Shape, T <: CoreDef.Node.Shape] = - Either[RefinedNode[Err], RefinedNode[T]] - type ConsErrOr[T <: CoreDef.Node.Shape] = - ErrorOrRefined[NodeShape.ConstructionError, T] - - // === Opaque Storage ======================================================= - - type LiteralStorage = CoreDef.LiteralStorage - type NameStorage = CoreDef.NameStorage - type ParentStorage = CoreDef.ParentStorage - type AstStorage = CoreDef.AstStorage - - // === Location ============================================================= - - type Location = LocationVal[Graph] - - // ========================================================================== - // === Node ================================================================= - // ========================================================================== - - /** Functionality for working with nodes. */ - object Node { - - /** Smart constructors to create nodes of various shapes. */ - //noinspection DuplicatedCode - object New { - - // === Meta Shapes ====================================================== - - /** Creates a node that has no particular shape. - * - * @return an empty node - */ - def Empty()(implicit core: Core): RefinedNode[NodeShape.Empty] = { - val node = CoreDef.Node.addRefined[NodeShape.Empty] - - node.location = Constants.invalidLocation - node.parents = Vector() - - node - } - - /** Creates a representation of a cons cell for building linked lists on - * the core graph. - * - * These should be used _very_ sparingly, if at all, but they provide a - * way to store dynamically-sized core components providing they can be - * broken down into statically sized components. - * - * The [[tail]] parameter should always point to either another node - * with shape [[MetaList]] or a node with shape [[MetaNil]]. - * - * It should be noted that, given that each [[Node]] contains a field - * of [[ParentLinks]], that constructing this properly provides a - * doubly-linked list, as no [[MetaList]] or [[MetaNil]] should have - * more than one parent. - * - * The location contained in this node is _invalid_ as it does not - * represent any location in the program source. - * - * @param head the current, arbitrary, element in the list - * @param tail the rest of the list - * @param core an implicit instance of core - * @return a node representing an on-graph meta list - */ - def MetaList( - head: Node, - tail: Node - )(implicit core: Core): ConsErrOr[NodeShape.MetaList] = { - if (Utility.ListOps.is(tail)) { - val node = CoreDef.Node.addRefined[NodeShape.MetaList] - - val headLink = Link.New.Connected(node, head) - val tailLink = Link.New.Connected(node, tail) - - node.head = headLink - node.tail = tailLink - node.location = Constants.invalidLocation - node.parents = Vector() - - Right(node) - } else { - val errorElems = Utility.ListOps.from(tail) - val errorNode = ConstructionError(errorElems, tail.location) - - Left(errorNode) - } - } - - /** Creates a representation of the end of a linked-list on the core - * graph. - * - * This should _only_ be used in conjunction with [[NodeShape.MetaList]]. - * - * The location contained in this node is _invalid_ as it does not - * represent any location in the program source. - * - * @param core an implicit instance of core - * @return a node representing the end of an on-graph meta list - */ - def MetaNil()(implicit core: Core): RefinedNode[NodeShape.MetaNil] = { - val node = CoreDef.Node.addRefined[NodeShape.MetaNil] - - node.location = Constants.invalidLocation - node.parents = Vector() - - node - } - - /** Creates a representation of a meta-value `true` in the core graph. - * - * The location contained in this node is _invalid_ as it does not - * represent any location in the program source. - * - * @param core an implicit instance of core - * @return a node representing the on-graph metavalue `true` - */ - def MetaTrue()(implicit core: Core): RefinedNode[NodeShape.MetaTrue] = { - val node = CoreDef.Node.addRefined[NodeShape.MetaTrue] - - node.location = Constants.invalidLocation - node.parents = Vector() - - node - } - - /** Creates a representation of the meta-value `false` in the core graph. - * - * The location contained in this node is _invalid_ as it does not - * represent any location in the program source. - * - * @param core an implicit instance of core - * @return a node representing the on-graph metavalue `false` - */ - def MetaFalse()(implicit core: Core): RefinedNode[NodeShape.MetaFalse] = { - val node = CoreDef.Node.addRefined[NodeShape.MetaFalse] - - node.location = Constants.invalidLocation - node.parents = Vector() - - node - } - - // === Literals ========================================================= - - /** Creates a node containing a numeric literal. - * - * @param number the literal number - * @param location the source location for the literal - * @param core an implicit instance of core - * @return a numeric literal node representing [[number]] - */ - def NumericLiteral( - number: String, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.NumericLiteral] = { - val node = CoreDef.Node.addRefined[NodeShape.NumericLiteral] - - node.number = number - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node containing a textual literal. - * - * @param text the literal text - * @param location the source location for the literal - * @param core an implicit instance of core - * @return a textual literal node representing [[text]] - */ - def TextLiteral( - text: String, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TextLiteral] = { - val node = CoreDef.Node.addRefined[NodeShape.TextLiteral] - - node.text = text - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node containing a foreign code literal. - * - * @param code the foreign code - * @param location the source location for the literal - * @param core an implicit instance of core - * @return a foreign code literal node representing [[code]] - */ - def ForeignCodeLiteral( - code: String, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.ForeignCodeLiteral] = { - val node = CoreDef.Node.addRefined[NodeShape.ForeignCodeLiteral] - - node.code = code - node.location = location - node.parents = Vector() - - node - } - - // === Names ============================================================ - - /** Creates a node representing a name. - * - * @param nameLiteral the literal representation of the name - * @param location the source location for the name - * @param core an implicit instance of core - * @return a node representing the name [[nameLiteral]] - */ - def Name( - nameLiteral: String, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.Name] = { - val node = CoreDef.Node.addRefined[NodeShape.Name] - - node.nameLiteral = nameLiteral - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a usage of `this`. - * - * @param location the source location of the `this` usage - * @param core an implicit instance of core - * @return a node representing the `this` usage at [[location]] - */ - def ThisName( - location: Location - )(implicit core: Core): RefinedNode[NodeShape.ThisName] = { - val node = CoreDef.Node.addRefined[NodeShape.ThisName] - - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a usage of `here`. - * - * @param location the source location of the `here` usage - * @param core an implicit instance of core - * @return a node representing the `here` usage at [[location]] - */ - def HereName( - location: Location - )(implicit core: Core): RefinedNode[NodeShape.HereName] = { - val node = CoreDef.Node.addRefined[NodeShape.HereName] - - node.location = location - node.parents = Vector() - - node - } - - // === Module =========================================================== - - /** Creates a node representing a module definition. - * - * @param name the name of the module - * @param imports the list of imports for the module, as a valid meta - * list - * @param definitions the list of definitions in the module, as a valid - * meta list - * @param location the source location of the module definition - * @param core an implicit instance of core - * @return a node representing the module definition - */ - def ModuleDef( - name: Node, - imports: Node, - definitions: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.ModuleDef] = { - if (!Utility.ListOps.is(imports)) { - val errorElems = Utility.ListOps.from(imports) - val error = ConstructionError(errorElems, imports.location) - - Left(error) - } else if (!Utility.ListOps.is(definitions)) { - val errorElems = Utility.ListOps.from(definitions) - val error = ConstructionError(errorElems, definitions.location) - - Left(error) - } else { - val node = CoreDef.Node.addRefined[NodeShape.ModuleDef] - - val nameLink = Link.New.Connected(node, name) - val importsLink = Link.New.Connected(node, imports) - val definitionsLink = Link.New.Connected(node, definitions) - - node.name = nameLink - node.imports = importsLink - node.definitions = definitionsLink - node.location = location - node.parents = Vector() - - Right(node) - } - } - - /** Creates a node representing an import statement. - * - * @param segments the segments of the import path, as a valid meta list - * @param location the source location of the import statement - * @param core an implicit instance of core - * @return a node representing the import statement - */ - def Import( - segments: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.Import] = { - if (Utility.ListOps.is(segments)) { - val node = CoreDef.Node.addRefined[NodeShape.Import] - - val segmentsLink = Link.New.Connected(node, segments) - - node.segments = segmentsLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(segments) - val errNode = ConstructionError(errList, segments.location) - - Left(errNode) - } - } - - /** Creates a node representing a top-level binding. - * - * This node does not represent the binding itself, but only serves to - * represent the connection between the binding and its containing - * module. - * - * @param module the module in which [[Binding]] is defined - * @param binding the binding itself - * @param location the source location of the binding - * @param core an implicit instance of core - * @return a node representing the top-level binding - */ - def TopLevelBinding( - module: Node, - binding: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.TopLevelBinding] = { - binding match { - case NodeShape.Binding.any(_) => - val node = CoreDef.Node.addRefined[NodeShape.TopLevelBinding] - - val moduleLink = Link.New.Connected(node, module) - val bindingLink = Link.New.Connected(node, binding) - - node.module = moduleLink - node.binding = bindingLink - node.location = location - node.parents = Vector() - - Right(node) - case _ => - val errNode = ConstructionError(binding, binding.location) - - Left(errNode) - } - } - - // === Type Definitions ================================================= - - /** Creates a node representing an atom definition. - * - * @param name the atom's name - * @param args the atom's arguments - * @param location the source location of the atom - * @param core an implicit instance of core - * @return a node representing an atom definition for [[Name]] - */ - def AtomDef( - name: Node, - args: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.AtomDef] = { - if (Utility.ListOps.is(args)) { - val node = CoreDef.Node.addRefined[NodeShape.AtomDef] - - val nameLink = Link.New.Connected(node, name) - val argsLink = Link.New.Connected(node, args) - - node.name = nameLink - node.args = argsLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(args) - val errNode = ConstructionError(errList, args.location) - - Left(errNode) - } - } - - /** Creates a node representing a complex type definition. - * - * @param name the name of the type definition - * @param typeParams the type parameters - * @param body the body of the definition - * @param location the source location of the definition - * @param core an implicit instance of core - * @return a node representing the type definition for [[Name]] - */ - def TypeDef( - name: Node, - typeParams: Node, - body: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.TypeDef] = { - if (!Utility.ListOps.is(typeParams)) { - val errList = Utility.ListOps.from(typeParams) - val errNode = ConstructionError(errList, typeParams.location) - - Left(errNode) - } else if (!Utility.ListOps.is(body)) { - val errList = Utility.ListOps.from(body) - val errNode = ConstructionError(errList, body.location) - - Left(errNode) - } else { - val node = CoreDef.Node.addRefined[NodeShape.TypeDef] - - val nameLink = Link.New.Connected(node, name) - val typeParamsLink = Link.New.Connected(node, typeParams) - val bodyLink = Link.New.Connected(node, body) - - node.name = nameLink - node.typeParams = typeParamsLink - node.body = bodyLink - node.location = location - node.parents = Vector() - - Right(node) - } - } - - // === Typing =========================================================== - - /** Creates a node representing the ascription of a type to a value. - * - * The signature is an entirely arbitrary Enso expression, as required by - * the language's syntactic unification. - * - * @param typed the expression being ascribed a type - * @param sig the type being ascribed to [[typed]] - * @param location the source location of the ascription - * @param core an implicit instance of core - * @return a node representing the ascription of the type represented by - * [[sig]] to [[typed]] - */ - def TypeAscription( - typed: Node, - sig: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypeAscription] = { - val node = CoreDef.Node.addRefined[NodeShape.TypeAscription] - - val typedLink = Link.New.Connected(node, typed) - val sigLink = Link.New.Connected(node, sig) - - node.typed = typedLink - node.sig = sigLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the ascription of a monadic context to a - * value (using the `in` keyword). - * - * @param typed the expression being ascribed a context - * @param context the context being ascribed to [[typed]] - * @param location the source location of the ascription - * @param core an implicit instance of core - * @return a node representing the ascription of the context [[context]] - * to the expression [[typed]] - */ - def ContextAscription( - typed: Node, - context: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.ContextAscription] = { - val node = CoreDef.Node.addRefined[NodeShape.ContextAscription] - - val typedLink = Link.New.Connected(node, typed) - val contextLink = Link.New.Connected(node, context) - - node.typed = typedLink - node.context = contextLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a typeset member. - * - * At most two of [[label]], [[memberType]] and [[value]] may be - * [[NodeShape.Empty]]. - * - * @param label the label of the member, if provided - * @param memberType the type of the member, if provided - * @param value the value of the member, if provided - * @param location the source location of the member definition - * @param core an implicit instance of core - * @return a node representing a typeset member called [[label]] with - * type [[memberType]] and default value [[value]] - */ - def TypesetMember( - label: Node, - memberType: Node, - value: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetMember] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetMember] - - val labelLink = Link.New.Connected(node, label) - val memberTypeLink = Link.New.Connected(node, memberType) - val valueLink = Link.New.Connected(node, value) - - node.label = labelLink - node.memberType = memberTypeLink - node.value = valueLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the typeset subsumption operator `<:`. - * - * This construct does not represent a user-facing language element at - * this time. - * - * @param left the left operand - * @param right the right operand - * @param location the location in the source to which the operator - * corresponds - * @param core an implicit instance of core - * @return a node representing the judgement that [[left]] `<:` [[right]] - */ - def TypesetSubsumption( - left: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetSubsumption] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetSubsumption] - - val leftLink = Link.New.Connected(node, left) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the typeset equality operator `~`. - * - * This construct does not represent a user-facing language element at - * this time. - * - * @param left the left operand - * @param right the right operand - * @param location the location in the source to which the operator - * corresponds - * @param core an implicit instance of core - * @return a node representing the judgement that [[left]] `~` [[right]] - */ - def TypesetEquality( - left: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetEquality] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetEquality] - - val leftLink = Link.New.Connected(node, left) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the typeset concatenation operator `,`. - * - * @param left the left operand - * @param right the right operand - * @param location the location in the source to which the operator - * corresponds - * @param core an implicit instance of core - * @return a node representing the judgement of [[left]] `,` [[right]] - */ - def TypesetConcat( - left: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetConcat] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetConcat] - - val leftLink = Link.New.Connected(node, left) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the typeset union operator `|`. - * - * @param left the left operand - * @param right the right operand - * @param location the location in the source to which the operator - * corresponds - * @param core an implicit instance of core - * @return a node representing the judgement of [[left]] `|` [[right]] - */ - def TypesetUnion( - left: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetUnion] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetUnion] - - val leftLink = Link.New.Connected(node, left) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the typeset intersection operator `&`. - * - * @param left the left operand - * @param right the right operand - * @param location the location in the source to which the operator - * corresponds - * @param core an implicit instance of core - * @return a node representing the judgement of [[left]] `&` [[right]] - */ - def TypesetIntersection( - left: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetIntersection] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetIntersection] - - val leftLink = Link.New.Connected(node, left) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing the typeset subtraction operator `\`. - * - * @param left the left operand - * @param right the right operand - * @param location the location in the source to which the operator - * corresponds - * @param core an implicit instance of core - * @return a node representing the judgement of [[left]] `\` [[right]] - */ - def TypesetSubtraction( - left: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypesetSubtraction] = { - val node = CoreDef.Node.addRefined[NodeShape.TypesetSubtraction] - - val leftLink = Link.New.Connected(node, left) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - // === Function ========================================================= - - /** Creates a node representing a lambda expression, the `->` function - * arrow. - * - * Please note that all lambdas in Enso are explicitly single-argument. - * - * @param arg the argument to the lambda - * @param body the body of the lambda - * @param location the location of this node in the program source - * @param core an implicit instance of core - * @return a lambda node with [[arg]] and [[body]] as its children - */ - def Lambda( - arg: Node, - body: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.Lambda] = { - val node = CoreDef.Node.addRefined[NodeShape.Lambda] - - val argLink = Link.New.Connected(node, arg) - val bodyLink = Link.New.Connected(node, body) - - node.arg = argLink - node.body = bodyLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a function definition. - * - * @param name the name of the function being defined - * @param args the arguments to the function being defined - * @param body the body of the function being defined - * @param location the source location of the function definition - * @param core an implicit instance of core - * @return a node representing a function defined for [[Name]] - */ - def FunctionDef( - name: Node, - args: Node, - body: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.FunctionDef] = { - if (Utility.ListOps.is(args)) { - val node = CoreDef.Node.addRefined[NodeShape.FunctionDef] - - val nameLink = Link.New.Connected(node, name) - val argsLink = Link.New.Connected(node, args) - val bodyLink = Link.New.Connected(node, body) - - node.name = nameLink - node.args = argsLink - node.body = bodyLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(args) - val errNode = ConstructionError(errList, args.location) - - Left(errNode) - } - } - - /** Creates a node representing a method definition - * - * @param targetPath the method path for the definition - * @param name the method name - * @param function the implementation of the method. This must either be - * a [[NodeShape.Lambda]] or a [[NodeShape.FunctionDef]] - * @param location the source location of the method definition - * @param core an implicit instance of core - * @return a node that defines method [[Name]] on [[path]] - */ - def MethodDef( - targetPath: Node, - name: Node, - function: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.MethodDef] = { - val bodyIsValid = function match { - case NodeShape.FunctionDef.any(_) => true - case NodeShape.Lambda.any(_) => true - case _ => false - } - - if (bodyIsValid) { - val node = CoreDef.Node.addRefined[NodeShape.MethodDef] - - val targetPathLink = Link.New.Connected(node, targetPath) - val nameLink = Link.New.Connected(node, name) - val functionLink = Link.New.Connected(node, function) - - node.targetPath = targetPathLink - node.name = nameLink - node.function = functionLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(function) - val errNode = ConstructionError(errList, function.location) - - Left(errNode) - } - } - - // === Definition-Site Argument Types =================================== - - /** Creates a node representing an ignored argument. - * - * An ignored argument is one that is not used in the body and is - * explicitly ignored so as not to introduce warnings. - * - * @param location the location of the ignored argument usage - * @param core an implicit instance of core - * @return a node representing an ignored argument - */ - def IgnoredArgument( - location: Location - )(implicit core: Core): RefinedNode[NodeShape.IgnoredArgument] = { - val node = CoreDef.Node.addRefined[NodeShape.IgnoredArgument] - - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing an argument from a function definition - * site. - * - * @param name the name of the argument - * @param suspended whether or not the argument is suspended, as either - * [[NodeShape.MetaTrue]] or [[NodeShape.MetaFalse]] - * @param default the default value for the argument, if present - * @param location the source location of the argument - * @param core an implicit instance of core - * @return a node representing a definition site argument called [[Name]] - */ - def DefinitionArgument( - name: Node, - suspended: Node, - default: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.DefinitionArgument] = { - if (Utility.BoolOps.is(suspended)) { - val node = CoreDef.Node.addRefined[NodeShape.DefinitionArgument] - - val nameLink = Link.New.Connected(node, name) - val suspendedLink = Link.New.Connected(node, suspended) - val defaultLink = Link.New.Connected(node, default) - - node.name = nameLink - node.suspended = suspendedLink - node.default = defaultLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(suspended) - val errNode = ConstructionError(errList, suspended.location) - - Left(errNode) - } - } - - // === Applications ===================================================== - - /** Creates a node representing a function application. - * - * Please note that _all_ functions in Enso are curried by default. and - * applications to multiple arguments are represented in [[Core]] as - * single-argument functions. - * - * @param function the function being applied - * @param argument the argument to [[function]] - * @param location the soure location for the application - * @param core an implicit instance of core - * @return a node that applies [[function]] to [[argument]] - */ - def Application( - function: Node, - argument: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.Application] = { - val node = CoreDef.Node.addRefined[NodeShape.Application] - - val functionLink = Link.New.Connected(node, function) - val argumentLink = Link.New.Connected(node, argument) - - node.function = functionLink - node.argument = argumentLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing an infix application. - * - * @param left the left argument to the operator - * @param operator the operator being applied - * @param right the right argument to the operator - * @param location the source location of the infox application - * @param core an implicit instance of core - * @return a node representing the application of [[operator]] to - * [[left]] and [[right]] - */ - def InfixApplication( - left: Node, - operator: Node, - right: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.InfixApplication] = { - val node = CoreDef.Node.addRefined[NodeShape.InfixApplication] - - val leftLink = Link.New.Connected(node, left) - val operatorLink = Link.New.Connected(node, operator) - val rightLink = Link.New.Connected(node, right) - - node.left = leftLink - node.operator = operatorLink - node.right = rightLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a left operator section. - * - * @param arg the left argument to [[operator]] - * @param operator the function being applied - * @param location the source location of the application - * @param core an implicit instance of core - * @return a node representing the partial application of [[operator]] to - * [[arg]] - */ - def LeftSection( - arg: Node, - operator: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.LeftSection] = { - val node = CoreDef.Node.addRefined[NodeShape.LeftSection] - - val argLink = Link.New.Connected(node, arg) - val operatorLink = Link.New.Connected(node, operator) - - node.arg = argLink - node.operator = operatorLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a right operator section. - * - * @param operator the function being applied - * @param arg the right argument to [[operator]] - * @param location the source location of the application - * @param core an implicit instance of core - * @return a node representing the partial application of [[operator]] to - * [[arg]] - */ - def RightSection( - operator: Node, - arg: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.RightSection] = { - val node = CoreDef.Node.addRefined[NodeShape.RightSection] - - val operatorLink = Link.New.Connected(node, operator) - val argLink = Link.New.Connected(node, arg) - - node.operator = operatorLink - node.arg = argLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a centre operator section. - * - * @param operator the function being partially applied - * @param location the source location of the application - * @param core an implicit instance of core - * @return a node representing the partial application of [[operator]] - */ - def CentreSection( - operator: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.CentreSection] = { - val node = CoreDef.Node.addRefined[NodeShape.CentreSection] - - val operatorLink = Link.New.Connected(node, operator) - - node.operator = operatorLink - node.location = location - node.parents = Vector() - - node - } - - /** A node representing a term being explicitly forced. - * - * An explicitly forced term is one where the user has explicitly called - * the `force` operator on it. This is useful only while the compiler - * does not _automatically_ handle suspensions and forcing. - * - * PLEASE NOTE: This is temporary and will be removed as soon as the - * compiler is capable enough to not require it. - * - * @param expression the expression being forced - * @param location the source location of the forced expression - * @param core an implicit instance of core - * @return a node representing [[expression]] being explicitly forced - */ - def ForcedTerm( - expression: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.ForcedTerm] = { - val node = CoreDef.Node.addRefined[NodeShape.ForcedTerm] - - val expressionLink = Link.New.Connected(node, expression) - - node.expression = expressionLink - node.location = location - node.parents = Vector() - - node - } - - // === Call-Site Argument Types ========================================= - - /** Creates a node representing a lambda shorthand argument. - * - * A lambda shorthand argument is the name for the usage of `_` at a - * function call-site, where it is syntax sugar for a lambda parameter to - * that function. - * - * @param location the location of this argument in the source code - * @param core an implicit instance of core - * @return a node representing the `_` argument found at [[location]] - */ - def LambdaShorthandArgument( - location: Location - )(implicit core: Core): RefinedNode[NodeShape.LambdaShorthandArgument] = { - val node = CoreDef.Node.addRefined[NodeShape.LambdaShorthandArgument] - - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing an argument from a function call site. - * - * The expression must always be present, but the argument [[Name]] may - * be an instance of [[NodeShape.Empty]]. - * - * @param expression the expression being passes as the argument - * @param name the name of the argument, if present - * @param location the source location of this argument - * @param core an implicit instance of core - * @return a node representing the use of [[expression]] as an argument - * to a function - */ - def CallSiteArgument( - expression: Node, - name: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.CallSiteArgument] = { - val node = CoreDef.Node.addRefined[NodeShape.CallSiteArgument] - - val expressionLink = Link.New.Connected(node, expression) - val nameLink = Link.New.Connected(node, name) - - node.expression = expressionLink - node.name = nameLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a usage of the function defaults - * suspension operator `...`. - * - * @param location the source location of the operator usage - * @param core an implicit instance of core - * @return a node representing a usage of the `...` operator - */ - def SuspendDefaultsOperator( - location: Location - )(implicit core: Core): RefinedNode[NodeShape.SuspendDefaultsOperator] = { - val node = CoreDef.Node.addRefined[NodeShape.SuspendDefaultsOperator] - - node.location = location - node.parents = Vector() - - node - } - - // === Structure ======================================================== - - /** Creates a node representing a block expression. - * - * @param expressions a valid meta list of expressions (should be - * [[NodeShape.MetaNil]] if none are present - * @param returnVal the final expression in the block - * @param location the source location of the block - * @param core an implicit instance of core - * @return a representation of a block containing [[expressions]] and - * [[returnVal]] - */ - def Block( - expressions: Node, - returnVal: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.Block] = { - if (Utility.ListOps.is(expressions)) { - val node = CoreDef.Node.addRefined[NodeShape.Block] - - val expressionsLink = Link.New.Connected(node, expressions) - val returnValLink = Link.New.Connected(node, returnVal) - - node.expressions = expressionsLink - node.returnVal = returnValLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(expressions) - val errNode = ConstructionError(errList, expressions.location) - - Left(errNode) - } - } - - /** Creates a node representing a binding of the form `name = expression`. - * - * @param name the name being bound to - * @param expression the expression being bound to [[Name]] - * @param location the source location of the binding - * @param core an implicit instance of core - * @return a representation of the binding of the result of - * [[expression]] to [[Name]] - */ - def Binding( - name: Node, - expression: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.Binding] = { - val node = CoreDef.Node.addRefined[NodeShape.Binding] - - val nameLink = Link.New.Connected(node, name) - val expressionLink = Link.New.Connected(node, expression) - - node.name = nameLink - node.expression = expressionLink - node.location = location - node.parents = Vector() - - node - } - - // === Case Expression ================================================== - - /** Creates a node representing a case expression. - * - * @param scrutinee the expression being matched on - * @param branches the branches doing the matching - * @param location the soure location of the case expression - * @param core an implicit instance of core - * @return a node representing pattern matching on [[scrutinee]] using - * [[branches]] - */ - def CaseExpr( - scrutinee: Node, - branches: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.CaseExpr] = { - if (Utility.ListOps.is(branches)) { - val node = CoreDef.Node.addRefined[NodeShape.CaseExpr] - - val scrutineeLink = Link.New.Connected(node, scrutinee) - val branchesLink = Link.New.Connected(node, branches) - - node.scrutinee = scrutineeLink - node.branches = branchesLink - node.location = location - node.parents = Vector() - - Right(node) - } else { - val errList = Utility.ListOps.from(branches) - val errNode = ConstructionError(errList, branches.location) - - Left(errNode) - } - } - - /** Creates a node representing a branch in a case expression. - * - * @param pattern the pattern match for the branch - * @param expression the expression that is executed if [[pattern]] - * successfully matches the case scrutinee - * @param location the source location of the case branch - * @param core an implicit instance of core - * @return a node representing a case branch matching [[pattern]] - */ - def CaseBranch( - pattern: Node, - expression: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.CaseBranch] = { - val node = CoreDef.Node.addRefined[NodeShape.CaseBranch] - - val patternLink = Link.New.Connected(node, pattern) - val expressionLink = Link.New.Connected(node, expression) - - node.pattern = patternLink - node.expression = expressionLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a structural pattern. - * - * A structural pattern is one that examines the _structure_ of the - * scrutinee. However, as Enso is a dependently typed language, an - * examination of the structure is also an examination of the type. - * - * @param matchExpression the expression representing the pattern - * @param location the source location of the patttern - * @param core an implicit instance of core - * @return a node representing the structural match defined by - * [[matchExpression]] - */ - def StructuralPattern( - matchExpression: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.StructuralPattern] = { - val node = CoreDef.Node.addRefined[NodeShape.StructuralPattern] - - val matchExpressionLink = Link.New.Connected(node, matchExpression) - - CoreDef.Node.addParent(matchExpression, matchExpressionLink) - - node.matchExpression = matchExpressionLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a type-based pattern. - * - * A type-based pattern is one that purely examines the type of the - * scrutinee, without including any structural elements. - * - * @param matchExpression the expression representing the pattern - * @param location the source location of the pattern - * @param core an implicit instance of core - * @return a node representing the type-based match defined by - * [[matchExpression]] - */ - def TypePattern( - matchExpression: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.TypePattern] = { - val node = CoreDef.Node.addRefined[NodeShape.TypePattern] - - val matchExpressionLink = Link.New.Connected(node, matchExpression) - - node.matchExpression = matchExpressionLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a named pattern. - * - * A named pattern is one that renames the scrutinee in the pattern - * branch. - * - * @param matchExpression the expression representing the pattern - * @param location the soure location of the pattern - * @param core an implicit instance of core - * @return a node representing the type-based match defined by - * [[matchExpression]] - */ - def NamedPattern( - matchExpression: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.NamedPattern] = { - val node = CoreDef.Node.addRefined[NodeShape.NamedPattern] - - val matchExpressionLink = Link.New.Connected(node, matchExpression) - - node.matchExpression = matchExpressionLink - node.location = location - node.parents = Vector() - - node - } - - /** Creates a node representing a fallback pattern. - * - * A fallback pattern is also known as a catch-all, pattern, and will - * unconditionally match any scrutinee. - * - * @param location the soure location of the pattern - * @param core an implicit instance of core - * @return a node representing the fallback pattern at [[location]] - */ - def FallbackPattern( - location: Location - )(implicit core: Core): RefinedNode[NodeShape.FallbackPattern] = { - val node = CoreDef.Node.addRefined[NodeShape.FallbackPattern] - - node.location = location - node.parents = Vector() - - node - } - - // === Comments ========================================================= - - /** Creates a node representing an entity with an associated doc comment. - * - * @param commented the entity that has the comment - * @param doc the documentation associated with [[commented]] - * @param location the source location of [[commented]] and its - * associated doc - * @param core an implicit instance of core - * @return a node representing the association of [[doc]] to - * [[commented]] - */ - def DocComment( - commented: Node, - doc: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.DocComment] = { - val node = CoreDef.Node.addRefined[NodeShape.DocComment] - - val commentedLink = Link.New.Connected(node, commented) - val docLink = Link.New.Connected(node, doc) - - node.commented = commentedLink - node.doc = docLink - node.location = location - node.parents = Vector() - - node - } - - // === Foreign ========================================================== - - /** Creates a node representing a block of foreign code. - * - * @param language the programming language for which [[code]] is written - * @param code the source code in [[language]] (must be a - * [[NodeShape.ForeignCodeLiteral]]) - * @param location the source location of the foreign code block - * @param core an implicit instance of core - * @return a node representing [[code]] in [[language]] - */ - def ForeignDefinition( - language: Node, - code: Node, - location: Location - )(implicit core: Core): ConsErrOr[NodeShape.ForeignDefinition] = { - code match { - case NodeShape.ForeignCodeLiteral.any(_) => - val node = CoreDef.Node.addRefined[NodeShape.ForeignDefinition] - - val languageLink = Link.New.Connected(node, language) - val codeLink = Link.New.Connected(node, code) - - node.language = languageLink - node.code = codeLink - node.location = location - node.parents = Vector() - - Right(node) - case _ => - val errList = Utility.ListOps.from(code) - val errNode = ConstructionError(errList, code.location) - - Left(errNode) - } - } - - // === Errors =========================================================== - - /** Creates a node representing a syntax error. - * - * @param errorAst the AST that is syntactically invalid - * @param core an implicit instance of core - * @return a node representing the syntax error described by [[errorAst]] - */ - def SyntaxError( - errorAst: AST - )(implicit core: Core): RefinedNode[NodeShape.SyntaxError] = { - val node = CoreDef.Node.addRefined[NodeShape.SyntaxError] - val errLocation: Location = - errorAst.location - .map(Conversions.astLocationToNodeLocation) - .getOrElse(Constants.invalidLocation) - - node.errorAst = errorAst - node.location = errLocation - node.parents = Vector() - - node - } - - /** Creates a node representing an error that occurred when constructing - * a [[Core]] expression. - * - * @param erroneousCore the core expression(s) that caused a problem (may - * be passed as a meta list) - * @param location the location at which the erroneous core occurred - * @param core an implicit instance of core - * @return a node representing an erroneous core expression - */ - def ConstructionError( - erroneousCore: Node, - location: Location - )(implicit core: Core): RefinedNode[NodeShape.ConstructionError] = { - val erroneousCoreList: Node = - if (Utility.ListOps.is(erroneousCore)) { - erroneousCore - } else { - Utility.ListOps.from(erroneousCore) - } - - val node = CoreDef.Node.addRefined[NodeShape.ConstructionError] - - val erroneousCoreLink = - Link.New.Connected(node, erroneousCoreList) - - node.erroneousCore = erroneousCoreLink - node.location = location - node.parents = Vector() - - node - } - } - - /** Useful conversions between types that are used for Core nodes. */ - object Conversions { - - /** Converts the parser's location representation into Core's location - * representation. - * - * @param location a location from the parser - * @return the core representation of [[location]] - */ - implicit def astLocationToNodeLocation( - location: AstLocation - ): Location = LocationVal(location.start, location.end) - } - - /** Constants for working with nodes. */ - object Constants { - - /** An invalid location in the program source. */ - val invalidSourceIndex: Int = -1 - val invalidLocation: Location = - LocationVal(invalidSourceIndex, invalidSourceIndex) - } - - /** Utility functions for working with nodes. */ - object Utility { - - object ListOps { - - /** Checks if two lists on the core graph are equal. - * - * Equality for lists is defined as the lists containing the same nodes - * as members. The nodes making up the lists themselves need not be - * equal. - * - * @param left the first list - * @param right the second list - * @param core an implicit instance of core - * @return `true` if [[left]] is equal to [[right]], `false` otherwise - */ - def equals( - left: RefinedNode[MetaList], - right: RefinedNode[MetaList] - )(implicit core: Core): Boolean = { - val visitedNodesInLeft = mutable.ArrayBuffer[Int]() - val visitedNodesInRight = mutable.ArrayBuffer[Int]() - - @tailrec - def go( - left: Node, - right: Node - ): Boolean = { - val leftIsVisited = visitedNodesInLeft.contains(left.ix) - val rightIsVisited = visitedNodesInRight.contains(right.ix) - - if (leftIsVisited && rightIsVisited) { - true - } else if (!leftIsVisited && !rightIsVisited) { - visitedNodesInLeft.append(left.ix) - visitedNodesInRight.append(right.ix) - - left match { - case NodeShape.MetaNil.any(_) => - right match { - case NodeShape.MetaNil.any(_) => true - case _ => false - } - case NodeShape.MetaList.any(left1) => - right match { - case NodeShape.MetaList.any(right1) => - (left1.head.target == right1.head.target) && go( - left1.tail.target, - right1.tail.target - ) - case _ => false - } - case _ => false - } - } else { - false - } - } - - go(left, right) - } - - /** Checks if the provided node is a meta-level list node. - * - * A node is considered to be a list node when it has either the shape - * [[NodeShape.MetaList]] or the shape [[NodeShape.MetaNil]]. - * - * @param node the node to check - * @param core an implicit instance of core - * @return `true` if [[node]] is a list node, otherwise `false` - */ - def is(node: Node)(implicit core: Core): Boolean = { - node match { - case NodeShape.MetaNil.any(_) => true - case NodeShape.MetaList.any(_) => true - case _ => false - } - } - - /** Finds the end of a list. - * - * @param node the list node to find the end of - * @param core an implicit instance of core - * @return [[Some]] when the [[node]] has an end, otherwise [[None]] if - * [[node]] is cyclic or not a list - */ - def end(node: Node)(implicit core: Core): Option[Node] = { - val visitedNodes = mutable.ArrayBuffer[Int]() - - @tailrec - def go(node: Node): Option[Node] = { - if (visitedNodes contains node.ix) { - None - } else { - node match { - case NodeShape.MetaNil.any(_) => Some(node) - case NodeShape.MetaList.any(list) => go(list.tail.target) - case _ => None - } - } - } - - go(node) - } - - /** Determines the length of a list. - * - * @param node the node representing a list - * @param core an implicit instance of core - * @return [[Some]] when [[node]] is a list that is not cyclical, - * [[None]] when [[node]] is not a list or is cylical - */ - def length(node: Node)(implicit core: Core): Option[Int] = { - val visitedNodes = mutable.ArrayBuffer[Int]() - var accumulator = 0 - - @tailrec - @throws[UnexpectedResultException] - def go(node: Node): Int = { - if (visitedNodes.contains(node.ix)) { - throw new UnexpectedResultException(-1) - } else { - visitedNodes.append(node.ix) - - node match { - case NodeShape.MetaNil.any(_) => accumulator - case NodeShape.MetaList.any(list) => - accumulator += 1 - go(list.tail.target) - case _ => throw new UnexpectedResultException(-1) - } - } - } - - try { - Some(go(node)) - } catch { - case _: UnexpectedResultException => None - } - } - - /** Gets the node at a particular index in the list. - * - * @param node the node representing a list - * @param index the index of the item you want to access - * @param core an implicit instance of core - * @return [[Some]] if the item exists, [[None]] if the index is out of - * bounds, [[node]] is not a list, or if [[index]] is past the - * loop point in a cyclical list - */ - def at(node: Node, index: Int)(implicit core: Core): Option[Node] = { - val visitedNodes = mutable.ArrayBuffer[Int]() - - @tailrec - def go(node: Node, currentIndex: Int): Option[Node] = { - if (visitedNodes.contains(node.ix)) { - None - } else { - visitedNodes.append(node.ix) - - node match { - case NodeShape.MetaNil.any(_) => None - case NodeShape.MetaList.any(list) => - if (currentIndex == index) { - Some(list.head.target) - } else { - go(list.tail.target, currentIndex + 1) - } - case _ => None - } - } - } - - go(node, 0) - } - - /** Constructs a meta list on the [[Core]] graph from a single core - * expression. - * - * @param node the expression to turn into a valid list - * @param core an implicit instance of core - * @return a node representing the head of a meta-level list - */ - def from( - node: Node - )(implicit core: Core): RefinedNode[NodeShape.MetaList] = { - from(NonEmptyList(node, List())) - } - - /** Constructs a meta list on the [[Core]] graph from a list of [[Core]] - * nodes. - * - * @param nodes the nodes to make a list out of - * @param core an implicit instance of core - * @return a node representing the head of a meta-level list - */ - def from( - nodes: NonEmptyList[Node] - )(implicit core: Core): RefinedNode[NodeShape.MetaList] = { - val nodesWithNil = nodes :+ New.MetaNil().wrapped - - // Note [Unsafety in List Construction] - val unrefinedMetaList = - nodesWithNil.toList.reduceRight((l, r) => - New - .MetaList(l, r) - .getOrElse(throw new RuntimeException("Should never happen.")) - .wrapped - ) - - PrimGraph.Component.Refined - .wrap[NodeShape, NodeShape.MetaList, Node](unrefinedMetaList) - } - - /* Note [Unsafety in List Construction] - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This makes use of internal implementation details to know that calling - * `right` here is always safe. The error condition for the `metaList` - * constructor occurs when the `tail` argument doesn't point to a valid - * list element, but here we construct that element directly and hence we - * know that it is valid. - * - * Furthermore, we can unconditionally refine the type as we know that the - * node we get back must be a MetaList, and we know that the input is not - * empty. - * - * It also bears noting that for this to be safe we _must_ use a right - * reduce, rather than a left reduce, otherwise the elements will not be - * constructed properly. This does, however, mean that this can stack - * overflow when provided with too many elements. - */ - - /** Generates a meta list on the core graph of length [[length]], with - * each cell filled with an empty node. - * - * @param length the length of the list to generate - * @param core an implicit instance of core - * @return a list of length [[length]] if `length > 0`, otherwise an - * empty list. - */ - def ofLength(length: Int)(implicit core: Core): Node = { - val nil = Node.New.MetaNil() - - @tailrec - def go(tail: Node, remainingLength: Int): Node = { - if (remainingLength == 0) { - tail - } else { - val cons = Node.New - .MetaList(Node.New.Empty(), tail) - .getOrElse(throw new RuntimeException("Should never happen")) - - go(cons, remainingLength - 1) - } - } - - if (length <= 0) { - nil - } else { - go(nil, length) - } - } - } - - object BoolOps { - - /** Checks if the provided node is a meta-level boolean node. - * - * @param node the node to check - * @param core an implicit instance of core - * @return `true` if [[node]] is a meta boolean, `false` otherwise - */ - def is(node: Node)(implicit core: Core): Boolean = { - node match { - case NodeShape.MetaTrue.any(_) => true - case NodeShape.MetaFalse.any(_) => true - case _ => false - } - } - } - } - } - - // ========================================================================== - // === Link ================================================================= - // ========================================================================== - - /** Functionality for working with links. */ - object Link { - object New { - - /** Makes a link with the provided source and target. - * - * @param source the start of the link - * @param target the end of the link - * @param core an implicit instance of core - * @return a link from [[source]] to [[target]] - */ - def Connected(source: Node, target: Node)(implicit core: Core): Link = { - val link = core.graph.addLink() - - link.source = source - link.target = target - - CoreDef.Node.addParent(target, link) - - link - } - - /** Makes a link with only a source. - * - * The target is defaulted to a new empty node. - * - * @param source the start of the link - * @param core an implicit instance of core - * @return a link from [[source]] to a new [[NodeShape.Empty]] node - */ - def Disconnected(source: Node)(implicit core: Core): Link = { - val link = core.graph.addLink() - val emptyNode = Node.New.Empty() - - link.source = source - link.target = emptyNode - - CoreDef.Node.addParent(emptyNode, link) - - link - } - } - } - // ========================================================================== - // === Implicits ============================================================ - // ========================================================================== - - /* Note [Implicit Conversions On Implicits] - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * While the enforced usage of the compiler plugin 'splain' does much to make - * debugging issues with implicit resolution easier, implicit conversions of - * implicit values can sometimes fail to resolve. If you have all of the - * imports described in the `Core` doc comment, as well as an implicit value - * of type `Core` and are seeing errors related to implicits resolution, you - * may be running into issues with implicits resolution. - * - * A quick fix is to make the values that the following implicits would - * generate _explicitly_ available as implicits in the usage scope. - */ - - /** Implicitly converts an implicit instance of core to the underlying graph - * data. - * - * @param core the core instance to convert - * @return the graph data stored in [[core]] - */ - implicit def getGraphData(implicit core: Core): GraphData = core.graph - - /** Implicitly converts an implicit instance of core to the associated storage - * for literals. - * - * @param core the core instance to convert - * @return the literal storage stored in [[core]] - */ - implicit def getLiteralStorage(implicit core: Core): LiteralStorage = - core.literalStorage - - /** Implicitly converts an implicit instance of core to the associated storage - * for names. - * - * @param core the core instance to convert - * @return the name storage stored in [[core]] - */ - implicit def getNameStorage(implicit core: Core): NameStorage = - core.nameStorage - - /** Implicitly converts an implicit instance of core to the associated storage - * for parent links. - * - * @param core the core instance to convert - * @return the parent link storage stored in [[core]] - */ - implicit def getParentStorage(implicit core: Core): ParentStorage = - core.parentStorage - - /** Implicitly converts an implicit instance of core to the associated storage - * for ast data. - * - * @param core the core instance to convert - * @return the ast storage stored in [[core]] - */ - implicit def getAstStorage(implicit core: Core): AstStorage = - core.astStorage - -} From 796cc44f74ec4bd6d60cd81aaadfc9dd3e6460e4 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 7 Jun 2022 09:35:18 +0200 Subject: [PATCH 2/4] Remove (now) invalid tests --- .../compiler/test/core/CorePrimTest.scala | 953 ----------- .../enso/compiler/test/core/CoreTest.scala | 249 --- .../test/core/SmartConstructorsTest.scala | 1480 ----------------- 3 files changed, 2682 deletions(-) delete mode 100644 engine/runtime/src/test/scala/org/enso/compiler/test/core/CorePrimTest.scala delete mode 100644 engine/runtime/src/test/scala/org/enso/compiler/test/core/CoreTest.scala delete mode 100644 engine/runtime/src/test/scala/org/enso/compiler/test/core/SmartConstructorsTest.scala diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/core/CorePrimTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/core/CorePrimTest.scala deleted file mode 100644 index 17c6494864ec..000000000000 --- a/engine/runtime/src/test/scala/org/enso/compiler/test/core/CorePrimTest.scala +++ /dev/null @@ -1,953 +0,0 @@ -package org.enso.compiler.test.core - -import org.enso.core.CoreGraph.DefinitionGen.Node.LocationVal -import org.enso.graph.{Graph => PrimGraph} -import org.enso.syntax.text.AST -import org.scalatest.BeforeAndAfterEach -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers - -import scala.annotation.nowarn - -/** This file tests the primitive, low-level operations on core. - * - * It does _not_ utilise the high-level API, and instead works directly with - * the defined graph primitives. - * - * PLEASE NOTE: Many of these tests will be removed once the smart constructors - * exist. - */ -@nowarn("cat=deprecation") -class CorePrimTest extends AnyFlatSpec with Matchers with BeforeAndAfterEach { - - // === Test Setup =========================================================== - import org.enso.core.CoreGraph.DefinitionGen.Link.Shape._ - import org.enso.core.CoreGraph.DefinitionGen.Node.Location._ - import org.enso.core.CoreGraph.DefinitionGen.Node.ParentLinks._ - import org.enso.core.CoreGraph.DefinitionGen.Node.Shape._ - import org.enso.core.CoreGraph.DefinitionGen._ - - // Reassignable mutable fixture elements - implicit var graph: PrimGraph.GraphData[CoreGraph] = _ - implicit var literalStorage: LiteralStorage = _ - implicit var parentStorage: ParentStorage = _ - implicit var nameStorage: NameStorage = _ - implicit var astStorage: AstStorage = _ - - override def beforeEach(): Unit = { - graph = PrimGraph[CoreGraph]() - literalStorage = LiteralStorage() - parentStorage = ParentStorage() - nameStorage = NameStorage() - astStorage = AstStorage() - } - - // === Tests for Links ====================================================== - - val link = "A link" - - link should "only be equal to itself" in { - val l1: Link[CoreGraph] = graph.addLink() - val l2: Link[CoreGraph] = graph.addLink() - - l1 shouldEqual l1 - l1 should not equal l2 - } - - link should "have a source and a target" in { - val l1: Link[CoreGraph] = graph.addLink() - val srcNode: Node[CoreGraph] = graph.addNode() - val destNode: Node[CoreGraph] = graph.addNode() - - l1.source = srcNode - l1.target = destNode - - val expectedShape = Link.ShapeVal(srcNode, destNode) - - l1.shape shouldEqual expectedShape - } - - // === Tests for Nodes ====================================================== - - val node = "A node" - val nodeShape = "A node's shape" - - node should "only be equal to itself" in { - val n1 = graph.addNode() - val n2 = graph.addNode() - - n1 shouldEqual n1 - n1 should not equal n2 - } - - node should "contain source location information" in { - val n1 = graph.addNode() - - n1.sourceStart = 302 - n1.sourceEnd = 364 - - val expectedLocation = Node.LocationVal(302, 364) - - n1.location shouldEqual expectedLocation - } - - node should "be able to have multiple parent edges" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - l1.target = n1 - l2.target = n1 - l3.target = n1 - - val parentIndices: Vector[Int] = Vector(l1.ix, l2.ix, l3.ix) - n1.parents = parentIndices - - n1.parents shouldEqual parentIndices - n1.parents.length shouldEqual 3 - } - - node should "be able to take on multiple shapes" in { - val n1 = graph.addNode() - - Node.setShape[Empty](n1) - - n1 match { - case Empty.any(_) => - Node.setShape[AtomDef](n1) - - n1 match { - case AtomDef.any(_) => succeed - case _ => fail - } - case _ => fail - } - } - - node should "be able to be constructed without clobbering its fields" in { - val emptyLink = graph.addLink() - val nilLink = graph.addLink() - val consNode = Node.addRefined[MetaList] - - consNode.head = emptyLink - consNode.tail = nilLink - consNode.location = LocationVal[CoreGraph](20, 30) - consNode.parents = Vector() - - // Intentional re-assignment in reverse order to check for clobbering - consNode.tail = nilLink - consNode.head = emptyLink - - consNode.head shouldEqual emptyLink - consNode.tail shouldEqual nilLink - consNode.sourceStart shouldEqual 20 - consNode.sourceEnd shouldEqual 30 - consNode.parents shouldEqual Vector() - - consNode.wrapped match { - case MetaList.any(_) => succeed - case _ => fail - } - } - - // === Tests for Node Shapes ================================================ - - nodeShape should "be able to be empty" in { - val n1 = graph.addNode() - - Node.setShape[Empty](n1) - - val isEmpty = n1 match { - case Empty.any(_) => true - case _ => false - } - - isEmpty shouldEqual true - } - - nodeShape should "be able to represent a list cons cell" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[MetaList](n1) - - n1 match { - case MetaList.any(n1) => - n1.head = l1 - n1.tail = l2 - - n1.metaList shouldEqual MetaListVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent boolean true" in { - val n1 = graph.addNode() - - Node.setShape[MetaNil](n1) - - n1 match { - case MetaNil.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent a nil cell" in { - val n1 = graph.addNode() - - Node.setShape[MetaTrue](n1) - - n1 match { - case MetaTrue.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent boolean false" in { - val n1 = graph.addNode() - - Node.setShape[MetaFalse](n1) - - n1 match { - case MetaFalse.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent a numeric literal" in { - val n1 = graph.addNode() - - Node.setShape[NumericLiteral](n1) - - n1 match { - case NumericLiteral.any(n1) => - val testText = "1e-1" - n1.number = testText - - n1.numericLiteral shouldEqual NumericLiteralVal(testText) - case _ => fail - } - } - - nodeShape should "be able to represent a text literal" in { - val n1 = graph.addNode() - - Node.setShape[TextLiteral](n1) - - n1 match { - case TextLiteral.any(n1) => - val testText = "Lorem ipsum" - n1.text = testText - - n1.textLiteral shouldEqual TextLiteralVal(testText) - case _ => fail - } - } - - nodeShape should "be able to represent a foreign code literal" in { - val n1 = graph.addNode() - - Node.setShape[ForeignCodeLiteral](n1) - - n1 match { - case ForeignCodeLiteral.any(n1) => - val testText = "lambda x: x + 1" - n1.code = testText - - n1.foreignCodeLiteral shouldEqual ForeignCodeLiteralVal(testText) - case _ => fail - } - } - - nodeShape should "be able to represent a name" in { - val n1 = graph.addNode() - - Node.setShape[Name](n1) - - n1 match { - case Name.any(n1) => - val testName = "Name" - n1.nameLiteral = testName - - n1.name shouldEqual NameVal(testName) - case _ => fail - } - } - - nodeShape should "be able to represent `this`" in { - val n1 = graph.addNode() - - Node.setShape[ThisName](n1) - - n1 match { - case ThisName.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent `here`" in { - val n1 = graph.addNode() - - Node.setShape[HereName](n1) - - n1 match { - case HereName.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent a module" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[ModuleDef](n1) - - n1 match { - case ModuleDef.any(n1) => - n1.name = l1 - n1.imports = l2 - n1.definitions = l3 - - n1.moduleDef shouldEqual ModuleDefVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent an import" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[Import](n1) - - n1 match { - case Import.any(n1) => - n1.segments = l1 - - n1.`import` shouldEqual ImportVal(l1) - case _ => fail - } - } - - nodeShape should "be able to represent a lop-level binding" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TopLevelBinding](n1) - - n1 match { - case TopLevelBinding.any(n1) => - n1.module = l1 - n1.binding = l2 - - n1.topLevelBinding shouldEqual TopLevelBindingVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent an atom definition" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[AtomDef](n1) - - n1 match { - case AtomDef.any(n1) => - n1.name = l1 - n1.args = l2 - - n1.atomDef shouldEqual AtomDefVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent a complex type definition" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[TypeDef](n1) - - n1 match { - case TypeDef.any(n1) => - n1.name = l1 - n1.typeParams = l2 - n1.body = l3 - - n1.typeDef shouldEqual TypeDefVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent a type signature" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypeAscription](n1) - - n1 match { - case TypeAscription.any(n1) => - n1.typed = l1 - n1.sig = l2 - - n1.typeAscription shouldEqual TypeAscriptionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent monadic context ascription" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[ContextAscription](n1) - - n1 match { - case ContextAscription.any(n1) => - n1.typed = l1 - n1.context = l2 - - n1.contextAscription shouldEqual ContextAscriptionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent a typeset member" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[TypesetMember](n1) - - n1 match { - case TypesetMember.any(n1) => - n1.label = l1 - n1.memberType = l2 - n1.value = l3 - - n1.typesetMember shouldEqual TypesetMemberVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent the subsumption judgement" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypesetSubsumption](n1) - - n1 match { - case TypesetSubsumption.any(n1) => - n1.left = l1 - n1.right = l2 - - n1.typesetSubsumption shouldEqual TypesetSubsumptionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent the eqquality judgement" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypesetEquality](n1) - - n1 match { - case TypesetEquality.any(n1) => - n1.left = l1 - n1.right = l2 - - n1.typesetEquality shouldEqual TypesetEqualityVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent the concatenation operator" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypesetConcat](n1) - - n1 match { - case TypesetConcat.any(n1) => - n1.left = l1 - n1.right = l2 - - n1.typesetConcat shouldEqual TypesetConcatVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent the union operator" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypesetUnion](n1) - - n1 match { - case TypesetUnion.any(n1) => - n1.left = l1 - n1.right = l2 - - n1.typesetUnion shouldEqual TypesetUnionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent the intersection operator" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypesetIntersection](n1) - - n1 match { - case TypesetIntersection.any(n1) => - n1.left = l1 - n1.right = l2 - - n1.typesetIntersection shouldEqual TypesetIntersectionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent the subtraction operator" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[TypesetSubtraction](n1) - - n1 match { - case TypesetSubtraction.any(n1) => - n1.left = l1 - n1.right = l2 - - n1.typesetSubtraction shouldEqual TypesetSubtractionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent a lambda" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[Lambda](n1) - - n1 match { - case Lambda.any(n1) => - n1.arg = l1 - n1.body = l2 - - n1.lambda shouldEqual LambdaVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent a function definition" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[FunctionDef](n1) - - n1 match { - case FunctionDef.any(n1) => - n1.name = l1 - n1.args = l2 - n1.body = l3 - - n1.functionDef shouldEqual FunctionDefVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent a method definition" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[MethodDef](n1) - - n1 match { - case MethodDef.any(n1) => - n1.targetPath = l1 - n1.name = l2 - n1.function = l3 - - n1.methodDef shouldEqual MethodDefVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent an ignored argument" in { - val n1 = graph.addNode() - - Node.setShape[IgnoredArgument](n1) - - n1 match { - case IgnoredArgument.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent a definition-site argument" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[DefinitionArgument](n1) - - n1 match { - case DefinitionArgument.any(n1) => - n1.name = l1 - n1.suspended = l2 - n1.default = l3 - - n1.definitionArgument shouldEqual DefinitionArgumentVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent prefix function application" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[Application](n1) - - n1 match { - case Application.any(n1) => - n1.function = l1 - n1.argument = l2 - - n1.application shouldEqual ApplicationVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent infix function application" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - val l3 = graph.addLink() - - Node.setShape[InfixApplication](n1) - - n1 match { - case InfixApplication.any(n1) => - n1.left = l1 - n1.operator = l2 - n1.right = l3 - - n1.infixApplication shouldEqual InfixApplicationVal(l1, l2, l3) - case _ => fail - } - } - - nodeShape should "be able to represent left sections" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[LeftSection](n1) - - n1 match { - case LeftSection.any(n1) => - n1.arg = l1 - n1.operator = l2 - - n1.leftSection shouldEqual LeftSectionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent right sections" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[RightSection](n1) - - n1 match { - case RightSection.any(n1) => - n1.operator = l1 - n1.arg = l2 - - n1.rightSection shouldEqual RightSectionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent centre sections" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[CentreSection](n1) - - n1 match { - case CentreSection.any(n1) => - n1.operator = l1 - - n1.centreSection shouldEqual CentreSectionVal(l1) - case _ => fail - } - } - - nodeShape should "be able to represent forced terms" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[ForcedTerm](n1) - - n1 match { - case ForcedTerm.any(n1) => - n1.expression = l1 - - n1.forcedTerm shouldEqual ForcedTermVal(l1) - case _ => fail - } - } - - nodeShape should "be able to represent _ arguments" in { - val n1 = graph.addNode() - - Node.setShape[LambdaShorthandArgument](n1) - - n1 match { - case LambdaShorthandArgument.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent call site arguments" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[CallSiteArgument](n1) - - n1 match { - case CallSiteArgument.any(n1) => - n1.expression = l1 - n1.name = l2 - - n1.callSiteArgument shouldEqual CallSiteArgumentVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent the defaults suspension operator" in { - val n1 = graph.addNode() - - Node.setShape[SuspendDefaultsOperator](n1) - - n1 match { - case SuspendDefaultsOperator.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent block expressions" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[Block](n1) - - n1 match { - case Block.any(n1) => - n1.expressions = l1 - n1.returnVal = l2 - - n1.block shouldEqual BlockVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent bindings" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[Binding](n1) - - n1 match { - case Binding.any(n1) => - n1.name = l1 - n1.expression = l2 - - n1.binding shouldEqual BindingVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent case expressions" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[CaseExpr](n1) - - n1 match { - case CaseExpr.any(n1) => - n1.scrutinee = l1 - n1.branches = l2 - - n1.caseExpr shouldEqual CaseExprVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent case branches" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[CaseBranch](n1) - - n1 match { - case CaseBranch.any(n1) => - n1.pattern = l1 - n1.expression = l2 - - n1.caseBranch shouldEqual CaseBranchVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent structural patterns" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[StructuralPattern](n1) - - n1 match { - case StructuralPattern.any(n1) => - n1.matchExpression = l1 - - n1.structuralPattern shouldEqual StructuralPatternVal(l1) - case _ => fail - } - } - - nodeShape should "be able to represent type-based patterns" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[TypePattern](n1) - - n1 match { - case TypePattern.any(n1) => - n1.matchExpression = l1 - - n1.typePattern shouldEqual TypePatternVal(l1) - case _ => fail - } - } - - nodeShape should "be able to represent named type-based patterns" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[NamedPattern](n1) - - n1 match { - case NamedPattern.any(n1) => - n1.matchExpression = l1 - - n1.namedPattern shouldEqual NamedPatternVal(l1) - case _ => fail - } - } - - nodeShape should "be able to represent fallback patterns" in { - val n1 = graph.addNode() - - Node.setShape[FallbackPattern](n1) - - n1 match { - case FallbackPattern.any(_) => succeed - case _ => fail - } - } - - nodeShape should "be able to represent doc comments" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[DocComment](n1) - - n1 match { - case DocComment.any(n1) => - n1.commented = l1 - n1.doc = l2 - - n1.docComment shouldEqual DocCommentVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent foreign code segments" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - val l2 = graph.addLink() - - Node.setShape[ForeignDefinition](n1) - - n1 match { - case ForeignDefinition.any(n1) => - n1.language = l1 - n1.code = l2 - - n1.foreignDefinition shouldEqual ForeignDefinitionVal(l1, l2) - case _ => fail - } - } - - nodeShape should "be able to represent syntax errors" in { - val n1 = graph.addNode() - val ast = AST.Blank() - - Node.setShape[SyntaxError](n1) - - n1 match { - case SyntaxError.any(n1) => - n1.errorAst = ast - - n1.syntaxError shouldEqual SyntaxErrorVal(ast) - case _ => fail - } - } - - nodeShape should "be able to represent construction errors" in { - val n1 = graph.addNode() - val l1 = graph.addLink() - - Node.setShape[ConstructionError](n1) - - n1 match { - case ConstructionError.any(n1) => - n1.erroneousCore = l1 - - n1.constructionError shouldEqual ConstructionErrorVal(l1) - } - } -} diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/core/CoreTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/core/CoreTest.scala deleted file mode 100644 index 1e758b4d5bfa..000000000000 --- a/engine/runtime/src/test/scala/org/enso/compiler/test/core/CoreTest.scala +++ /dev/null @@ -1,249 +0,0 @@ -package org.enso.compiler.test.core - -import cats.data.NonEmptyList -import org.enso.compiler.core.Core -import org.enso.compiler.core.Core.Node.Utility -import org.enso.compiler.test.CompilerTest -import org.enso.core.CoreGraph.DefinitionGen.Node.{Shape => NodeShape} -import org.enso.core.CoreGraph.{DefinitionGen => CoreDef} -import org.enso.graph.{Graph => PrimGraph} - -class CoreTest extends CompilerTest { - - // === Test Setup =========================================================== - - import Core._ - import CoreDef.Link.Shape._ - import CoreDef.Node.ParentLinks._ - import CoreDef.Node.Shape._ - import PrimGraph.Component.Refined._ - import PrimGraph.VariantCast - - // === Useful Constants ===================================================== - - val constantLocationStart = 201 - val constantLocationEnd = 1337 - val dummyLocation: Core.Location = - CoreDef.Node.LocationVal(constantLocationStart, constantLocationEnd) - - // === More Complex Graph Shape Tests ======================================= - - // TODO [AA] Once deletion and replacement functions exist, expand these tests - // to check that the shapes behave properly under usage of such functions. - - "Diamonds constructed on the graph" should { - implicit val core: Core = new Core() - - val fnName = Node.New.Name("foo", dummyLocation) - val binding1Name = Node.New.Name("a", dummyLocation) - val binding1 = Node.New.Binding(binding1Name, fnName, dummyLocation) - val binding2Name = Node.New.Name("b", dummyLocation) - val binding2 = Node.New.Binding(binding2Name, fnName, dummyLocation) - val bindingsList = Utility.ListOps.from(binding1) - - val block = - Node.New.Block(bindingsList, binding2, dummyLocation).getOrElse(fail()) - - "have multiple parents for the node at the bottom of the diamond" in { - fnName.parents.size shouldEqual 2 - fnName.parents should contain(binding1.expression.ix) - fnName.parents should contain(binding2.expression.ix) - } - - "ensure that traversals through both paths reach the same place" in { - val fnNameViaLeftPath = block.expressions.target - .unsafeAs[NodeShape.MetaList] - .head - .target - .unsafeAs[NodeShape.Binding] - .expression - .target - - val fnNameViaRightPath = - block.returnVal.target.unsafeAs[NodeShape.Binding].expression.target - - fnNameViaLeftPath shouldEqual fnNameViaRightPath - } - } - - "Multi-level trees constructed on the graph" should { - implicit val core: Core = new Core() - - /* Builds the following tree for purposes of the test - * - * 1 - * | \ - * 2 3 - * | \ - * 4 5 - * | \ - * 6 7 - */ - - val node7 = Node.New.Empty() - val node6 = Node.New.Empty() - val node5 = Node.New.LeftSection(node6, node7, dummyLocation) - val node4 = Node.New.Empty() - val node3 = Node.New.Empty() - val node2 = Node.New.LeftSection(node4, node5, dummyLocation) - val node1 = Node.New.LeftSection(node2, node3, dummyLocation) - - "allow walking to all the leaf nodes" in { - node1.arg.target - .unsafeAs[NodeShape.LeftSection] - .arg - .target shouldEqual node4 - - node1.operator.target shouldEqual node3 - - node1.arg.target - .unsafeAs[NodeShape.LeftSection] - .operator - .target - .unsafeAs[NodeShape.LeftSection] - .arg - .target shouldEqual node6 - - node1.arg.target - .unsafeAs[NodeShape.LeftSection] - .operator - .target - .unsafeAs[NodeShape.LeftSection] - .operator - .target shouldEqual node7 - } - - "allow walking from leaf to parent via parent links" in { - val node5handle = - core.graph.componentRefFromIndex[Links](node7.parents.head).source - val node2handle = - core.graph - .componentRefFromIndex[Links](node5handle.parents.head) - .source - val node1handle = - core.graph - .componentRefFromIndex[Links](node2handle.parents.head) - .source - - node1handle shouldEqual node1 - } - } - - "Cycles on the graph" should { - implicit val core: Core = new Core() - - val empty = Node.New.Empty() - - val tempNil = Node.New.MetaNil() - val cons4 = Node.New.MetaList(empty, tempNil).getOrElse(fail()) - val cons3 = Node.New.MetaList(empty, cons4).getOrElse(fail()) - val cons2 = Node.New.MetaList(empty, cons3).getOrElse(fail()) - val cons1 = Node.New.MetaList(empty, cons2).getOrElse(fail()) - - // Link the nodes in a loop - val loopLink = Link.New.Connected(cons4, cons1) - cons4.tail = loopLink - - "allow correct traversal" in { - cons1.tail.target - .unsafeAs[NodeShape.MetaList] // cons2 - .tail - .target - .unsafeAs[NodeShape.MetaList] // cons3 - .tail - .target - .unsafeAs[NodeShape.MetaList] // cons4 - .tail - .target shouldEqual cons1 - } - - "allow reverse traversal" in { - val cons4ref = - core.graph.componentRefFromIndex[Links](cons1.parents.head).target - val cons3ref = - core.graph.componentRefFromIndex[Links](cons4ref.parents.head).target - val cons2ref = - core.graph.componentRefFromIndex[Links](cons3ref.parents.head).target - val cons1ref = - core.graph.componentRefFromIndex[Links](cons2ref.parents.head).target - - cons1ref shouldEqual cons1 - } - } - - "Linked lists on the graph" should { - implicit val core: Core = new Core() - - val myBindingName = Node.New.Name("a", dummyLocation) - val myFnName = Node.New.Name("function", dummyLocation) - val myBinding = Node.New.Binding(myBindingName, myFnName, dummyLocation) - - val list = Utility.ListOps.from( - NonEmptyList( - myBinding.wrapped, - List( - myBindingName.wrapped, - myFnName.wrapped - ) - ) - ) - - "should allow finding of their end" in { - list.tail.target - .unsafeAs[NodeShape.MetaList] // cons2 - .tail - .target - .unsafeAs[NodeShape.MetaList] // cons3 - .tail - .target shouldEqual Utility.ListOps.end(list).get - } - - "be able to contain complex structures" in { - val bindingRef = - Utility.ListOps - .at(list, 0) - .getOrElse(fail()) - .unsafeAs[NodeShape.Binding] - - bindingRef shouldEqual myBinding - - bindingRef.name shouldEqual myBindingName - bindingRef.expression shouldEqual myFnName - } - - "allow forward traversal" in { - list.tail.target - .unsafeAs[NodeShape.MetaList] - .head - .target shouldEqual myBindingName - } - - "allow reverse traversal via parent links" in { - val listEnd = Utility.ListOps.end(list).get - listEnd.is[NodeShape.MetaNil] shouldEqual true - - val cons3ref = - core.graph - .componentRefFromIndex[Links](listEnd.parents.head) - .source - .as[NodeShape.MetaList] - .getOrElse(fail()) - cons3ref.head.target.is[NodeShape.Name] shouldEqual true - cons3ref.head.target shouldEqual myFnName - - val cons2ref = core.graph - .componentRefFromIndex[Links](cons3ref.parents.head) - .source - .unsafeAs[NodeShape.MetaList] - cons2ref.head.target.is[NodeShape.Name] shouldEqual true - cons2ref.head.target shouldEqual myBindingName - - val cons1ref = core.graph - .componentRefFromIndex[Links](cons2ref.parents.head) - .source - .unsafeAs[NodeShape.MetaList] - cons1ref.head.target.is[NodeShape.Binding] shouldEqual true - cons1ref.head.target shouldEqual myBinding - } - } -} diff --git a/engine/runtime/src/test/scala/org/enso/compiler/test/core/SmartConstructorsTest.scala b/engine/runtime/src/test/scala/org/enso/compiler/test/core/SmartConstructorsTest.scala deleted file mode 100644 index 7ad7de400545..000000000000 --- a/engine/runtime/src/test/scala/org/enso/compiler/test/core/SmartConstructorsTest.scala +++ /dev/null @@ -1,1480 +0,0 @@ -package org.enso.compiler.test.core - -import cats.data.NonEmptyList -import org.enso.compiler.core.Core -import org.enso.compiler.core.Core.Node.Utility.BoolOps -import org.enso.compiler.core.Core.Node.{Constants, Utility} -import org.enso.compiler.test.CompilerTest -import org.enso.core.CoreGraph.DefinitionGen.Node.{Shape => NodeShape} -import org.enso.core.CoreGraph.{DefinitionGen => CoreDef} -import org.enso.graph.{Graph => PrimGraph} -import org.enso.syntax.text.{AST, Location => AstLocation} -import org.scalatest.Assertion - -class SmartConstructorsTest extends CompilerTest { - - // === Test Setup =========================================================== - - import Core._ - import CoreDef.Link.Shape._ - import CoreDef.Node.Location._ - import CoreDef.Node.ParentLinks._ - import CoreDef.Node.Shape._ - import PrimGraph.Component.Refined._ - import PrimGraph.VariantCast - - // === Useful Constants ===================================================== - - val constantLocationStart = 201 - val constantLocationEnd = 1337 - val dummyLocation: Core.Location = - CoreDef.Node.LocationVal(constantLocationStart, constantLocationEnd) - - // === Utilities ============================================================ - - /** Embodies the notion that a given node construction should fail with a - * provided result. - * - * It allows a literate style of assertion as is familiar from ScalaTest - * through use of an implicit class. - * - * @param maybeErr the result of the possibly-erroring node construction - * @param core an implicit instance of core - * @tparam T the type of the node construction when it succeeds - */ - implicit class ShouldFailWithResult[T <: CoreDef.Node.Shape]( - maybeErr: Core.ConsErrOr[T] - )(implicit core: Core) { - - /** Expresses that a node should fail to construct, and provide the - * erroneous core structures in [[errList]]. - * - * @param errList a meta list (on the core graph) containing the erroneous - * core - * @return a success if [[maybeErr]] is a failure and the contained error - * matches [[errList]], otherwise a failure - */ - def shouldFailWithResult(errList: RefinedNode[MetaList]): Assertion = { - maybeErr match { - case Left(err) => - err.erroneousCore.target match { - case NodeShape.MetaList.any(xs) => - if (Utility.ListOps.equals(xs, errList)) { - succeed - } else { - fail() - } - case _ => fail() - } - case Right(_) => fail() - } - } - } - - // === Tests for Node Smart Constructors (Meta Shapes) ====================== - - "Empty nodes" should { - implicit val core: Core = new Core() - val emptyNode = Node.New.Empty() - - "have valid fields" in { - emptyNode.location shouldEqual Node.Constants.invalidLocation - emptyNode.parents shouldEqual Vector() - } - } - - "Meta list nodes" should { - implicit val core: Core = new Core() - val emptyNode = Node.New.Empty() - val nilNode = Node.New.MetaNil() - val listNode = - Node.New.MetaList(emptyNode, nilNode).getOrElse(fail()) - - "have valid fields" in { - listNode.location shouldEqual Node.Constants.invalidLocation - listNode.parents shouldEqual Vector() - } - - "have properly connected links" in { - listNode.head.source shouldEqual listNode - listNode.head.target shouldEqual emptyNode - listNode.tail.source shouldEqual listNode - listNode.tail.target shouldEqual nilNode - } - - "have children parented to the node" in { - emptyNode.parents should contain(listNode.head.ix) - nilNode.parents should contain(listNode.tail.ix) - } - - "fail to construct if tail isn't a valid meta list" in { - val node = Node.New.MetaList(emptyNode, emptyNode) - - node shouldFailWithResult Utility.ListOps.from(emptyNode) - } - } - - "Meta nil nodes" should { - implicit val core: Core = new Core() - val nilNode = Node.New.MetaNil() - - "have valid fields" in { - nilNode.location shouldEqual Node.Constants.invalidLocation - nilNode.parents shouldEqual Vector() - } - } - - "Meta true nodes" should { - implicit val core: Core = new Core() - val trueNode = Node.New.MetaTrue() - - "have valid fields" in { - trueNode.location shouldEqual Node.Constants.invalidLocation - trueNode.parents shouldEqual Vector() - } - } - - "Meta false nodes" should { - implicit val core: Core = new Core() - val falseNode = Node.New.MetaFalse() - - "have valid fields" in { - falseNode.location shouldEqual Node.Constants.invalidLocation - falseNode.parents shouldEqual Vector() - } - } - - // === Tests for Node Smart Constructors (Literals) ========================= - - "Numeric literal nodes" should { - implicit val core: Core = new Core() - val numLit = "1e-262" - val number = Node.New.NumericLiteral(numLit, dummyLocation) - - "have valid fields" in { - number.number shouldEqual numLit - number.location shouldEqual dummyLocation - number.parents shouldEqual Vector() - } - } - - "Text literal nodes" should { - implicit val core: Core = new Core() - val textLit = "FooBarBaz" - val text = Node.New.TextLiteral(textLit, dummyLocation) - - "have valid fields" in { - text.text shouldEqual textLit - text.location shouldEqual dummyLocation - text.parents shouldEqual Vector() - } - } - - "Foreign code literal nodes" should { - implicit val core: Core = new Core() - val codeLit = "lambda x: x + 1" - val code = Node.New.ForeignCodeLiteral(codeLit, dummyLocation) - - "have valid fields" in { - code.code shouldEqual codeLit - code.location shouldEqual dummyLocation - code.parents shouldEqual Vector() - } - } - - // === Tests for Node Smart Constructors (Names) ============================ - - "Name nodes" should { - implicit val core: Core = new Core() - val nameLit = "MyType" - val name = Node.New.Name(nameLit, dummyLocation) - - "have valid fields" in { - name.nameLiteral shouldEqual nameLit - name.location shouldEqual dummyLocation - name.parents shouldEqual Vector() - } - } - - "This name nodes" should { - implicit val core: Core = new Core() - val thisName = Node.New.ThisName(dummyLocation) - - "have valid fields" in { - thisName.location shouldEqual dummyLocation - thisName.parents shouldEqual Vector() - } - } - - "Here name nodes" should { - implicit val core: Core = new Core() - val hereName = Node.New.HereName(dummyLocation) - - "have valid fields" in { - hereName.location shouldEqual dummyLocation - hereName.parents shouldEqual Vector() - } - } - - // === Tests for Node Smart Constructors (Module) =========================== - - "Module nodes" should { - implicit val core: Core = new Core() - val importNil = Node.New.MetaNil() - val defNil = Node.New.MetaNil() - val name = Node.New.Name("MyModule", dummyLocation) - - val module = - Node.New - .ModuleDef(name, importNil, defNil, dummyLocation) - .getOrElse(fail()) - - "have valid fields" in { - module.location shouldEqual dummyLocation - module.parents shouldEqual Vector() - } - - "have properly connected links" in { - module.name.source shouldEqual module - module.name.target shouldEqual name - module.imports.source shouldEqual module - module.imports.target shouldEqual importNil - module.definitions.source shouldEqual module - module.definitions.target shouldEqual defNil - } - - "have children parented to the node" in { - name.parents should contain(module.name.ix) - importNil.parents should contain(module.imports.ix) - defNil.parents should contain(module.definitions.ix) - } - - "fail to construct if imports isn't a meta list" in { - val node = Node.New.ModuleDef(name, name, defNil, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - - "fail if construct definitions isn't a meta list" in { - val node = Node.New.ModuleDef(name, importNil, name, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - } - - "Import nodes" should { - implicit val core: Core = new Core() - val segmentsNil = Node.New.MetaNil() - val empty = Node.New.Empty() - val imp = - Node.New.Import(segmentsNil, dummyLocation).getOrElse(fail()) - - "have valid fields" in { - imp.location shouldEqual dummyLocation - imp.parents shouldEqual Vector() - } - - "have properly connected links" in { - imp.segments.source shouldEqual imp - imp.segments.target shouldEqual segmentsNil - } - - "have children parented to the node" in { - segmentsNil.parents should contain(imp.segments.ix) - } - - "fail to construct if segments isn't a valid meta list" in { - val node = Node.New.Import(empty, dummyLocation) - - node shouldFailWithResult Utility.ListOps.from(empty) - } - } - - "Top-level binding nodes" should { - implicit val core: Core = new Core() - val emptyModule = Node.New.Empty() - val bindingSrc = Node.New.Empty() - val bindingTgt = Node.New.Empty() - val binding = - Node.New.Binding(bindingSrc, bindingTgt, dummyLocation) - val topLevelBinding = - Node.New - .TopLevelBinding(emptyModule, binding, dummyLocation) - .getOrElse(fail()) - - "have valid fields" in { - topLevelBinding.location shouldEqual dummyLocation - topLevelBinding.parents shouldEqual Vector() - } - - "have properly connected links" in { - topLevelBinding.module.source shouldEqual topLevelBinding - topLevelBinding.module.target shouldEqual emptyModule - topLevelBinding.binding.source shouldEqual topLevelBinding - topLevelBinding.binding.target shouldEqual binding - } - - "have children parented to the node" in { - emptyModule.parents should contain(topLevelBinding.module.ix) - binding.parents should contain(topLevelBinding.binding.ix) - } - - "fail to construct if binding isn't a valid binding" in { - val node = - Node.New.TopLevelBinding(emptyModule, bindingSrc, dummyLocation) - - node shouldFailWithResult Utility.ListOps.from(bindingSrc) - } - } - - // === Tests for Node Smart Constructors (Type Definitions) ================= - - "Atom definition nodes" should { - implicit val core: Core = new Core() - - val name = Node.New.Empty() - val argName = Node.New.Empty() - val args = Utility.ListOps.from(argName) - - val atomDef = Node.New.AtomDef(name, args, dummyLocation).getOrElse(fail()) - - "have valid fields" in { - atomDef.location shouldEqual dummyLocation - atomDef.parents shouldEqual Vector() - } - - "have properly connected links" in { - atomDef.name.source shouldEqual atomDef - atomDef.name.target shouldEqual name - atomDef.args.source shouldEqual atomDef - atomDef.args.target shouldEqual args - } - - "have children parented to the node" in { - name.parents should contain(atomDef.name.ix) - args.parents should contain(atomDef.args.ix) - } - - "fail to construct if args is not a valid meta list" in { - val node = Node.New.AtomDef(name, argName, dummyLocation) - - node shouldFailWithResult Utility.ListOps.from(argName) - } - } - - "Type definition nodes" should { - implicit val core: Core = new Core() - - val name = Node.New.Empty() - val tParam = Node.New.Empty() - val tParams = Utility.ListOps.from(tParam) - - val bodyExpr = Node.New.Empty() - val body = Utility.ListOps.from(bodyExpr) - - val typeDef = - Node.New.TypeDef(name, tParams, body, dummyLocation).getOrElse(fail()) - - "have valid fields" in { - typeDef.location shouldEqual dummyLocation - typeDef.parents shouldEqual Vector() - } - - "have properly connected links" in { - typeDef.name.source shouldEqual typeDef - typeDef.name.target shouldEqual name - typeDef.typeParams.source shouldEqual typeDef - typeDef.typeParams.target shouldEqual tParams - typeDef.body.source shouldEqual typeDef - typeDef.body.target shouldEqual body - } - - "have children parented to the node" in { - name.parents should contain(typeDef.name.ix) - tParams.parents should contain(typeDef.typeParams.ix) - body.parents should contain(typeDef.body.ix) - } - - "fail to construct of the type params are not a valid meta list" in { - val node = Node.New.TypeDef(name, name, body, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - "fail to construct if the body is not a valid meta list" in { - val node = Node.New.TypeDef(name, tParams, name, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - } - - // === Tests for Node Smart Constructors (Typing) =========================== - - "Type ascription nodes" should { - implicit val core: Core = new Core() - - val typed = Node.New.Empty() - val sig = Node.New.Empty() - val ascription = Node.New.TypeAscription(typed, sig, dummyLocation) - - "have valid fields" in { - ascription.location shouldEqual dummyLocation - ascription.parents shouldEqual Vector() - } - - "have properly connected links" in { - ascription.typed.source shouldEqual ascription - ascription.typed.target shouldEqual typed - ascription.sig.source shouldEqual ascription - ascription.sig.target shouldEqual sig - } - - "have children parented to the node" in { - typed.parents should contain(ascription.typed.ix) - sig.parents should contain(ascription.sig.ix) - } - } - - "Context ascription nodes" should { - implicit val core: Core = new Core() - - val typed = Node.New.Empty() - val context = Node.New.Empty() - val ascription = Node.New.ContextAscription(typed, context, dummyLocation) - - "have valid fields" in { - ascription.location shouldEqual dummyLocation - ascription.parents shouldEqual Vector() - } - - "have properly connected links" in { - ascription.typed.source shouldEqual ascription - ascription.typed.target shouldEqual typed - ascription.context.source shouldEqual ascription - ascription.context.target shouldEqual context - } - - "have children parented to the node" in { - typed.parents should contain(ascription.typed.ix) - context.parents should contain(ascription.context.ix) - } - } - - "Typeset memeber nodes" should { - implicit val core: Core = new Core() - - val label = Node.New.Empty() - val memberType = Node.New.Empty() - val value = Node.New.Empty() - - val typesetMember = - Node.New.TypesetMember(label, memberType, value, dummyLocation) - - "have valid fields" in { - typesetMember.location shouldEqual dummyLocation - typesetMember.parents shouldEqual Vector() - } - - "have properly connected links" in { - typesetMember.label.source shouldEqual typesetMember - typesetMember.label.target shouldEqual label - typesetMember.memberType.source shouldEqual typesetMember - typesetMember.memberType.target shouldEqual memberType - typesetMember.value.source shouldEqual typesetMember - typesetMember.value.target shouldEqual value - } - - "have children parented to the node" in { - label.parents should contain(typesetMember.label.ix) - memberType.parents should contain(typesetMember.memberType.ix) - value.parents should contain(typesetMember.value.ix) - } - } - - "Typset subsumption nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val right = Node.New.Empty() - - val op = Node.New.TypesetSubsumption(left, right, dummyLocation) - - "have valid fields" in { - op.location shouldEqual dummyLocation - op.parents shouldEqual Vector() - } - - "have properly connected links" in { - op.left.source shouldEqual op - op.left.target shouldEqual left - op.right.source shouldEqual op - op.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(op.left.ix) - right.parents should contain(op.right.ix) - } - } - - "Typset equality nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val right = Node.New.Empty() - - val op = Node.New.TypesetEquality(left, right, dummyLocation) - - "have valid fields" in { - op.location shouldEqual dummyLocation - op.parents shouldEqual Vector() - } - - "have properly connected links" in { - op.left.source shouldEqual op - op.left.target shouldEqual left - op.right.source shouldEqual op - op.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(op.left.ix) - right.parents should contain(op.right.ix) - } - } - - "Typset concat nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val right = Node.New.Empty() - - val op = Node.New.TypesetConcat(left, right, dummyLocation) - - "have valid fields" in { - op.location shouldEqual dummyLocation - op.parents shouldEqual Vector() - } - - "have properly connected links" in { - op.left.source shouldEqual op - op.left.target shouldEqual left - op.right.source shouldEqual op - op.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(op.left.ix) - right.parents should contain(op.right.ix) - } - } - - "Typset union nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val right = Node.New.Empty() - - val op = Node.New.TypesetUnion(left, right, dummyLocation) - - "have valid fields" in { - op.location shouldEqual dummyLocation - op.parents shouldEqual Vector() - } - - "have properly connected links" in { - op.left.source shouldEqual op - op.left.target shouldEqual left - op.right.source shouldEqual op - op.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(op.left.ix) - right.parents should contain(op.right.ix) - } - } - - "Typset intersection nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val right = Node.New.Empty() - - val op = Node.New.TypesetIntersection(left, right, dummyLocation) - - "have valid fields" in { - op.location shouldEqual dummyLocation - op.parents shouldEqual Vector() - } - - "have properly connected links" in { - op.left.source shouldEqual op - op.left.target shouldEqual left - op.right.source shouldEqual op - op.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(op.left.ix) - right.parents should contain(op.right.ix) - } - } - - "Typset subtraction nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val right = Node.New.Empty() - - val op = Node.New.TypesetSubtraction(left, right, dummyLocation) - - "have valid fields" in { - op.location shouldEqual dummyLocation - op.parents shouldEqual Vector() - } - - "have properly connected links" in { - op.left.source shouldEqual op - op.left.target shouldEqual left - op.right.source shouldEqual op - op.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(op.left.ix) - right.parents should contain(op.right.ix) - } - } - - // === Tests for Node Smart Constructors (Function) ========================= - - "Lambda nodes" should { - implicit val core: Core = new Core() - - val arg = Node.New.Empty() - val body = Node.New.Empty() - - val lambda = Node.New.Lambda(arg, body, dummyLocation) - - "have valid fields" in { - lambda.location shouldEqual dummyLocation - lambda.parents shouldEqual Vector() - } - - "have properly connected links" in { - lambda.arg.source shouldEqual lambda - lambda.arg.target shouldEqual arg - lambda.body.source shouldEqual lambda - lambda.body.target shouldEqual body - } - - "have children parented to the node" in { - arg.parents should contain(lambda.arg.ix) - body.parents should contain(lambda.body.ix) - } - } - - "Function definition nodes" should { - implicit val core: Core = new Core() - - val name = Node.New.Empty() - val arg = Node.New.Empty() - val args = Utility.ListOps.from(arg) - val body = Node.New.Empty() - - val functionDef = - Node.New.FunctionDef(name, args, body, dummyLocation).getOrElse(fail()) - - "have valid fields" in { - functionDef.location shouldEqual dummyLocation - functionDef.parents shouldEqual Vector() - } - - "have properly connected links" in { - functionDef.name.source shouldEqual functionDef - functionDef.name.target shouldEqual name - functionDef.args.source shouldEqual functionDef - functionDef.args.target shouldEqual args - functionDef.body.source shouldEqual functionDef - functionDef.body.target shouldEqual body - } - - "have children parented to the node" in { - name.parents should contain(functionDef.name.ix) - args.parents should contain(functionDef.args.ix) - body.parents should contain(functionDef.body.ix) - } - - "fail to construct if args is not a meta list" in { - val node = Node.New.FunctionDef(name, name, body, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - } - - "Method definition nodes" should { - implicit val core: Core = new Core() - - val targetPath = Node.New.Empty() - val name = Node.New.Empty() - val lamArg = Node.New.Empty() - val lamBody = Node.New.Empty() - val function = Node.New.Lambda(lamArg, lamBody, dummyLocation) - - val methodDef = - Node.New - .MethodDef(targetPath, name, function, dummyLocation) - .getOrElse(fail()) - - "have valid fields" in { - methodDef.location shouldEqual dummyLocation - methodDef.parents shouldEqual Vector() - } - - "have properly connected links" in { - methodDef.targetPath.source shouldEqual methodDef - methodDef.targetPath.target shouldEqual targetPath - methodDef.name.source shouldEqual methodDef - methodDef.name.target shouldEqual name - methodDef.function.source shouldEqual methodDef - methodDef.function.target shouldEqual function - } - - "have children parented to the node" in { - targetPath.parents should contain(methodDef.targetPath.ix) - name.parents should contain(methodDef.name.ix) - function.parents should contain(methodDef.function.ix) - } - - "fail to construct if function is not a valid function representation" in { - val node = Node.New.MethodDef(targetPath, name, name, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - } - - // === Tests for Node Smart Constructors (Def-Site Args) ==================== - - "Ignored argument nodes" should { - implicit val core: Core = new Core() - - val ignored = Node.New.IgnoredArgument(dummyLocation) - - "have valid fields" in { - ignored.location shouldEqual dummyLocation - ignored.parents shouldEqual Vector() - } - } - - "Definition argument nodes" should { - implicit val core: Core = new Core() - - val name = Node.New.Empty() - val suspended = Node.New.MetaTrue() - val default = Node.New.Empty() - - val arg = Node.New - .DefinitionArgument(name, suspended, default, dummyLocation) - .getOrElse(fail()) - - "have valid fields" in { - arg.location shouldEqual dummyLocation - arg.parents shouldEqual Vector() - } - - "have properly connected links" in { - arg.name.source shouldEqual arg - arg.name.target shouldEqual name - arg.suspended.source shouldEqual arg - arg.suspended.target shouldEqual suspended - arg.default.source shouldEqual arg - arg.default.target shouldEqual default - } - - "have children parented to the node" in { - name.parents should contain(arg.name.ix) - suspended.parents should contain(arg.suspended.ix) - default.parents should contain(arg.default.ix) - } - - "fail to construct if suspended is not a meta boolean" in { - val node = Node.New.DefinitionArgument(name, name, default, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(name) - } - } - - // === Tests for Node Smart Constructors (Applications) ===================== - - "Application nodes" should { - implicit val core: Core = new Core() - - val function = Node.New.Empty() - val argument = Node.New.Empty() - - val application = Node.New.Application(function, argument, dummyLocation) - - "have valid fields" in { - application.location shouldEqual dummyLocation - application.parents shouldEqual Vector() - } - - "have properly connected links" in { - application.function.source shouldEqual application - application.function.target shouldEqual function - application.argument.source shouldEqual application - application.argument.target shouldEqual argument - } - - "have children parented to the node" in { - function.parents should contain(application.function.ix) - argument.parents should contain(application.argument.ix) - } - } - - "Infix application nodes" should { - implicit val core: Core = new Core() - - val left = Node.New.Empty() - val operator = Node.New.Empty() - val right = Node.New.Empty() - - val app = Node.New.InfixApplication(left, operator, right, dummyLocation) - - "have valid fields" in { - app.location shouldEqual dummyLocation - app.parents shouldEqual Vector() - } - - "have properly connected links" in { - app.left.source shouldEqual app - app.left.target shouldEqual left - app.operator.source shouldEqual app - app.operator.target shouldEqual operator - app.right.source shouldEqual app - app.right.target shouldEqual right - } - - "have children parented to the node" in { - left.parents should contain(app.left.ix) - operator.parents should contain(app.operator.ix) - right.parents should contain(app.right.ix) - } - } - - "Left section nodes" should { - implicit val core: Core = new Core() - - val arg = Node.New.Empty() - val operator = Node.New.Empty() - - val sec = Node.New.LeftSection(arg, operator, dummyLocation) - - "have valid fields" in { - sec.location shouldEqual dummyLocation - sec.parents shouldEqual Vector() - } - - "have properly connected links" in { - sec.arg.source shouldEqual sec - sec.arg.target shouldEqual arg - sec.operator.source shouldEqual sec - sec.operator.target shouldEqual operator - } - - "have children parented to the node" in { - arg.parents should contain(sec.arg.ix) - operator.parents should contain(sec.operator.ix) - } - } - - "Right section nodes" should { - implicit val core: Core = new Core() - - val operator = Node.New.Empty() - val arg = Node.New.Empty() - - val sec = Node.New.RightSection(operator, arg, dummyLocation) - - "have valid fields" in { - sec.location shouldEqual dummyLocation - sec.parents shouldEqual Vector() - } - - "have properly connected links" in { - sec.operator.source shouldEqual sec - sec.operator.target shouldEqual operator - sec.arg.source shouldEqual sec - sec.arg.target shouldEqual arg - } - - "have children parented to the node" in { - operator.parents should contain(sec.operator.ix) - arg.parents should contain(sec.arg.ix) - } - } - - "Centre section nodes" should { - implicit val core: Core = new Core() - - val operator = Node.New.Empty() - - val sec = Node.New.CentreSection(operator, dummyLocation) - - "have valid fields" in { - sec.location shouldEqual dummyLocation - sec.parents shouldEqual Vector() - } - - "have properly connected links" in { - sec.operator.source shouldEqual sec - sec.operator.target shouldEqual operator - } - - "have children parented to the node" in { - operator.parents should contain(sec.operator.ix) - } - } - - "Forced term nodes" should { - implicit val core: Core = new Core() - - val expression = Node.New.Empty() - - val forcedTerm = Node.New.ForcedTerm(expression, dummyLocation) - - "have valid fields" in { - forcedTerm.location shouldEqual dummyLocation - forcedTerm.parents shouldEqual Vector() - } - - "have properly connected links" in { - forcedTerm.expression.source shouldEqual forcedTerm - forcedTerm.expression.target shouldEqual expression - } - - "have children parented to the node" in { - expression.parents should contain(forcedTerm.expression.ix) - } - } - - // === Tests for Node Smart Constructors (Call-Site Args) =================== - - "Lambda shorthand argument nodes" should { - implicit val core: Core = new Core() - - val arg = Node.New.LambdaShorthandArgument(dummyLocation) - - "have valid fields" in { - arg.location shouldEqual dummyLocation - arg.parents shouldEqual Vector() - } - } - - "Call-site argument nodes" should { - implicit val core: Core = new Core() - - val expression = Node.New.Empty() - val name = Node.New.Empty() - - val arg = Node.New.CallSiteArgument(expression, name, dummyLocation) - - "have valid fields" in { - arg.location shouldEqual dummyLocation - arg.parents shouldEqual Vector() - } - - "have properly connected links" in { - arg.expression.source shouldEqual arg - arg.expression.target shouldEqual expression - arg.name.source shouldEqual arg - arg.name.target shouldEqual name - } - - "have children parented to the node" in { - expression.parents should contain(arg.expression.ix) - name.parents should contain(arg.name.ix) - } - } - - "Default suspension operator nodes" should { - implicit val core: Core = new Core() - - val suspend = Node.New.SuspendDefaultsOperator(dummyLocation) - - "have valid fields" in { - suspend.location shouldEqual dummyLocation - suspend.parents shouldEqual Vector() - } - } - - // === Tests for Node Smart Constructors (Structure) ======================== - - "Block nodes" should { - implicit val core: Core = new Core() - - val expressions = Utility.ListOps.from(Node.New.Empty()) - val returnVal = Node.New.Empty() - - val block = - Node.New.Block(expressions, returnVal, dummyLocation).getOrElse(fail()) - - "have valid fields" in { - block.location shouldEqual dummyLocation - block.parents shouldEqual Vector() - } - - "have properly connected links" in { - block.expressions.source shouldEqual block - block.expressions.target shouldEqual expressions - block.returnVal.source shouldEqual block - block.returnVal.target shouldEqual returnVal - } - - "have children parented to the node" in { - expressions.parents should contain(block.expressions.ix) - returnVal.parents should contain(block.returnVal.ix) - } - - "fail to construct if expressions is not a valid meta list" in { - val node = Node.New.Block(returnVal, returnVal, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(returnVal) - } - } - - "Binding nodes" should { - implicit val core: Core = new Core() - - val name = Node.New.Empty() - val expression = Node.New.Empty() - - val binding = Node.New.Binding(name, expression, dummyLocation) - - "have valid fields" in { - binding.location shouldEqual dummyLocation - binding.parents shouldEqual Vector() - } - - "have properly connected links" in { - binding.name.source shouldEqual binding - binding.name.target shouldEqual name - binding.expression.source shouldEqual binding - binding.expression.target shouldEqual expression - } - - "have children parented to the node" in { - name.parents should contain(binding.name.ix) - expression.parents should contain(binding.expression.ix) - } - } - - // === Tests for Node Smart Constructors (Case Expression) ================== - - "Case expression nodes" should { - implicit val core: Core = new Core() - - val scrutinee = Node.New.Empty() - val branches = Utility.ListOps.from(Node.New.Empty()) - - val caseExpr = - Node.New.CaseExpr(scrutinee, branches, dummyLocation).getOrElse(fail()) - - "have valid fields" in { - caseExpr.location shouldEqual dummyLocation - caseExpr.parents shouldEqual Vector() - } - - "have properly connected links" in { - caseExpr.scrutinee.source shouldEqual caseExpr - caseExpr.scrutinee.target shouldEqual scrutinee - caseExpr.branches.source shouldEqual caseExpr - caseExpr.branches.target shouldEqual branches - } - - "have children parented to the node" in { - scrutinee.parents should contain(caseExpr.scrutinee.ix) - branches.parents should contain(caseExpr.branches.ix) - } - - "fail to construct if branches is not a valid meta list" in { - val node = Node.New.CaseExpr(scrutinee, scrutinee, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(scrutinee) - } - } - - "Case branch nodes" should { - implicit val core: Core = new Core() - - val pattern = Node.New.Empty() - val expression = Node.New.Empty() - - val caseBranch = Node.New.CaseBranch(pattern, expression, dummyLocation) - - "have valid fields" in { - caseBranch.location shouldEqual dummyLocation - caseBranch.parents shouldEqual Vector() - } - - "have properly connected links" in { - caseBranch.pattern.source shouldEqual caseBranch - caseBranch.pattern.target shouldEqual pattern - caseBranch.expression.source shouldEqual caseBranch - caseBranch.expression.target shouldEqual expression - } - - "have children parented to the node" in { - pattern.parents should contain(caseBranch.pattern.ix) - expression.parents should contain(caseBranch.expression.ix) - } - } - - "Structural pattern nodes" should { - implicit val core: Core = new Core() - - val matchExpression = Node.New.Empty() - - val pattern = Node.New.StructuralPattern(matchExpression, dummyLocation) - - "have valid fields" in { - pattern.location shouldEqual dummyLocation - pattern.parents shouldEqual Vector() - } - - "have properly connected links" in { - pattern.matchExpression.source shouldEqual pattern - pattern.matchExpression.target shouldEqual matchExpression - } - - "have children parented to the node" in { - matchExpression.parents should contain(pattern.matchExpression.ix) - } - } - - "Type pattern nodes" should { - implicit val core: Core = new Core() - - val matchExpression = Node.New.Empty() - - val pattern = Node.New.TypePattern(matchExpression, dummyLocation) - - "have valid fields" in { - pattern.location shouldEqual dummyLocation - pattern.parents shouldEqual Vector() - } - - "have properly connected links" in { - pattern.matchExpression.source shouldEqual pattern - pattern.matchExpression.target shouldEqual matchExpression - } - - "have children parented to the node" in { - matchExpression.parents should contain(pattern.matchExpression.ix) - } - } - - "Named pattern nodes" should { - implicit val core: Core = new Core() - - val matchExpression = Node.New.Empty() - - val pattern = Node.New.NamedPattern(matchExpression, dummyLocation) - - "have valid fields" in { - pattern.location shouldEqual dummyLocation - pattern.parents shouldEqual Vector() - } - - "have properly connected links" in { - pattern.matchExpression.source shouldEqual pattern - pattern.matchExpression.target shouldEqual matchExpression - } - - "have children parented to the node" in { - matchExpression.parents should contain(pattern.matchExpression.ix) - } - } - - "Fallback pattern nodes" should { - implicit val core: Core = new Core() - - val pattern = Node.New.FallbackPattern(dummyLocation) - - "have valid fields" in { - pattern.location shouldEqual dummyLocation - pattern.parents shouldEqual Vector() - } - } - - // === Tests for Node Smart Constructors (Comments) ========================= - - "Doc comment nodes" should { - implicit val core: Core = new Core() - - val commented = Node.New.Empty() - val doc = Node.New.Empty() - - val docComment = Node.New.DocComment(commented, doc, dummyLocation) - - "have valid fields" in { - docComment.location shouldEqual dummyLocation - docComment.parents shouldEqual Vector() - } - - "have properly connected links" in { - docComment.commented.source shouldEqual docComment - docComment.commented.target shouldEqual commented - docComment.doc.source shouldEqual docComment - docComment.doc.target shouldEqual doc - } - - "have children parented to the node" in { - commented.parents should contain(docComment.commented.ix) - doc.parents should contain(docComment.doc.ix) - } - } - - // === Tests for Node Smart Constructors (Foreign) ========================== - - "Foreign definition nodes" should { - implicit val core: Core = new Core() - - val language = Node.New.Empty() - val code = - Node.New.ForeignCodeLiteral("lambda x: x + 1", dummyLocation) - - val foreignDefinition = - Node.New - .ForeignDefinition(language, code, dummyLocation) - .getOrElse(fail()) - - "have valid fields" in { - foreignDefinition.location shouldEqual dummyLocation - foreignDefinition.parents shouldEqual Vector() - } - - "have properly connected links" in { - foreignDefinition.language.source shouldEqual foreignDefinition - foreignDefinition.language.target shouldEqual language - foreignDefinition.code.source shouldEqual foreignDefinition - foreignDefinition.code.target shouldEqual code - } - - "have children parented to the node" in { - language.parents should contain(foreignDefinition.language.ix) - code.parents should contain(foreignDefinition.code.ix) - } - - "fail to construct of code is not a valid foreign code literal" in { - val node = Node.New.ForeignDefinition(language, language, dummyLocation) - node shouldFailWithResult Utility.ListOps.from(language) - } - } - - // === Tests for Node Smart Constructors (Errors) =========================== - - "Syntax error nodes" should { - implicit val core: Core = new Core() - - val astWithLocation: AST = AST - .Blank() - .setLocation( - AstLocation(dummyLocation.sourceStart, dummyLocation.sourceEnd) - ) - val astNoLocation: AST = AST.Blank() - - val syntaxError = Node.New.SyntaxError(astWithLocation) - - "have valid fields" in { - syntaxError.parents shouldEqual Vector() - } - - "inherit the location from the AST" in { - syntaxError.location shouldEqual dummyLocation - } - - "default to an invalid location if the AST does not provide any" in { - val errorNoLocation = Node.New.SyntaxError(astNoLocation) - errorNoLocation.location shouldEqual Constants.invalidLocation - } - } - - "Construction error nodes" should { - implicit val core: Core = new Core() - - val errNode = Node.New.Empty() - val errList = Utility.ListOps.from(errNode) - val error = Node.New.ConstructionError(errList, dummyLocation) - - "have valid fields" in { - error.location shouldEqual dummyLocation - error.parents shouldEqual Vector() - } - - "have properly connected links" in { - error.erroneousCore.source shouldEqual error - error.erroneousCore.target shouldEqual errList - } - - "have children parented to the node" in { - errList.parents should contain(error.erroneousCore.ix) - } - - "use a passed-in meta list unchanged" in { - error.erroneousCore.target shouldEqual errList - } - - "contain a meta-list if passed a single node" in { - val input = errNode - val err = Node.New.ConstructionError(input, dummyLocation) - - input.wrapped.is[NodeShape.Empty] shouldEqual true - - Utility.ListOps.is(input) should not equal true - Utility.ListOps.is(err.erroneousCore.target) shouldEqual true - - // The only element in that list should be the single node - err.erroneousCore.target.unsafeAs[MetaList].head.target shouldEqual input - err.erroneousCore.target - .unsafeAs[MetaList] - .tail - .target - .is[MetaNil] shouldBe true - } - } - - // === Tests for Node Utility Functions ===================================== - - "Lists" should { - implicit val core: Core = new Core() - - val empty1 = Node.New.Empty().wrapped - val empty2 = Node.New.Empty().wrapped - - val list1 = Utility.ListOps.from(NonEmptyList(empty1, List(empty2))) - val list2 = Utility.ListOps.from(NonEmptyList(empty1, List(empty2))) - val list3 = Utility.ListOps.from(NonEmptyList(empty2, List(empty1))) - - "be defined as equal when the child nodes are equal" in { - Utility.ListOps.equals(list1, list2) shouldEqual true - } - - "be defined as not equal when the child nodes are not equal" in { - Utility.ListOps.equals(list1, list3) shouldEqual false - } - } - - "Nodes for meta booleans" should { - implicit val core: Core = new Core() - - val emptyNode = Node.New.Empty() - val trueNode = Node.New.MetaTrue() - val falseNode = Node.New.MetaFalse() - - "be correctly identified" in { - BoolOps.is(emptyNode) shouldEqual false - BoolOps.is(trueNode) shouldEqual true - BoolOps.is(falseNode) shouldEqual true - } - } - - "Nodes for meta lists" should { - implicit val core: Core = new Core() - val emptyNode = Node.New.Empty() - val nilNode = Node.New.MetaNil() - val consNode = - Node.New.MetaList(emptyNode, nilNode).getOrElse(fail()) - - "be correctly identified" in { - Utility.ListOps.is(emptyNode) shouldEqual false - Utility.ListOps.is(nilNode) shouldEqual true - Utility.ListOps.is(consNode) shouldEqual true - } - } - - "Core lists" should { - implicit val core: Core = new Core() - - val emptyNode1 = Node.New.Empty().wrapped - val emptyNode2 = Node.New.Empty().wrapped - val emptyNode3 = Node.New.Empty().wrapped - - val listOfOne = Utility.ListOps.from(emptyNode1) - val listOfMany = Utility.ListOps - .from(NonEmptyList(emptyNode1, List(emptyNode2, emptyNode3))) - - "be able to be constructed from arbitrary nodes" in { - listOfOne.head.target shouldEqual emptyNode1 - - listOfOne.tail.target match { - case NodeShape.MetaNil.any(_) => - case _ => fail() - } - - listOfMany.head.target shouldEqual emptyNode1 - - listOfMany.tail.target match { - case NodeShape.MetaList.any(e2) => - e2.head.target shouldEqual emptyNode2 - - e2.tail.target match { - case NodeShape.MetaList.any(e3) => - e3.head.target shouldEqual emptyNode3 - e3.tail.target match { - case NodeShape.MetaNil.any(_) => succeed - case _ => fail() - } - case _ => fail() - } - case _ => fail() - } - } - } - - // === Tests for Node Conversions =========================================== - - "AST locations" should { - val startLoc = 1232 - val endLoc = 1337 - - val astLoc = AstLocation(startLoc, endLoc) - val coreLoc = CoreDef.Node.LocationVal(startLoc, endLoc) - - "be converted losslessly to core locations" in { - Node.Conversions.astLocationToNodeLocation(astLoc) shouldEqual coreLoc - } - } - - // === Tests for Link Smart Constructors ==================================== - - "Connected links" should { - implicit val core: Core = new Core() - - val n1 = Node.New.Empty() - val n2 = Node.New.Empty() - - val link = Link.New.Connected(n1, n2) - - "be able to be made with a source and target" in { - link.source shouldEqual n1 - link.target shouldEqual n2 - } - - "be a parent of their target" in { - n2.parents should contain(link.ix) - } - } - - "Disconnected links" should { - implicit val core: Core = new Core() - - val sourceNode = Node.New.MetaNil() - - val link = Link.New.Disconnected(sourceNode) - - "be able to be made with only a source" in { - link.source shouldEqual sourceNode - - link.target match { - case NodeShape.Empty.any(_) => succeed - case _ => fail() - } - } - - "be a parent of their empty target" in { - link.target.parents should contain(link.ix) - } - } -} From 38cd2415b467436abdd61621afb3adb962e9847c Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 7 Jun 2022 10:00:08 +0200 Subject: [PATCH 3/4] Also remove (now) unused core-definition --- build.sbt | 28 - lib/scala/core-definition/README.md | 5 - .../main/scala/org/enso/core/CoreGraph.scala | 656 ------------------ 3 files changed, 689 deletions(-) delete mode 100644 lib/scala/core-definition/README.md delete mode 100644 lib/scala/core-definition/src/main/scala/org/enso/core/CoreGraph.scala diff --git a/build.sbt b/build.sbt index b42f122a314a..766678e62dbc 100644 --- a/build.sbt +++ b/build.sbt @@ -232,7 +232,6 @@ bootstrap := {} lazy val enso = (project in file(".")) .settings(version := "0.1") .aggregate( - `core-definition`, `interpreter-dsl`, `json-rpc-server-test`, `json-rpc-server`, @@ -938,30 +937,6 @@ lazy val testkit = project ) ) -lazy val `core-definition` = (project in file("lib/scala/core-definition")) - .configs(Benchmark) - .settings( - version := "0.1", - inConfig(Compile)(truffleRunOptionsSettings), - inConfig(Benchmark)(Defaults.testSettings), - Test / parallelExecution := false, - Test / logBuffered := false, - scalacOptions += "-Ymacro-annotations", - libraryDependencies ++= jmh ++ Seq( - "com.chuusai" %% "shapeless" % shapelessVersion, - "org.scalacheck" %% "scalacheck" % scalacheckVersion % Test, - "org.scalactic" %% "scalactic" % scalacticVersion % Test, - "org.scalatest" %% "scalatest" % scalatestVersion % Test, - "org.typelevel" %% "cats-core" % catsVersion, - "com.github.julien-truffaut" %% "monocle-core" % monocleVersion - ), - addCompilerPlugin( - "org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full - ) - ) - .dependsOn(graph) - .dependsOn(syntax.jvm) - lazy val searcher = project .in(file("lib/scala/searcher")) .configs(Test) @@ -1222,15 +1197,12 @@ lazy val runtime = (project in file("engine/runtime")) "com.novocode" % "junit-interface" % "0.11" % Test exclude ("junit", "junit-dep") ), // Note [Unmanaged Classpath] - Compile / unmanagedClasspath += (`core-definition` / Compile / packageBin).value, - Test / unmanagedClasspath += (`core-definition` / Compile / packageBin).value, Test / unmanagedClasspath += (baseDirectory.value / ".." / ".." / "app" / "gui" / "view" / "graph-editor" / "src" / "builtin" / "visualization" / "native" / "inc"), Compile / compile / compileInputs := (Compile / compile / compileInputs) .dependsOn(CopyTruffleJAR.preCompileTask) .value, Compile / compile := FixInstrumentsGeneration.patchedCompile .dependsOn(FixInstrumentsGeneration.preCompileTask) - .dependsOn(`core-definition` / Compile / packageBin) .value, // Note [Classpath Separation] Test / javaOptions ++= Seq( diff --git a/lib/scala/core-definition/README.md b/lib/scala/core-definition/README.md deleted file mode 100644 index 84922d7742d2..000000000000 --- a/lib/scala/core-definition/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Core Definition - -This library contains the definition of the Enso core language. This language is -used in the Enso compiler as an intermediate representation to enable both a -flexible, pass-based architecture, and integrated type-checking. diff --git a/lib/scala/core-definition/src/main/scala/org/enso/core/CoreGraph.scala b/lib/scala/core-definition/src/main/scala/org/enso/core/CoreGraph.scala deleted file mode 100644 index 665a13f6fc6d..000000000000 --- a/lib/scala/core-definition/src/main/scala/org/enso/core/CoreGraph.scala +++ /dev/null @@ -1,656 +0,0 @@ -package org.enso.core - -import org.enso.graph.definition.Macro.{component, field, genGraph, opaque} -import org.enso.graph.{Sized, VariantIndexed, Graph => PrimGraph} -import shapeless.{::, HNil} -import org.enso.syntax.text.AST - -object CoreGraph { - @genGraph object Definition { - - // ======================================================================== - // === The Graph Definition =============================================== - // ======================================================================== - - /** This type denotes the core graph itself. */ - case class CoreGraph() extends PrimGraph - - /** The list of components that make up a [[CoreGraph]]. */ - implicit def components = - new PrimGraph.Component.List[CoreGraph] { - type Out = Nodes :: Links :: HNil - } - - // ======================================================================== - // === Opaque Storage ===================================================== - // ======================================================================== - - /** Storage for string literals. */ - @opaque case class Literal(opaque: String) - - /** Storage for name literals. */ - @opaque case class Name(opaque: String) - - /** Storage for parents for a given node. - * - * An entry in the vector will be the index of an [[Edge]] in the graph - * that has the containing node as its `target` field. - */ - @opaque case class Parent(opaque: Vector[Int]) - - /** Storage for raw AST nodes. */ - @opaque case class Ast(opaque: AST) - - // ======================================================================== - // === Node =============================================================== - // ======================================================================== - - /** A node in the [[CoreGraph]]. */ - @component case class Nodes() { type Node[G <: PrimGraph] } - - /** The list of fields that a [[Node]] has in a [[CoreGraph]]. */ - implicit def nodeFields = - new PrimGraph.Component.Field.List[CoreGraph, Nodes] { - type Out = Node.Shape :: Node.ParentLinks :: Node.Location :: HNil - } - - object Node { - - // ====================================================================== - // === Field Definitions ================================================ - // ====================================================================== - - /** A location describes which portion of the source code this particular - * node in the graph represents. - * - * @param sourceStart the start position in the source code - * @param sourceEnd the end position in the source code - * @tparam G the graph type - */ - @field case class Location[G <: PrimGraph]( - sourceStart: Int, - sourceEnd: Int - ) - - /** This type represents all the incoming [[Link]]s to the current node. - * - * It should be noted that it _does not_ store the links directly. This - * would only make sense if the link direction was reversed. Instead, it - * holds unsafe references to the incoming link in the underlying graph. - * These can be turned into the [[Link]]s directly by using - * [[PrimGraph.GraphData.componentRefFromIndex()]]. - * - * @param parents a vector containing the raw indices of the parent links - * @tparam G the graph type - */ - @field case class ParentLinks[G <: PrimGraph]( - parents: OpaqueData[Vector[Int], ParentStorage] - ) - - /** The shape of a node represents all the different forms that a node can - * take. - */ - @field object Shape { - type G = PrimGraph - - // === Base Shapes ==================================================== - /** A representation of a node that has no particular shape. */ - case class Empty() - - /** A representation of a cons cell for building linked lists on the - * graph. - * - * These should be used _very_ sparingly, if at all, but they provide a - * way to store dynamically-sized core components providing they can be - * broken down into statically sized components. - * - * The [[tail]] parameter should always point to either another node - * with shape [[MetaList]] or a node with shape [[MetaNil]]. - * - * It should be noted that, given that each [[Node]] contains a field - * of [[ParentLinks]], that constructing this properly provides a - * doubly-linked list, as no [[MetaList]] or [[MetaNil]] should have - * more than one parent. - * - * @param head the current, arbitrary, element in the list - * @param tail the rest of the list - */ - case class MetaList(head: Link[G], tail: Link[G]) - - /** A representation of the end of a linked-list on the graph. */ - case class MetaNil() - - /** A node representing boolean true. */ - case class MetaTrue() - - /** A node representing boolean false. */ - case class MetaFalse() - - // === Literals ======================================================= - - /** A representation of a numeric literal. - * - * @param number the numeric literal - */ - case class NumericLiteral(number: OpaqueData[String, LiteralStorage]) - - /** A representation of a textual literal. - * - * @param text the textual literal - */ - case class TextLiteral(text: OpaqueData[String, LiteralStorage]) - - /** A representation of literal text from a foreign code block. - * - * @param code the foreign code literal - */ - case class ForeignCodeLiteral(code: OpaqueData[String, LiteralStorage]) - - // === Names ========================================================== - - /** A name. - * - * @param nameLiteral the literal string representing the name - */ - case class Name(nameLiteral: OpaqueData[String, LiteralStorage]) - - /** A representation of the `this` reserved name */ - case class ThisName() - - /** A representation of the `here` reserved name */ - case class HereName() - - // === Module ========================================================= - - /** The core representation of a top-level Enso module. - * - * @param name the name of the module - * @param imports the module's imports as a [[MetaList]], where - * each list member points to an import - * @param definitions the module's definitions as a [[MetaList]], where - * each list member points to a binding - */ - case class ModuleDef( - name: Link[G], - imports: Link[G], - definitions: Link[G] - ) - - /** An import statement. - * - * @param segments the segments of the import path, represented as a - * [[MetaList]]. - */ - case class Import(segments: Link[G]) - - /** A module-level binding. - * - * @param module a link to the module in which this binding is found - * @param binding the binding itself - */ - case class TopLevelBinding(module: Link[G], binding: Link[G]) - - // === Type Definitions =============================================== - - /** An atom definition. - * - * @param name the name of the atom - * @param args the atom's arguments as a [[MetaList]] - */ - case class AtomDef(name: Link[G], args: Link[G]) - - /** An expanded-form type definition, with a body. - * - * @param name the name of the aggregate type - * @param typeParams the type parameters to the definition, as a - * [[MetaList]] of bindings - * @param body the body of the type definition, represented as a - * [[MetaList]] of bindings - */ - case class TypeDef( - name: Link[G], - typeParams: Link[G], - body: Link[G] - ) - - // === Typing ========================================================= - - /** The ascription of a type to a value. - * - * @param typed the expression being ascribed a type - * @param sig the signature being ascribed to [[typed]] - */ - case class TypeAscription(typed: Link[G], sig: Link[G]) - - /** A representation of the `in` portion of a type signature that - * represents the ascription of a monadic context. - * - * @param typed the type being put in a context - * @param context the context - */ - case class ContextAscription(typed: Link[G], context: Link[G]) - - /** A representation of a typeset member. - * - * PLEASE NOTE: This is here more as a note than anything, and will not - * be exposed to users yet. It is currently used for Atom arguments. - * - * @param label the member's label, if given - * @param memberType the member's type, if given - * @param value the member's value, if given - */ - case class TypesetMember( - label: Link[G], - memberType: Link[G], - value: Link[G] - ) - - /** The typset subsumption judgement `<:`. - * - * This construct does not represent a user-facing language element. - * - * @param left the left type in the subsumption judgement - * @param right the right type in the subsumption judgement - */ - case class TypesetSubsumption(left: Link[G], right: Link[G]) - - /** The typeset equality judgement `~`. - * - * This construct does not represent a user-facing language element. - * - * @param left the left operand - * @param right the right operand - */ - case class TypesetEquality(left: Link[G], right: Link[G]) - - /** The typeset concatenation operator `,`. - * - * @param left the left operand - * @param right the right operand - */ - case class TypesetConcat(left: Link[G], right: Link[G]) - - /** The typeset union operator `|`. - * - * @param left the left operand - * @param right the right operand - */ - case class TypesetUnion(left: Link[G], right: Link[G]) - - /** The typeset intersection operator `&`. - * - * @param left the left operand - * @param right the right operand - */ - case class TypesetIntersection(left: Link[G], right: Link[G]) - - /** The typeset subtraction operator `\`. - * - * @param left the left operand - * @param right the right operand - */ - case class TypesetSubtraction(left: Link[G], right: Link[G]) - - // === Function ======================================================= - - /** A lambda expression, the `->` function arrrow. - * - * Note that all lambdas in Enso are explicitly single-argument. - * - * @param arg the argument to the lambda - * @param body the body of the lambda - */ - case class Lambda(arg: Link[G], body: Link[G]) - - /** A sugared function definition. - * - * @param name the name of the function - * @param args the function arguments, as a [[MetaList]] - * @param body the body of the function - */ - case class FunctionDef(name: Link[G], args: Link[G], body: Link[G]) - - /** A method definition. - * - * @param targetPath the path of the method - * @param name the name of the method - * @param function the function that is executed (can be any callable - * representation) - */ - case class MethodDef( - targetPath: Link[G], - name: Link[G], - function: Link[G] - ) - - // === Definition-Site Argument Types ================================= - - /** An ignored function argument, denoted by `_`. - * - * This can commonly be seen in use where an API requires a function - * take an argument, but a particular implementation doesn't need it: - * `_ -> ...`. - */ - case class IgnoredArgument() - - /** A function argument definition. - * - * @param name the name of the argument - * @param suspended whether or not the argument uses suspended - * evaluation (should be [[MetaTrue]] or [[MetaFalse]] - * @param default the default value for the argument, if present - */ - case class DefinitionArgument( - name: Link[G], - suspended: Link[G], - default: Link[G] - ) - - // === Applications =================================================== - - /** A function application. - * - * All functions in Enso are curried by default, and are represented in - * the [[CoreGraph]] as single-argument functions. - * - * @param function function expression being called - * @param argument the argument to the function - */ - case class Application(function: Link[G], argument: Link[G]) - - /** An infix function application. - * - * @param left the left argument - * @param operator the function being applied - * @param right the right argument - */ - case class InfixApplication( - left: Link[G], - operator: Link[G], - right: Link[G] - ) - - /** A left section operator application. - * - * @param arg the left argument to [[operator]] - * @param operator the function being sectioned - */ - case class LeftSection(arg: Link[G], operator: Link[G]) - - /** A right section operator application. - * - * @param operator the function being sectioned - * @param arg the right argument to [[operator]] - */ - case class RightSection(operator: Link[G], arg: Link[G]) - - /** A centre section operator application. - * - * @param operator the operator being sectioned - */ - case class CentreSection(operator: Link[G]) - - /** A representation of a term that is explicitly forced. - * - * An explicitly forced term is one where the user has explicitly - * called the `force` operator on it. This is useful only while the - * compiler does not _automatically_ handle suspensions and forcing. - * - * PLEASE NOTE: This is temporary and will be removed as soon as the - * compiler is capable enough to not require it. - * - * @param expression - */ - case class ForcedTerm(expression: Link[G]) - - // === Call-Site Argument Types ======================================= - - /** Used to represent `_` arguments that are shorthand for the creation - * of lambdas. - */ - case class LambdaShorthandArgument() - - /** A function call-site argument. - * - * @param expression the argument expression - * @param name the name of the argument, if given - */ - case class CallSiteArgument(expression: Link[G], name: Link[G]) - - /** The `...` argument that may be passed to a function to suspend the - * execution of its default arguments. - */ - case class SuspendDefaultsOperator() - - // === Structure ====================================================== - - /** A block expression. - * - * @param expressions the expressions in the block as a [[MetaList]] - * @param returnVal the final expression of the block - */ - case class Block(expressions: Link[G], returnVal: Link[G]) - - /** A binding expression of the form `name = expr`. - * - * @param name the name being bound to - * @param expression the expression being bound to [[name]] - */ - case class Binding(name: Link[G], expression: Link[G]) - - // === Case Expression ================================================ - - /** A case expression. - * - * @param scrutinee the case expression's scrutinee - * @param branches the match branches, as a [[MetaList]] - */ - case class CaseExpr(scrutinee: Link[G], branches: Link[G]) - - /** A case branch. - * - * All case patterns will initially be desugared to a - * [[StructuralPattern]] and will be refined during further desugaring - * passes, some of which may depend on type checking. - * - * @param pattern the pattern to match the scrutinee against - * @param expression the expression - */ - case class CaseBranch(pattern: Link[G], expression: Link[G]) - - /** A pattern that matches on the scrutinee based on its structure. - * - * @param matchExpression the expression representing the possible - * structure of the scrutinee - */ - case class StructuralPattern(matchExpression: Link[G]) - - /** A pattern that matches on the scrutinee purely based on a type - * subsumption judgement. - * - * @param matchExpression the expression representing the possible type - * of the scrutinee - */ - case class TypePattern(matchExpression: Link[G]) - - /** A pattern that matches on the scrutinee based on a type subsumption - * judgement and assigns a new name to it for use in the branch. - * - * @param matchExpression the expression representing the possible type - * of the scrutinee, and its new name - */ - case class NamedPattern(matchExpression: Link[G]) - - /** A pattern that matches on any scrutinee. */ - case class FallbackPattern() - - // === Comments ======================================================= - - /** A documentation comment. - * - * @param commented the commented entity - * @param doc a [[TextLiteral]] containing the documentation comment - */ - case class DocComment(commented: Link[G], doc: Link[G]) - - // === Foreign ======================================================== - - /** A foreign code definition. - * - * @param language the name of the foreign programming language - * @param code the foreign code, represented as a [[ForeignCodeLiteral]] - */ - case class ForeignDefinition(language: Link[G], code: Link[G]) - - // === Errors ========================================================= - - /** A syntax error. - * - * @param errorAst the raw AST representation of the syntax error - */ - case class SyntaxError(errorAst: OpaqueData[AST, AstStorage]) - - /** Returned on an attempt to construct erroneous core. - * - * @param erroneousCore a [[MetaList]] containing the one-or-more core - * nodes that were in an incorrect format - */ - case class ConstructionError(erroneousCore: Link[G]) - } - - // ====================================================================== - // === Utility Functions ================================================ - // ====================================================================== - - /** Adds a link as a parent of the provided node. - * - * This should _only_ be used when the [[target]] field of [[link]] - * points to [[node]]. - * - * @param node the node to add a parent to - * @param link the link to add as a parent - * @param graph the graph in which this takes place - * @param map the graph's parent storage - */ - def addParent( - node: Node[CoreGraph], - link: Link[CoreGraph] - )(implicit - graph: PrimGraph.GraphData[CoreGraph], - map: ParentStorage - ): Unit = { - import Node.ParentLinks._ - - node.parents = node.parents :+ link.ix - } - - /** Adds a node to the graph with its shape already set to a given shape. - * - * @param graph the graph to add the node to - * @param ev evidence that the variant field is indexed - * @tparam V the shape to set the node to - * @return a refined node reference - */ - def addRefined[V <: Node.Shape](implicit - graph: PrimGraph.GraphData[CoreGraph], - ev: VariantIndexed[Node.Shape, V] - ): PrimGraph.Component.Refined[Node.Shape, V, Node[CoreGraph]] = { - val node = graph.addNode() - - setShape[V](node) - PrimGraph.Component.Refined[Node.Shape, V, Node[CoreGraph]](node) - } - - /** Sets the shape of the provided [[node]] to [[NodeShape]]. - * - * @param node the node to set - * @param ev evidence that [[NodeShape]] belongs to an indexed variant - * @param graph the graph to mutate - * @tparam NodeShape the shape to set the node to - */ - def setShape[NodeShape <: Node.Shape]( - node: Node[CoreGraph] - )(implicit - ev: VariantIndexed[Node.Shape, NodeShape], - graph: PrimGraph.GraphData[CoreGraph] - ): Unit = { - graph.unsafeSetVariantCase[Nodes, Node.Shape, NodeShape](node) - } - - /** Checks whether a given node represents some kind of language error. - * - * @param node the node to check - * @return `true` if [[node]] represents an errors `false` otherwise - */ - def isErrorNode( - node: Node[CoreGraph] - )(implicit graph: PrimGraph.GraphData[CoreGraph]): Boolean = { - node match { - case Shape.SyntaxError.any(_) => true - case Shape.ConstructionError.any(_) => true - case _ => false - } - } - - /** Checks whether a given node represents syntactic sugar. - * - * @param node the node to check - * @return `true` if [[node]] represents syntax sugar, `false` otherwise - */ - def shapeIsSugar( - node: Node[CoreGraph] - )(implicit graph: PrimGraph.GraphData[CoreGraph]): Boolean = { - node match { - case Shape.TypeDef.any(_) => true - case Shape.FunctionDef.any(_) => true - case Shape.InfixApplication.any(_) => true - case Shape.LeftSection.any(_) => true - case Shape.RightSection.any(_) => true - case Shape.CentreSection.any(_) => true - case Shape.ForcedTerm.any(_) => true - case _ => false - } - } - - /** Checks whether a given node represents primitive language constructs. - * - * @param node the node to check - * @return `true` if [[Node]] has a primitive shape, `false` otherwise - */ - def shapeIsPrimitive( - node: Node[CoreGraph] - )(implicit graph: PrimGraph.GraphData[CoreGraph]): Boolean = { - !shapeIsSugar(node) - } - } - - // ======================================================================== - // === Link =============================================================== - // ======================================================================== - - /** A link between nodes in the [[CoreGraph]]. */ - @component case class Links() { type Link[G <: PrimGraph] } - - /** The list of fields that a [[Link]] has in a [[CoreGraph]]. */ - implicit def linkFields = - new PrimGraph.Component.Field.List[CoreGraph, Links] { - type Out = Link.Shape :: HNil - } - - object Link { - - // ====================================================================== - // === Field Definitions ================================================ - // ====================================================================== - - /** The shape of a link is static and represents a standard directional - * edge in a graph. - * - * @param source the node at the start of the link - * @param target the node at the end of the link - * @tparam G the graph type - */ - @field case class Shape[G <: PrimGraph](source: Node[G], target: Node[G]) - } - } -} From 09fd6af688f019d12d3fd25de00671ccdcc0b0fe Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Tue, 7 Jun 2022 11:48:38 +0200 Subject: [PATCH 4/4] Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e923c9ccb7c..faf4c9ea3d34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -230,6 +230,7 @@ builtins from method signatures][3454] - [Avoid needless concatenations of warning/error messages][3465] - [Lazy evaluation of RHS argument for || and &&][3492] +- [Drop Core implementation of IR][3512] [3227]: https://github.com/enso-org/enso/pull/3227 [3248]: https://github.com/enso-org/enso/pull/3248 @@ -255,6 +256,7 @@ [3492]: https://github.com/enso-org/enso/pull/3492 [3493]: https://github.com/enso-org/enso/pull/3493 [3505]: https://github.com/enso-org/enso/pull/3505 +[3512]: https://github.com/enso-org/enso/pull/3512 # Enso 2.0.0-alpha.18 (2021-10-12)