Last active
August 16, 2021 20:09
-
-
Save carson-katri/5436b1be407f13e8ca67a5d26a162c6b to your computer and use it in GitHub Desktop.
Wrapper types experiment in Wren
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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