Skip to content

Instantly share code, notes, and snippets.

@ExFed
Last active January 11, 2021 20:45
Show Gist options
  • Save ExFed/ee4f589cd43c3d7bcc952b88c12b7b46 to your computer and use it in GitHub Desktop.
Save ExFed/ee4f589cd43c3d7bcc952b88c12b7b46 to your computer and use it in GitHub Desktop.
gStruct Binding PoC
import groovy.transform.Canonical
import groovy.transform.CompileStatic
interface Type {}
@CompileStatic
@Canonical
class Ref implements Type {
String name
Type type
String toString() { name }
}
@CompileStatic
@Canonical
class Extern implements Type {
String name
}
@CompileStatic
@Canonical
class Tuple implements Type {
List<Type> types = []
String toString() { "Tuple(${types.join(', ')})" }
}
@CompileStatic
@Canonical
class Struct implements Type {
Map<String, Type> fields = [:]
String toString() { "Struct(${fields.collect { k, v -> "$k:$v" }.join(', ')})" }
}
class Compiler {
@CompileStatic
static Closure<?> binder(Map<String, Type> bindings) {
return { Map<String, Type> mapping ->
def dupes = mapping.keySet().intersect(bindings.keySet())
if (dupes) {
throw new RuntimeException("duplicate names: $dupes")
}
println "## binding $mapping"
bindings << mapping
}
}
static Map<String, Type> compile(Closure code) {
def model = new TreeMap<String, Type>().withDefault { String name ->
{ -> throw new RuntimeException("name not found in model: $name") }.call()
}
def getRefs = { -> model.collectEntries { k, v -> [k, new Ref(k, v)] } }
def tasks = [] as Queue<Closure> // breadth first syntax traversal
def addTask = { Closure task -> tasks.offer(task) }
def nextTask = { -> tasks.poll() }
def scope = new Expando().tap {
bind = binder(model)
extern = { String name -> new Extern(name) }
tuple = { Closure cl ->
println '# initializing tuple'
def tuple = new Tuple()
addTask {
println '# constructing tuple'
(getRefs() as Expando).tap {
types = { Type... types ->
println "## adding types: $types"
tuple.types.addAll(types)
}
}.with cl // apply cl in context of tuple scope
}
return tuple
}
struct = { Closure cl ->
println '# initializing struct'
def struct = new Struct()
addTask {
println '# constructing struct'
(getRefs() as Expando).tap {
field = binder(struct.fields)
}.with cl // apply cl in context of struct scope
}
return struct
}
}
addTask { scope.with code } // get the traversal started
while (tasks) {
nextTask().call() // traverse each syntax node
}
return model
}
}
Compiler.compile {
bind LatLon: struct {
field latitude: DecimalDeg
field longitude: DegMinSec
}
bind GeoVolume: struct {
field northEast: LatLon
field southWest: LatLon
field height: Real
}
bind DegMinSec: tuple { types Int, Int, Real }
bind DecimalDeg: tuple { types extern('double') }
bind Int: extern('int')
bind Real: extern('float')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment