Author: dda
Date: 2008-02-27 14:07:56 -0800 (Wed, 27 Feb 2008)
New Revision: 8118
Modified:
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
Log:
Change 20080222-dda-o by [EMAIL PROTECTED] on 2008-02-22 21:31:39 EST
in /Users/dda/laszlo/src/svn/openlaszlo/trunk-dep
for http://svn.openlaszlo.org/openlaszlo/trunk
Summary: Add support for new dependency mechanism in script compiler
New Features:
Bugs Fixed: LPP-5335 (partial)
Technical Reviewer: ptw (pending)
QA Reviewer: hminsky (pending)
Doc Reviewer: (pending)
Documentation:
Release Notes:
Details:
Introduces a new function Compiler.dependenciesForExpression() taking
a source expression e.g. "a.b.c + this.something.Fcn(1)" and
producing a source expression representing the dependency, e.g.
[a.b, "c"].concat(this.something.hasOwnProperty("$lsc$Fcn_dependencies")
? (this.something cast Object).$lsc$Fcn_dependencies(this, this.something, 1) :
[])
This change does not functionally change *anything*, but it provides
an API needed to switch over to having the tag compiler generate the
dependency functions.
The significant changes are in ReferenceCollector, which keeps two
implementations (old and new) for the moment. It doesn't make sense
to refactor them into a common codebase since the old implementation
will go away after new dependencies are fully integrated. The old
implementation
internal methods can be found in ReferenceCollector named as
*_using_subfunction
in reference to the original naming convention fcn() -> fcn.dependencies() .
The new implementation uses naming fcn() -> $lsc$fcn_dependencies() as
indicated in the example above.
The implementation is conscious of the naming convention, since there
may be calls to the dependency functions in the produced output.
There is also a fix to the ParseTreePrinter so that it knows how to print
'cast'. This wasn't needed before to print final output from JS1, since
casts were always removed. Casts are generated in the dependency source
so they will work with SWF9 - without it, the flex compile complains
about references to nonexistant dependency functions. Downcasting to
Object makes the compiler *less* strict and accepting of any function name.
The output from the simple dependency given above has been tested to
compile with flex2 as a proof of concept.
Also a small improvement to ReferenceGenerator to only create one
Compiler.Parser object.
This snippet added to NodeModel.java during testing (but not part of this
change)
shows how the new dependency function can be called:
if (when.equals(WHEN_ALWAYS)) {
System.out.println("CONSTRAINT: src = " +
canonicalValue.toString());
String dep = (new
org.openlaszlo.sc.Compiler()).dependenciesForExpression(canonicalValue.toString());
System.out.println("CONSTRAINT: dep = " + dep);
}
Tests:
regression: smokecheck,weather,lzpix (swf8/dhtml), runlzunit
Modified:
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
2008-02-27 20:53:04 UTC (rev 8117)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
2008-02-27 22:07:56 UTC (rev 8118)
@@ -380,6 +380,49 @@
}
}
+ /**
+ * @param source javascript source for a function (including function
keyword, etc.)
+ * @param name name, will get name_dependencies as name of function
+ */
+ public String dependenciesForExpression(String estr) {
+ String fname = "$lsc$dependencies";
+ String source = "function " + fname + " () {" +
+ "\n#pragma 'constraintFunction'\n" +
+ "\n#pragma 'withThis'\n" +
+ // Use this.setAttribute so that the compiler
+ // will recognize it for inlining.
+ "this.setAttribute(\"x\", " +
+ "\n#beginAttribute\n" + estr +
+ "\n#endAttribute\n)}";
+
+ return dependenciesForFunction(source);
+ }
+
+ /**
+ * @param source javascript source for a function
+ */
+ private String dependenciesForFunction(String source) {
+ SimpleNode node = new Parser().parse(source);
+ // Expect ASTProgram -> ASTModifiedDefinition -> ASTFunctionDeclaration
+ SimpleNode fcn = node.get(0).get(0);
+ if (!(fcn instanceof ASTFunctionDeclaration))
+ throw new CompilerError("Internal error: bad AST for constraints");
+
+ ReferenceCollector dependencies = new
ReferenceCollector(options.getBoolean(Compiler.COMPUTE_METAREFERENCES));
+
+ SimpleNode[] children = fcn.getChildren();
+ int stmtpos = (children.length - 1);
+ for (;stmtpos < children.length; stmtpos++) {
+ dependencies.visit(children[stmtpos]);
+ }
+ SimpleNode depExpr = dependencies.computeReferencesAsExpression();
+ String result = new ParseTreePrinter().visit(depExpr);
+ if (options.getBoolean(Compiler.PRINT_CONSTRAINTS)) {
+ System.out.println(result);
+ }
+ return result;
+ }
+
//
// Compiler Options
//
@@ -849,6 +892,6 @@
}
/**
- * @copyright Copyright 2001-2007 Laszlo Systems, Inc. All Rights
+ * @copyright Copyright 2001-2008 Laszlo Systems, Inc. All Rights
* Reserved. Use is subject to license terms.
*/
Modified:
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
===================================================================
---
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
2008-02-27 20:53:04 UTC (rev 8117)
+++
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
2008-02-27 22:07:56 UTC (rev 8118)
@@ -375,6 +375,7 @@
on.set(Ops.DELETE, "delete");
on.set(Ops.VOID, "void");
on.set(Ops.NEW, "new");
+ on.set(Ops.CAST, "cast");
OperatorNames = (String[])on.toArray(OperatorNames);
}
Modified:
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
===================================================================
---
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
2008-02-27 20:53:04 UTC (rev 8117)
+++
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ReferenceCollector.java
2008-02-27 22:07:56 UTC (rev 8118)
@@ -27,6 +27,7 @@
Set metareferences;
Set metafunctions;
String depth = "";
+ Compiler.Parser parser = new Compiler.Parser();
public ReferenceCollector() {
this(false);
@@ -64,9 +65,13 @@
return s;
}
+ // TODO: [2006-02-22 dda] Remove this 'subfunction' version soon.
+ // 'subfunction' naming (Class.f() and Class.f.dependencies())
+ // does not work in SWF9.
+
// f(args...) -> f["dependencies"](this, undefined, args...)
// a.f(args...) -> f["dependencies"](this, a, args...)
- private SimpleNode fsubst(SimpleNode node) {
+ private SimpleNode fsubst_using_subfunction(SimpleNode node) {
SimpleNode fn = node.get(0);
SimpleNode callee;
if (fn instanceof ASTPropertyIdentifierReference) {
@@ -84,12 +89,66 @@
map.put("_1", fn);
map.put("_2", callee);
map.put("_3", new Compiler.Splice(node.get(1).getChildren()));
- // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
- return (new
Compiler.Parser()).substitute("_1.hasOwnProperty('dependencies') ?
_1.dependencies(this, _2, _3) : []", map);
+ return parser.substitute("_1.hasOwnProperty('dependencies') ?
_1.dependencies(this, _2, _3) : []", map);
}
+ // callee.fn(args...) ->
+ // callee.hasOwnProperty('$lsc$fn_dependencies') ?
+ // (callee cast Object).$lsc$fn_dependencies(args...) : []
+ // If callee doesn't exist (i.e. original expression is just fn()),
+ // then 'this' is assumed for callee. If we don't downcast the callee
+ // at the point of the call, on SWF9 we'd get compile errors
+ // when the dependency function doesn't exist.
+ // The cast is a no-op for runtimes that don't need them.
+ private SimpleNode fsubst(SimpleNode node) {
+ SimpleNode fn = node.get(0);
+ SimpleNode callee;
+ if (fn instanceof ASTPropertyIdentifierReference) {
+ callee = fn.get(0);
+ fn = fn.get(1);
+ } else {
+ callee = new ASTThisReference(0);
+ }
+ String depnm = "$lsc$" + ((ASTIdentifier)fn).getName() + "_dependencies";
+
+ // the function uses #pragma "warnUndefinedReferences=false"
+ // to avoid warnings for non-existent dependencies
+ Map map = new HashMap();
+ map.put("_1", callee);
+ map.put("_2", new Compiler.Splice(node.get(1).getChildren()));
+
+ return parser.substitute("_1.hasOwnProperty('" + depnm + "') ? (_1 cast
Object)." + depnm + "(this, _1, _2) : []", map);
+ }
+
+ // TODO: [2006-02-22 dda] Remove this 'subfunction' version soon.
+ // 'subfunction' naming (Class.f() and Class.f.dependencies())
+ // does not work in SWF9.
+
// Concatenate references array with any results from dependeny
// functions
+ private SimpleNode build_using_subfunction(Set references, Set functions) {
+ SimpleNode a = rsubst(references);
+ Map map = new HashMap();
+ Set added = new HashSet();
+ ParseTreePrinter ptp = new ParseTreePrinter();
+ for (Iterator i = functions.iterator(); i.hasNext(); ) {
+ SimpleNode n = (SimpleNode)i.next();
+ String s = ptp.visit(n);
+ // Eliminate redundant constraints
+ if (! added.contains(s)) {
+ added.add(s);
+ SimpleNode b = fsubst_using_subfunction(n);
+
+ map.put("_1", a);
+ map.put("_2", b);
+ a = parser.substitute("_1.concat(_2)", map);
+ }
+ }
+ return a;
+ }
+
+ // Concatenate references array with any results from dependeny
+ // functions
private SimpleNode build(Set references, Set functions) {
SimpleNode a = rsubst(references);
Map map = new HashMap();
@@ -105,17 +164,30 @@
map.put("_1", a);
map.put("_2", b);
- // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
- a = (new Compiler.Parser()).substitute("_1.concat(_2)", map);
+ a = parser.substitute("_1.concat(_2)", map);
}
}
return a;
}
+ // TODO: [2006-02-22 dda] Do we want to keep computeMetaReferences?
+ // ptw says it's a failed experiment. It's hard to test any
+ // new code that keeps it alive.
+
+ public SimpleNode computeReferencesAsExpression() {
+ return build(references, functions);
+ }
+
+ // TODO: [2006-02-22 dda] Remove this 'subfunction' version soon.
+ // 'subfunction' naming (Class.f() and Class.f.dependencies())
+ // does not work in SWF9.
+ // Migrate callers to new implementation in
+ // computeReferencesAsExpression().
+
public SimpleNode computeReferences(String name) {
// Sanitize the name
name = name.replace('#', '_').replace(' ', '_').replace('/',
'_').replace('.', '_');
- SimpleNode d = build(references, functions);
+ SimpleNode d = build_using_subfunction(references, functions);
if (computeMetaReferences) {
for (Iterator i = metareferences.iterator(); i.hasNext(); ) {
SimpleNode r = (SimpleNode)i.next();
@@ -125,13 +197,12 @@
metareferences.remove(r);
}
}
- SimpleNode md = build(metareferences, metafunctions);
+ SimpleNode md = build_using_subfunction(metareferences, metafunctions);
// store metadependencies as a property of deps
Map map = new HashMap();
map.put("_1", d);
map.put("_2", md);
- // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
- return (new Compiler.Parser()).substitute(
+ return parser.substitute(
// TODO: [2003-06-19 ptw] (krank) Have to use sanitized
// name here, so that substitute does not try to name
// the function "x"
@@ -144,8 +215,7 @@
} else {
Map map = new HashMap();
map.put("_1", d);
- // TODO: [2006-01-03 ptw] Do we really need a new Parser each time?
- return (new Compiler.Parser()).substitute(
+ return parser.substitute(
// TODO: [2003-06-19 ptw] (krank) Have to use sanitized
// name here, so that substitute does not try to name
// the function "x"
_______________________________________________
Laszlo-checkins mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-checkins