Consider this in D programming language:
import luad.all
class C1
{
auto l1 = new LuaState;
l1["somebool"] = true;
this()
~this()
}
class C2
{
C1 cc = new C1;
auto l2 = new LuaState;
// here I want to inject l1["somebool"] to l2
}
void main() { C2 cx = new C2; }
As a solution, it is possible that I make a local variable
bool var = cc.l1["somebool"]
and then insert it in l2 - but this does not seem to be the best solution.
Is there any way to copy one lua stack defined inside a class to another stack in another class?
I don't know much about LuaD or Lua, but you can extract globals into a struct as shown in the last example on this page. And then you can set the values from the struct into l2 state.
// warning: untested
struct State
{
bool somebool;
}
State state;
l1.globals.toStruct!State(state);
foreach (member; __traits(allMembers, State))
{
l2.globals.set(member, __traits(getMember, state, member));
}
Related
I am trying to write some externs to some Lua libraries that require to pass dictionary tables and I want to make them type safe.
So far, I have been declaring abstract classes with public inline constructors, but this gets tedious really fast:
abstract JobOpts(Table<String, Dynamic>) {
public inline function new(command:String, args:Array<String>) {
this = Table.create(null, {
command: command,
arguments: Table.create(args)
});
}
}
Is there a better way that allows me to keep things properly typed but that does not require that much boilerplate?
Please note that typedefs and anonymous structures are not valid options, because they introduce nasty fields in the created table and also do a function execution to assign a metatable to them:
--typedef X = {cmd: String}
_hx_o({__fields__={cmd=true},cmd="Yo"})
My abstract code example compiles to a clean lua table, but it is a lot of boilerplate
Some targets support #:nativeGen to strip Haxe-specific metadata from objects, but this does not seem to be the case for typedefs on Lua target. Fortunately, Haxe has a robust macro system so you can make the code write itself. Say,
Test.hx:
import lua.Table;
class Test {
public static function main() {
var q = new JobOpts("cmd", ["a", "b"]);
Sys.println(q);
}
}
#:build(TableBuilder.build())
abstract JobOpts(Table<String, Dynamic>) {
extern public inline function new(command:String, args:Array<String>) this = throw "no macro!";
}
TableBuilder.hx:
import haxe.macro.Context;
import haxe.macro.Expr;
class TableBuilder {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields) {
if (field.name != "_new") continue; // look for new()
var f = switch (field.kind) { // ... that's a function
case FFun(_f): _f;
default: continue;
}
// abstract "constructors" transform `this = val;`
// into `{ var this; this = val; return this; }`
var val = switch (f.expr.expr) {
case EBlock([_decl, macro this = $x, _ret]): x;
default: continue;
}
//
var objFields:Array<ObjectField> = [];
for (arg in f.args) {
var expr = macro $i{arg.name};
if (arg.type.match(TPath({ name: "Array", pack: [] } ))) {
// if the argument's an array, make an unwrapper for it
expr = macro lua.Table.create($expr, null);
}
objFields.push({ field: arg.name, expr: expr });
}
var objExpr:Expr = { expr: EObjectDecl(objFields), pos: Context.currentPos() };
val.expr = (macro lua.Table.create(null, $objExpr)).expr;
}
return fields;
}
}
And thus...
Test.main = function()
local this1 = ({command = "cmd", args = ({"a","b"})});
local q = this1;
_G.print(Std.string(q));
end
Do note, however, that Table.create is a bit of a risky function - you will only be able to pass in array literals, not variables containing arrays. This can be remedied by making a separate "constructor" function with the same logic but without array➜Table.create unwrapping.
While visiting a compilation unit--- and given a certain condition- I would like to apply a transformation (using the => operator) and count the number of times the same transformation was applied for a given compilation unit.
I was able to perform that using a kind of "global module variable", but I am quite sure that it is possible to combine both replacements and actions within a single visit expression. Is that possible?
module MultiCatch
import lang::java::\syntax::Java18;
import ParseTree;
import IO;
import Map;
import Type;
import List;
// sure, I don't like global variables.
//
// However I could not find a way to perform both
// a replacement and count the number of times
// it was applied in the same compilation unit.
int numberOfOccurences = 0;
/**
* Refactor a try-catch statement to use the
* MultiCatch construct of Java 7.
*/
public tuple[int, CompilationUnit] refactorMultiCatch(CompilationUnit unit) {
numberOfOccurences = 0;
CompilationUnit cu = visit(unit) {
case (TryStatement)`try <Block b1> <Catches c1>` => (TryStatement)`try <Block b1> <Catches mc>`
when mc := computeMultiCatches(c1)
};
return <numberOfOccurences, cu>;
}
/*
* Based on a simple notion of similarity,
* this function calculates the possible
* occurences of MultiCatch.
*/
private Catches computeMultiCatches(cs){
map [Block, tuple[list[CatchType], VariableDeclaratorId, Block] ] mCatches =();
visit(cs){
case(CatchClause)`catch (<CatchType t> <VariableDeclaratorId vId>) <Block b>` :{
if (b in mCatches){
<ts, vId, blk> = mCatches[b];
ts += t;
mCatches[b] = <ts, vId, blk>;
numberOfOccurences += 1;
}
else{
mCatches[b] = <[t], vId, b>;
}
}
}
return generateMultiCatches([mCatches[b] | b <- mCatches]);
}
/*
* Creates a syntactic catch clause (either a simple one or
* a multicatch).
*
* This is a recursive definition. The base case expects only
* one tuple, and than it returns a single catch clause. In the
* recursive definition, at least two tuples must be passed as
* arguments, and thus it returns at least two catches clauses
* (actually, one catch clause for each element in the list)
*/
private Catches generateMultiCatches([<ts, vId, b>]) = {
types = parse(#CatchType, intercalate("| ", ts));
return (Catches)`catch(<CatchType types> <VariableDeclaratorId vId>) <Block b>`;
};
private Catches generateMultiCatches([<ts, vId, b>, C*]) = {
catches = generateMultiCatches(C);
types = parse(#CatchType, intercalate("| ", ts));
return (Catches)`catch(<CatchType types> <VariableDeclaratorId vId>) <Block b> <CatchClause+ catches>`;
};
One way to do it is using a local variable and a block with an insert:
module MultiCatch
import lang::java::\syntax::Java18;
import ParseTree;
import IO;
import Map;
import Type;
import List;
/**
* Refactor a try-catch statement to use the
* MultiCatch construct of Java 7.
*/
public tuple[int, CompilationUnit] refactorMultiCatch(CompilationUnit unit) {
int numberOfOccurences = 0; /* the type is superfluous */
CompilationUnit cu = visit(unit) {
case (TryStatement)`try <Block b1> <Catches c1>` : {
numberOfOccurences += 1;
mc = computeMultiCatches(c1)
insert (TryStatement)`try <Block b1> <Catches mc>`;
}
};
return <numberOfOccurences, cu>;
}
The {...} block allows multiple statements to be executed after the match;
The local variable is now only present in the frame of refactorMultiCatch;
The insert statement has the same effect as the previous => arrow did;
Since the match := always succeeds, I changed the when clause into a simple assigment
There is also other more complex ways to share state in Rascal, but I personally prefer to have state not escape the lexical scope of a function.
Edited as the original post was impossible to understand...sorry guys.
Why did I want to use expando/weakmap?
I had a custom layout/sizer element that resizes children. By using expando, I wanted to control that resizing behavior without creating a strong reference.
e.g.
var l1 = new Layout();
var e1 = new DivElement();
e1.text = 'The size of this element will remain as is';
//setting property prior to appending to avoid resizing
l1.add_resizable_attribute(e1,false);
l1.append(e1);
print(l1.isFrozen(e1));//returns true
I found a better solution, but I want to know how to map an object with data in Dart and share it across multiple objects safely and dynamically manage that.
Why did I want to share a expando property?
My Layout element may contain another layout element and form a tree. Allowing access to the expando property of an object anywhere in the tree seems a rational thing to do.
e.g.
var l1 = new Layout();
var l2 = new Layout();
var e1 = new DivElement();
e1.text = 'The size of this element will remain as is';
l1.add_resizable_attribute(e1,false);
print(l1.isFrozen(e1));//returns true
print(l2.isFrozen(e1));//returns false as l2 is not part of the tree
l1.append(l2)//forming a tree
print(l1.isFrozen(e1));//returns true
print(l2.isFrozen(e1));// returns true on l2 as well
l2.add_resizable_attribute(e1,true);
print(l1.isFrozen(e1));//changed on l2 but returns false on l1 as well
What is the problem?
Cannot merge or split expando instances.
Potential solutions
Give up on expando property/weakmap (works only on a dom element)
new HtmlElement()..dataset['allow_layout_resize_this']='false';
Did not think of this, but the simplest.
Reflection
Obvious but currently needs 'dart:mirror' to make this work with any class instances.
Traversing the tree
Complex and ugly.
class Layout extends HtmlElement{
Expando<bool> _freeze_resizing = new Expando<bool>();
Layout.created():super.created();
void add_resizable_attribute(HtmlElement e, bool isResizable) {
_freeze_resizing[e] = !isResizable;
}
isFrozen(HtmlElement e,
{bool search_down: true,
bool search_up: true
}) {
///resize allowed by default
bool v;
if (search_up) {
Layout t = _get_topmost_layout();
return t.isFrozen(
e, search_down: true,
search_up: false);
} else if (search_down) {
v = _freeze_resizing[e];
v = v == null ? false : v;
if (v) return true;
return isFrozen_in_children(e);
}
return _freeze_resizing[e];
}
bool isFrozen_in_children(e) {
for (var c in children) {
if (c is! Layout) continue;
if (c.isFrozen(
e,
search_up: false,
search_down: true
)) return true;
}
return false;
}
Layout _get_topmost_layout() {
Layout tm;
var e = this;
while (e is Layout) {
tm = e;
e = e.parent;
}
return tm;
}
void _enforce_owner_exclusive_expando(element,[bool search_up=true]){
///remove expando properties from non-owner
if(!children.contains(element)){
_freeze_resizing[element]=null;
}
void enforce_on_children(){
for(var c in children){
if(c is! Layout) continue;
c._enforce_owner_exclusive_expando(element,false);
}
}
if(search_up){
var tm = _get_topmost_layout();
tm._enforce_owner_exclusive_expando(element,false);
}else{
enforce_on_children();
}
}
append(e){
super.append(e);
_enforce_owner_exclusive_expando(element);
}
}
Generally the problem can be circumvented and Dart is still easier than javascript. This is, however, the first ever time I have found Dart frustrating.
How would you solve an issue like this?
Weakmap like structure with keys method
Yay, I've finally solved this!!!!
https://github.com/TastyCatFood/mistletoe
Has keys method
import 'package:mistletoe/mistletoe.dart';
void main(){
var m = new Mistletoe();
var t = new DateTime.now();
m.add( t, 'hi', 'bye');
print(m.keys(t));//prints 'hi'
print(m.value(t,'hi'));//prints bye;
t = null;
//With t garbage collected, m is empty now
}
Support for pseudo dynamic addition of properties
import 'package:mistletoe/mistletoe.dart';
Dynamism d = new Dynamism(expert:true);
void main(){
var o = new Object();
d.on(o).set('greetings',()=>print('hello world'));
d.on(o).invoke('greetings');//prints hello world
o = null;
//With o garbage collected, d is empty now.
}
I requested the feature here: https://github.com/dart-lang/sdk/issues/25781
published: https://pub.dartlang.org/packages/mistletoe
Note: I initially posted an over-simplified version of my problem. A more
accurate description follows:
I have the following struct:
struct Thing(T) {
T[3] values;
int opApply(scope int delegate(size_t, ref T) dg) {
int res = 0;
foreach(idx, ref val; values) {
res = dg(idx, val);
if (res) break;
}
return res;
}
}
Foreach can be used like so:
unittest {
Thing!(size_t[]) thing;
foreach(i, ref val ; thing) val ~= i;
}
However, it is not #nogc friendly:
#nogc unittest {
Thing!size_t thing;
foreach(i, ref val ; thing) val = i;
}
If I change the signature to
int opApply(scope int delegate(size_t, ref T) #nogc dg) { ... }
It works for the #nogc case, but fails to compile for non-#nogc cases.
The solutions I have tried are:
Cast the delegate
int opApply(scope int delegate(size_t, ref T) dg) {
auto callme = cast(int delegate(size_t, ref T) #nogc) dg;
// use callme instead of dg to support nogc
This seems wrong as I am willfully casting a #nogc attribute even onto
functions that do may not support it.
Use opSlice instead of opApply:
I'm not sure how to return an (index, ref value) tuple from my range. Even if
I could, I think it would have to contain a pointer to my static array, which
could have a shorter lifetime than the returned range.
Use a templated opApply:
All attempts to work with this have failed to automatically determine the
foreach argument types. For example, I needed to specify:
foreach(size_t idx, ref int value ; thing)
Which I see as a significant hindrance to the API.
Sorry for underspecifying my problem before. For total transparency,
Enumap is the "real-world" example. It
currently uses opSlice, which does not support ref access to values. My
attempts to support 'foreach with ref' while maintaining #nogc support is what
prompted this question.
Instead of overloading the opApplyoperator you can implement an input range for your type. Input ranges work automatically as the agregate argument in foreach statements:
struct Thing(K,V) {
import std.typecons;
#nogc bool empty(){return true;}
#nogc auto front(){return tuple(K.init, V.init);}
#nogc void popFront(){}
}
unittest {
Thing!(int, int) w;
foreach(val ; w) {
int[] i = [1,2,3]; // spurious allocation
}
}
#nogc unittest {
Thing!(int, int) w;
foreach(idx, val ; w) { assert(idx == val); }
}
This solves the problem caused by the allocation of the delegate used in foreach.
Note that the example is shitty (the range doesn't work at all, and usually ranges are provided via opSlice, etc) but you should get the idea.
Does Dart support the concept of variable functions/methods? So to call a method by its name stored in a variable.
For example in PHP this can be done not only for methods:
// With functions...
function foo()
{
echo 'Running foo...';
}
$function = 'foo';
$function();
// With classes...
public static function factory($view)
{
$class = 'View_' . ucfirst($view);
return new $class();
}
I did not found it in the language tour or API. Are others ways to do something like this?
To store the name of a function in variable and call it later you will have to wait until reflection arrives in Dart (or get creative with noSuchMethod). You can however store functions directly in variables like in JavaScript
main() {
var f = (String s) => print(s);
f("hello world");
}
and even inline them, which come in handy if you are doing recusion:
main() {
g(int i) {
if(i > 0) {
print("$i is larger than zero");
g(i-1);
} else {
print("zero or negative");
}
}
g(10);
}
The functions stored can then be passed around to other functions
main() {
var function;
function = (String s) => print(s);
doWork(function);
}
doWork(f(String s)) {
f("hello world");
}
I may not be the best explainer but you may consider this example to have a wider scope of the assigning functions to a variable and also using a closure function as a parameter of a function.
void main() {
// a closure function assigned to a variable.
var fun = (int) => (int * 2);
// a variable which is assigned with the function which is written below
var newFuncResult = newFunc(9, fun);
print(x); // Output: 27
}
//Below is a function with two parameter (1st one as int) (2nd as a closure function)
int newFunc(int a, fun) {
int x = a;
int y = fun(x);
return x + y;
}