1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
use core:lang;
use lang:bs;
use lang:bs:macro;
use layout;
class PictureBlock on Compiler {
// Root block.
private ExprBlock root;
// Sub-block, so that we can put the return statement last.
ExprBlock sub;
// Variable for accessing the picture object being created.
LocalVarAccess me;
// Counter for generating unique identifiers.
private Nat unique;
// Create.
init(SrcPos pos, Block parent) {
ExprBlock root(pos, parent);
ExprBlock sub(pos, root);
Var me(root, SStr("picture"), namedExpr(root, name{presentation:Picture}, Actuals()));
root.add(me);
root.add(sub);
root.add(LocalVarAccess(pos, me.var));
init() {
root = root;
sub = sub;
me = LocalVarAccess(pos, me.var);
}
}
// Generate a variable name.
Str uniqueName() { "@ node${unique++}"; }
// Get the block.
ExprBlock block() { root; }
// Add an expression.
void add(Expr expr) {
sub.add(expr);
}
}
class PictureElem on Compiler {
// The block we insert things into.
private ExprBlock into;
// The variable we created in the parent block.
LocalVarAccess me;
// Create.
init(SStr var, SrcName create, Actuals params, PictureBlock parent) {
ExprBlock into(create.pos, parent.sub);
Expr created = namedExpr(parent.sub, create, params);
Var v(parent.sub, var, created);
parent.add(v);
parent.add(into);
init() {
into = into;
me(create.pos, v.var);
}
parent.add(namedExpr(parent.sub, SStr("add"), parent.me, Actuals(me)));
}
// Set a property.
void set(SStr name, Actuals? params) {
Actuals p = if (params) { params; } else { Actuals(); };
if (e = findProperty(name, p)) {
into.add(e);
} else {
throw SyntaxError(name.pos, "No suitable property '${name.v}' found for ${me.result} (parameters: ${p})");
}
}
// Generate a call for the property if it exists.
private Expr? findProperty(SStr name, Actuals params) {
Expr e = namedExpr(into, name, me, params);
unless (e as UnresolvedName) {
return e;
}
// If more than one parameter, we can't do assignment.
if (params.expressions.count != 1) {
return null;
}
// TODO: Consider calling the constructor of whatever type 'l' is, if we found something.
Expr l = namedExpr(into, name, me, Actuals());
if (l as UnresolvedName) {
return null;
}
AssignOpInfo assign(SStr("=", name.pos), 10, true);
return assign.meaning(into, l, params.expressions[0]);
}
// Get the block.
ExprBlock block() { into; }
}
PictureElem pictureElem(SrcPos pos, SrcName create, Actuals params, PictureBlock parent) {
PictureElem(SStr(parent.uniqueName, pos), create, params, parent);
}
// Create a layout block from a picture block.
package LayoutBlock asLayoutBlock(LayoutRoot parent, PictureBlock p) on Compiler {
var pBlock = p.block;
ExprBlock wrap(pBlock.pos, parent.block);
Var v(wrap, SStr("@ picture"), namedExpr(pBlock, SStr("component"), Actuals(pBlock)));
wrap.add(v);
LayoutBlock(wrap, pBlock, LocalVarAccess(pBlock.pos, v.var));
}
// Special case for 'of' syntax.
void place(PictureElem to, SrcName dir, Expr distance, Expr origin) {
Actuals a;
a.add(namedExpr(to.block, dir, Actuals()));
a.add(distance);
a.add(origin);
to.set(SStr("place", dir.pos), a);
}
// Special case for animation syntax.
void set(PictureElem to, AniDecl ani) {
ani.finalize();
to.set(SStr("animation", ani.block.pos), Actuals(ani.block));
}
|