From 9914bf5a27a311c598a90371f175faf89f574479 Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Mon, 26 Jul 2021 19:55:28 -0600 Subject: [PATCH] pass typed data back and forth with #extern. close #17 --- src/kiss/Helpers.hx | 30 +++++++++++++++---- src/kiss/Macros.hx | 46 +++++++++++++++++++++++------- src/test/cases/ExternTestCase.hx | 2 ++ src/test/cases/ExternTestCase.kiss | 15 ++++------ 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/kiss/Helpers.hx b/src/kiss/Helpers.hx index 54e5cbe..d831786 100644 --- a/src/kiss/Helpers.hx +++ b/src/kiss/Helpers.hx @@ -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) { + return CallExp(func, args).withPosOf(posRef); + } + function callSymbol(symbol:String, args:Array) { + return call(_symbol(symbol), args); + } + function field(f:String, exp:ReaderExp) { + return FieldExp(f, exp).withPosOf(posRef); + } + function list(exps:Array) { + return ListExp(exps).withPosOf(posRef); + } return { - call: (func:ReaderExp, args:Array) -> CallExp(func, args).withPosOf(posRef), - callSymbol: (symbol:String, args:Array) -> CallExp(Symbol(symbol).withPosOf(posRef), args).withPosOf(posRef), + call: call, + callSymbol: callSymbol, + callField: (fieldName:String, callOn:ReaderExp, args:Array) -> call(field(fieldName, callOn), args), print: (arg:ReaderExp) -> CallExp(Symbol("print").withPosOf(posRef), [arg]).withPosOf(posRef), - list: (exps:Array) -> 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) -> CallExp(Symbol("begin").withPosOf(posRef), exps).withPosOf(posRef), + begin: (exps:Array) -> callSymbol("begin", exps), + let: (bindings:Array, body:Array) -> callSymbol("let", [list(bindings)].concat(body)), none: () -> None.withPosOf(posRef) }; } diff --git a/src/kiss/Macros.hx b/src/kiss/Macros.hx index 2c30d10..f8c32be 100644 --- a/src/kiss/Macros.hx +++ b/src/kiss/Macros.hx @@ -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; diff --git a/src/test/cases/ExternTestCase.hx b/src/test/cases/ExternTestCase.hx index 17ce450..d77215e 100644 --- a/src/test/cases/ExternTestCase.hx +++ b/src/test/cases/ExternTestCase.hx @@ -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 } diff --git a/src/test/cases/ExternTestCase.kiss b/src/test/cases/ExternTestCase.kiss index 271e966..8478b90 100644 --- a/src/test/cases/ExternTestCase.kiss +++ b/src/test/cases/ExternTestCase.kiss @@ -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)))) \ No newline at end of file + (Assert.equals 18 + (let [jsToEval "5+6+7"] + (#extern Int js [:String jsToEval _] + (js.Lib.eval jsToEval))))) \ No newline at end of file