pass typed data back and forth with #extern. close #17

This commit is contained in:
2021-07-26 19:55:28 -06:00
parent 0586a1dc4f
commit 9914bf5a27
4 changed files with 67 additions and 26 deletions

View File

@@ -466,19 +466,37 @@ class Helpers {
// Return convenient functions for succinctly making new ReaderExps that link back to an original exp's
// position in source code
public static function expBuilder(posRef:ReaderExp) {
function _symbol(?name:String) {
return Prelude.symbol(name).withPosOf(posRef);
}
function call(func:ReaderExp, args:Array<ReaderExp>) {
return CallExp(func, args).withPosOf(posRef);
}
function callSymbol(symbol:String, args:Array<ReaderExp>) {
return call(_symbol(symbol), args);
}
function field(f:String, exp:ReaderExp) {
return FieldExp(f, exp).withPosOf(posRef);
}
function list(exps:Array<ReaderExp>) {
return ListExp(exps).withPosOf(posRef);
}
return {
call: (func:ReaderExp, args:Array<ReaderExp>) -> CallExp(func, args).withPosOf(posRef),
callSymbol: (symbol:String, args:Array<ReaderExp>) -> CallExp(Symbol(symbol).withPosOf(posRef), args).withPosOf(posRef),
call: call,
callSymbol: callSymbol,
callField: (fieldName:String, callOn:ReaderExp, args:Array<ReaderExp>) -> call(field(fieldName, callOn), args),
print: (arg:ReaderExp) -> CallExp(Symbol("print").withPosOf(posRef), [arg]).withPosOf(posRef),
list: (exps:Array<ReaderExp>) -> ListExp(exps).withPosOf(posRef),
the: (type:ReaderExp, value:ReaderExp) -> callSymbol("the", [type, value]),
list: list,
str: (s:String) -> StrExp(s).withPosOf(posRef),
symbol: (?name:String) -> Prelude.symbol(name).withPosOf(posRef),
symbol: _symbol,
raw: (code:String) -> RawHaxe(code).withPosOf(posRef),
typed: (path:String, exp:ReaderExp) -> TypedExp(path, exp).withPosOf(posRef),
meta: (m:String, exp:ReaderExp) -> MetaExp(m, exp).withPosOf(posRef),
field: (f:String, exp:ReaderExp) -> FieldExp(f, exp).withPosOf(posRef),
field: field,
keyValue: (key:ReaderExp, value:ReaderExp) -> KeyValueExp(key, value).withPosOf(posRef),
begin: (exps:Array<ReaderExp>) -> CallExp(Symbol("begin").withPosOf(posRef), exps).withPosOf(posRef),
begin: (exps:Array<ReaderExp>) -> callSymbol("begin", exps),
let: (bindings:Array<ReaderExp>, body:Array<ReaderExp>) -> callSymbol("let", [list(bindings)].concat(body)),
none: () -> None.withPosOf(posRef)
};
}

View File

@@ -809,25 +809,49 @@ class Macros {
{};
}
trace(compileArgs);
trace(bindingListExp);
// TODO generate tink_json writers and parsers for this
var b = wholeExp.expBuilder();
// TODO generate tink_json writers and parsers for this
var bindingList = bindingListExp.bindingList("#extern", true);
var idx = 0;
var stringifyExpList = [];
var parseBindingList = [];
while (idx < bindingList.length) {
var type = "";
var untypedName = switch (bindingList[idx].def) {
case TypedExp(_type, symbol = {pos: _, def: Symbol(name)}):
type = _type;
symbol;
default: throw CompileError.fromExp(bindingList[idx], "name in #extern binding list must be a typed symbol");
};
switch (bindingList[idx + 1].def) {
// _ in the value position of the #extern binding list will reuse the name as the value
case Symbol("_"):
bindingList[idx + 1] = untypedName;
default:
}
stringifyExpList.push(b.callSymbol("tink.Json.stringify", [b.the(b.symbol(type), bindingList[idx + 1])]));
parseBindingList.push(bindingList[idx]);
parseBindingList.push(b.callSymbol("tink.Json.parse", [b.callField("readLine", b.callSymbol("Sys.stdin", []), [])]));
idx += 2;
}
var externExps = [
b.print(
b.callSymbol("tink.Json.stringify", [
b.callSymbol("the", [
bodyType, b.begin(exps)
])
b.the(bodyType, if (bindingList.length > 0) {
b.let(parseBindingList, exps);
} else {
b.begin(exps);
})
]))
];
b.callSymbol("the", [
b.the(
bodyType,
b.callSymbol("tink.Json.parse", [
b.call(b.raw(CompilerTools.compileToScript(externExps, langArg, compileArgs).toString()), [])
])
]);
b.call(b.raw(CompilerTools.compileToScript(externExps, langArg, compileArgs).toString()), [b.list(stringifyExpList)])
]));
};
return macros;

View File

@@ -7,6 +7,7 @@ import kiss.Prelude;
@:build(kiss.Kiss.build())
class ExternTestCase extends Test {
#if (sys || hxnodejs)
function testExternPython() {
_testExternPython();
}
@@ -14,4 +15,5 @@ class ExternTestCase extends Test {
function testExternJavaScript() {
_testExternJavaScript();
}
#end
}

View File

@@ -1,13 +1,10 @@
(function _testExternPython []
(Assert.isTrue
(#extern Bool python []
(#if python
true
false))))
(#extern Bool python [:String passingString "Hello python!"]
(python.NativeStringTools.startswith passingString "Hello"))))
(function _testExternJavaScript []
(Assert.isTrue
(#extern Bool js []
(#if js
true
false))))
(Assert.equals 18
(let [jsToEval "5+6+7"]
(#extern Int js [:String jsToEval _]
(js.Lib.eval jsToEval)))))