Skip to content

Instantly share code, notes, and snippets.

@carson-katri
Last active August 16, 2021 20:09
Show Gist options
  • Save carson-katri/5436b1be407f13e8ca67a5d26a162c6b to your computer and use it in GitHub Desktop.
Save carson-katri/5436b1be407f13e8ca67a5d26a162c6b to your computer and use it in GitHub Desktop.
Wrapper types experiment in Wren
import "mirror" for Mirror, ClassMirror, MethodMirror
import "meta" for Meta
class Wrapper {
static operators { ["-","!","~","*","/","+","..","...","<<",">>","&","^","|","<","<=",">",">=","is","==","!="] }
static generate(wrappedType, innerBody) {
var s = "class %(wrappedType)_ {\n"
s = s + " wrappedValue { _wrappedValue }\n"
s = s + " construct wrap(wrappedValue) {\n"
s = s + " _wrappedValue = wrappedValue\n"
s = s + " }\n"
for (method in ClassMirror.methodNames(wrappedType)) {
var signature = ""
var isInit = method.startsWith("init")
if (isInit) {
signature = "construct " + method.split("init ")[1]
} else {
signature = method
}
var isSubscript = signature.startsWith("[")
var startToken = isSubscript ? "[" : "("
var endToken = isSubscript ? "]" : ")"
signature = signature.split(startToken)[0]
var isOperator = Wrapper.operators.contains(signature)
if (method.contains(startToken)) {
var arity = method.split(startToken)[1].where {|c| c == "_" }.count
signature = signature + startToken
for (i in 0...arity) {
signature = signature + "a%(i)"
if (i < arity - 1) signature = signature + ","
}
if (isOperator) {
signature = signature + "%(endToken) { wrappedValue %(signature.split(startToken)[0]) %(startToken)%(signature.split(startToken)[1])%(endToken) }"
} else {
signature = signature + "%(endToken) { " + (isInit ? "_wrappedValue = %(wrappedType)" : "wrappedValue") + (isInit ? ".%(signature.split("construct ")[1])%(endToken) }" : ((isSubscript ? "" : ".") + "%(signature)%(endToken) }"))
}
} else {
if (isOperator) {
signature = signature + " { %(method)wrappedValue }"
} else {
signature = signature + " { wrappedValue.%(method) }"
}
}
s = s + " %(signature)\n"
}
s = s + innerBody + "\n"
s = s + "}\n"
s = s + "return %(wrappedType)_"
System.print(s)
return Meta.compile(s).call()
}
}
class Vec {
x { _x }
y { _y }
z { _z }
construct new(x, y, z) {
_x = x
_y = y
_z = z
}
translate(x, y, z) {
_x = _x + x
_y = _y + y
_z = _z + z
}
}
// Generate a wrapper for a class
var WrappedVec = Wrapper.generate(
Vec,
// extend it with more methods
"injected { x + y + z }"
)
// Use wrapped methods
System.print(WrappedVec.new(1, 2, 3).z)
// Use injected methods
System.print(WrappedVec.new(1, 2, 3).injected)
// Generate a wrapper for a core class
var WrappedString = Wrapper.generate(
String,
"static helloWorldConst { \"Hello, world!\" }"
)
// `wrap` constructor which wraps an unwrapped value.
System.print(WrappedString.wrap("Hello, world!").split("!"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment