Extensible Visual Constraint Language
Brian Broll & Akos Ledeczi, Vanderbilt University
Background
Constraints
- Well-formedness rules for a DSML
- Typically written in OCL or Microsoft Formula
WebGME
- Next generation of the GME
- Runs in a web browser
- Component based
- Provides:
- Scalability
- Real-time collaboration
- Version control
- Custom data visualizations
Related Work
Visual OCL
- Logical, typed, object oriented
- Adheres to UML for simplicity
Constraint Diagrams
- Also Logical, typed, object oriented
- Similar to Euler diagrams
- More compact than Visual OCL
Other Visual Constraint Approaches
-
Inspired by Scratch from MIT
- Imperative (Instruction flow)
- Explicitly focuses on making programming more accessible
-
Implemented as a DSML
- Supports domain specific customization
- Supports evaluation in distributed
environment
Extensible Visual Constraint Language
Architecture
- Composed of 4 main components:
- Metamodel
- Language syntax defined
- Model
- Contains constraint instances
- Visualizer
- Provides the Scratch-like representation
- Compiler
- Transpiles the visual blocks to asynchronous Javascript
- Implemented as a WebGME plugin
- Metamodel
Components
Diagram of Components
*Directed connections represent information flow
Language Syntax
- Represents the basic structure of the elements
- Blue lines represent pointers in the metamodel
- The visualizer will interpret these as connected or contained blocks
Core Concepts
- Data types are instances of a Predicate block
- Inheritance allows the child block to be implicitly casted to the base block type
Data Types
- Functions inherit from their return type
- This allows them to be used as their given return type
- Pointers represent the input for the given function
Functions
Control Flow
- Inheritance represents structural similarities
- The "true_next" pointer references the block contained in the parent which is executed if the conditional (target block of the "cond" pointer) is true
- Similarly, the "false_next" pointer references the block to be executed if the conditional is false
Constraint Generation
-
Asynchronous support
- Hoisting the necessary code into the callback
- Deterministic evaluation of loops (without causing a stack overflow)
-
Additional Features:
- Framework for testing new constraint code blocks
- Variable hoisting
-
Promotes scalable constraint code
- Lazy loading of WebGME nodes
Code Generation
- In synchronous code, the generated code for a predicate block is the return value of the predicate block
- For example:
Callback Hoisting
nodes = getChildren(currentNode);
// next block's code
- In asynchronous code, the generated code for a predicate block may creation of the context in which the return value is defined
- For example:
Callback Hoisting
getChildren(currentNode, function(children) {
{{= RETURN_VALUE.START }}children{{= RETURN_VALUE.END}}
});
- In asynchronous code, the generated code for the parent block is hoisted into the correct context (placed around the return value)
- Generated code for command blocks stores the location of subsequent code
- This allows the hoisting to the callback to also move the subsequent block code
- For example:
Callback Hoisting
getChildren(currentNode, function(children) {
nodes = children;
// next block's code
});
- Loops are converted to recursive functions
- To eliminate stack overflow, recursive calls are placed in a "setTimeout" call
- This flattens the call stack
- Each subsequent call is placed on the event queue at the end of the execution of the prior iteration
Deterministic Loops
while (myConditional) {
// Executed while
// "myConditional" is true
}
// Executed once
// "myConditional" is false
var asyncLoop = function() {
if (myConditional) {
// Executed if "myConditional" is true
setTimeout(asyncLoop, 0);
} else {
// Executed once "myConditional" is false
// Subsequent blocks' code is hoisted here
}
};
Example
Unique Name Constraint
function (core, currentNode, callback){
"use strict";
var names = [];
var name = null;
var node = null;
var queue = [];
getNode(currentNode, function(arg0_7){
getDescendents(arg0_7, function(arg1_6){
queue = arg1_6;
var fn_1 = function(){
var arg1 = Object.keys(queue);
var arg2 = arg1[0];
while(arg0_2[arg2] && arg1.length){
arg2 = arg1.pop();
}
if (!arg0_2[arg2]){
arg0_2[arg2] = true;
node = queue[arg2];
getNode(node, function(arg0_4){
name = core.getAttribute(arg0_4, "name");
if (names.indexOf(name) !== -1){
violationInfo = {
hasViolation: true,
message: "duplicate names!",
nodes: null
};
}
if(getDimension(names) === getDimension(name)){
names = names.concat(name);
} else {
names.push(name);
}
setTimeout(fn_1, 0);
});
} else {
callback(err, violationInfo);
}
};
var arg0_2 = {};
fn_1();
});
});
}
Questions?
Extensible Visual Constraint Language
By Brian Broll
Extensible Visual Constraint Language
- 1,034