Simplistic type hierarchy for ASTs

nicksrules
Oliver Kennedy 2023-07-13 13:18:35 -04:00
parent 7bc91c8402
commit f1a5fa4cc8
Signed by: okennedy
GPG Key ID: 3E5F9B3ABD3FDB60
5 changed files with 85 additions and 28 deletions

View File

@ -0,0 +1,15 @@
package com.astraldb.spec
case class ASTDefinition(
family: Type.AST,
nodes: Set[Node]
)
{
val subtypes:Map[Type.ASTSubtype, Set[Node]] =
nodes.flatMap { node =>
node.supertypes.map { st =>
st -> node
}
}
.groupMap { _._1 } { _._2 }
}

View File

@ -4,10 +4,14 @@ import scala.collection.mutable
import com.astraldb.expression._
case class Definition(
nodes:Map[String, Seq[Node]],
asts: Map[String, ASTDefinition],
rules:Seq[Rule],
globals: Map[String, Type],
) {
def nodes =
asts.mapValues { _.nodes }
override def toString =
s"""/////// ASTs //////
|${nodes.map { case (family, nodeTypes) => s"Ast(${family})(\n ${nodeTypes.mkString(",\n ")}\n)" }.mkString("\n\n")}
@ -15,6 +19,7 @@ case class Definition(
|/////// Rules /////
|${rules.mkString("\n\n")}
""".stripMargin
val familyOfNode: Map[String, String] =
nodes.flatMap { case (family, elements) => elements.map { _.name -> family } }
.toMap
@ -32,7 +37,12 @@ class HardcodedDefinition
{
lazy val definition: Definition =
Definition(
nodes = nodes.mapValues { _.toSeq }.toMap,
asts = nodes.map { case (f, n) =>
val family = Type.AST(f)
f -> ASTDefinition(
family = family,
nodes = n.map { _.copy(family = family) }.toSet
)}.toMap,
rules = rules.toSeq,
globals = globals.toMap
)
@ -43,13 +53,12 @@ class HardcodedDefinition
import FieldConversions._
def Ast(label: String)(newNodes: Node*): Unit =
def Ast(label: String)(newNodes: => Node*): Unit =
nodes.getOrElseUpdate(label, mutable.Buffer.empty)
.appendAll(newNodes)
def Node(label: String)(fields: (String, Type)*): Node =
com.astraldb.spec.Node(label, fields)
com.astraldb.spec.Node(label, fields, supertypes = Set.empty, family = null)
def Rule(label: String, family: String)(pattern: Match)(replacement: Expression): Unit =
rules.append(

View File

@ -1,6 +1,11 @@
package com.astraldb.spec;
case class Node(val name:String, val fields:Seq[Field])
case class Node(
val name: String,
val fields: Seq[Field],
val family: Type.AST,
val supertypes: Set[Type.ASTSubtype]
)
{
def renderName = name+"Node"
def enumName = "JITD_NODE_"+name
@ -9,4 +14,9 @@ case class Node(val name:String, val fields:Seq[Field])
override def toString =
name + "(" + fields.map { _.toString }.mkString(", ") + ")"
def withSupertypes(supertypes: String*): Node =
copy(supertypes = this.supertypes ++ supertypes.map { Type.ASTSubtype(_) })
def allSupertypes: Set[Type.ASTType] = supertypes ++ Set(family)
}

View File

@ -19,12 +19,20 @@ object Type
override def toString: String = s"Native[${name}]"
def scalaType: String = name
}
case class AST(family: String) extends Type
sealed trait ASTType extends Type
case class AST(family: String) extends ASTType
{
override def toString: String = s"Ast[${family}]"
def scalaType: String = family
}
case class Node(nodeType: String) extends Type
case class ASTSubtype(typeName: String) extends ASTType
{
override def toString: String = s"ASTSubtype[${typeName}]"
def scalaType: String = typeName
}
case class Node(nodeType: String) extends ASTType
{
override def toString: String = s"Node[${nodeType}]"
def scalaType: String = nodeType

View File

@ -12,10 +12,8 @@ object Typecheck
{
(source, target) match {
case (a, b) if a == b => true
case (Type.Node(label), Type.AST(family)) =>
schema.nodes.get(family)
.map { _.exists { _.name == label } }
.getOrElse { false }
case (Type.Node(label), o:Type.ASTType) =>
schema.nodesByName(label).allSupertypes contains o
case (Type.Union(elems), a) =>
elems.forall { escalatesTo(_, a, schema) }
case (a, Type.Union(elems)) =>
@ -30,14 +28,16 @@ object Typecheck
{
if(a == b){ return a }
(a, b) match {
case (Type.Node(label), Type.AST(family)) if
schema.nodes.get(family)
.map { _.exists { _.name == label } }
.getOrElse { false } => a
case (Type.AST(family), Type.Node(label)) if
schema.nodes.get(family)
.map { _.exists { _.name == label } }
.getOrElse { false } => b
case (n@Type.Node(label), o:Type.ASTType) if
schema.nodesByName(label)
.allSupertypes contains o => n
case (o:Type.ASTType, n@Type.Node(label)) if
schema.nodesByName(label)
.allSupertypes contains o => n
case (n:Type.ASTSubtype, a:Type.AST) if
schema.asts(a.family).subtypes contains n => n
case (a:Type.AST, n:Type.ASTSubtype) if
schema.asts(a.family).subtypes contains n => n
case (Type.Union(elems), _) if elems contains b => a
case (_, Type.Union(elems)) if elems contains a => b
case (_, Type.Any) => a
@ -53,14 +53,29 @@ object Typecheck
{
if(a == b){ return a }
(a, b) match {
case (Type.Node(label), Type.AST(family)) if
schema.nodes.get(family)
.map { _.exists { _.name == label } }
.getOrElse { false } => b
case (Type.AST(family), Type.Node(label)) if
schema.nodes.get(family)
.map { _.exists { _.name == label } }
.getOrElse { false } => a
case (n:Type.Node, o:Type.ASTType) if
schema.nodesByName(n.nodeType)
.allSupertypes contains o => o
case (o:Type.ASTType, n@Type.Node(label)) if
schema.nodesByName(label)
.allSupertypes contains o => o
case (n:Type.ASTSubtype, o:Type.AST) if
schema.asts(o.family).subtypes contains n => o
case (o:Type.AST, n:Type.ASTSubtype) if
schema.asts(o.family).subtypes contains n => o
case (a:Type.Node, b:Type.Node) =>
val sharedSuperTypes =
schema.nodesByName(a.nodeType).allSupertypes &
schema.nodesByName(b.nodeType).allSupertypes
if(sharedSuperTypes.isEmpty){
assert(false, s"Node types $a and $b have nothing in common")
} else {
sharedSuperTypes.find { _.isInstanceOf[Type.ASTSubtype] }
.orElse { sharedSuperTypes.find { _.isInstanceOf[Type.AST] }}
.getOrElse {
assert(false, "A node can't inherit from another node")
}
}
case (Type.Union(elems), _) if elems contains b => a
case (_, Type.Union(elems)) if elems contains a => b
case (_, Type.Any) => Type.Any