164Query

Friday, December 18, 2009

Modified HW3 Final Project Proposal

Part I
1. In project 3, we implemented a small browser and extended with basic scripting. In order to facilitate more complicated scripting, we aim to embed a baby version of jQuery into the 164 language; we'll call this library 164Query. With its control structures and iterators, the 164 language is well-suited for DOM layout; however, we have no clean way of modifying the DOM. One solutions for this would be to have programmers manually traverse the DOM with JavaScript-like functions. These functions would be able to traverse the DOM, select DOM nodes, or add events. While this sounds like a feasible solution, because modifying the DOM is a task that will be done frequently, we want to design a cleaner abstraction for this functionality. As an example, what if we wanted to change the color of all the links on a page that contain a certain word? Without this baby version of jQuery, we would have to write a function that first grabs all correct links in the DOM. Then we would write a for loop that iterates over all of these links and adds event listeners to all of these links such that their color changes appropriately. It would be much cleaner to abstract away the iteration and adding of event listeners. What jQuery does for JavaScript is facilitate the ease with which the DOM is modified, and we hope to add this same feature to the 164 language. This way, we would have a universal method of changing DOM elements which is readily understandable. We do not rely on a programmer-designed family of functions; we rely on implementation of the 164Query library.
2. With the example described previously, although it is not difficult to write code that grabs links, iterates over these links, and adds the appropriate event listeners, it leaves significant room for error. As a result of breaking up the task into many different sub-parts, each step is now prone to error. Furthermore, the increase in code size of the original method also contributes to the difficulty of writing clean code for these kind of DOM-manipulation tasks. It seems that without the correct plumbing, debugging code would be difficult because programmers would have to do deal with all the details and would not be able to focus on the main idea of the program. By embedding the 164Query library into 164, we abstract away complexity and give programmers the tools to write readable and more error-free code.
3. This problem is worth solving because it makes it easier for us to modify the DOM and helps with adding scripting features to BAH webpages. We would no longer have to create functions for grabbing all a certain kind of node, iterators for nodes, etc. since we are making it part of the language itself. Because of the confined nature of this problem, we are left with few other options than extending the functionality of 164. In extending project 3, we hope to allow 164 to do more than just layout the BAH and basic scripting.

Part II

Code example: q('_Link’):bind('onhover',['q(~this~):fill(~red~)', 'q(~this~):fill(~black~)'])

This small fragment displays the simplicity and elegance 164Query. We one clean line of code, we efficiently solve the problem in question in Part I. From a high level, this code will grab all the links on the page, and bind the onhover event to each of these links. The second argument to ‘bind’ is the 164Query fragment that will be executed when the event occurs. In onhover’s case, this is a two-element list of 164Query statements, the former of which will be executed when the mouse is hovering over the element, the latter when the mouse leaves that element.

Implementation-wise, q(‘_Link) will create a Q object with klass attribute equal to a lambda will be used to filter DOM nodes, and return this Q object to implement call-chaining. The ‘bind’ function will call the ‘each’ function and pass in the lambda that ‘each’ will execute. The ‘each’ function is the main driver of 164Query in that most other methods in 164Query will use ‘each’ as a subroutine to execute their functionalities. ‘Each’ takes in a lambda and does a preorder traversal of the nodes in the DOM, filtering the nodes based on the klass attribute of that instance of the Q class, and executing the argument-lambda on the nodes in question. With this example, a lambda that sets the ‘onclick’ attribute of DOM nodes is passed into ‘each’. Finally in one of the passes through the DOM, nodes with ‘onclick’ attributes set, will have those events registered with the canvas.

def q(klass) {
...
if(klass == “_Link”) {
def selector = lambda(n) { n.name == “Link”}
Q:new({klass: selector})
...
}

Q.bind = lambda(self, bQueryEvent, programString) {
self:each(lambda(node) { node[bQueryEvent] = programString })
self # return query object for call chaining
}

Q.each = lambda(self, f) {
for(n in preorder(dom)) {
...
if( self.klass(n) ) { f(n) }
...
}
self # return query object for call chaining
}

Part III
1. Project Domain – Three Sample Programs
a) Following a cursor on a grid
In this instance, the DOM will consist of a grid of squares. The squares in the grid will change color depending on the location of the mouse cursor. All the squares in the same row and column as the (x,y) coordinates of the mouse will change to a different color. So in a sense, the color of the squares in the graph will "follow" the location of the cursor.

To support more flexible instantiation of the grid size, we create a script node in the DOM which contains 164 code that will be executed before DOM layout. In this example, we create the DOM in the script, and then call DOM relayout at the end. The DOM will contain a list of HBox children, and each of them will have their ‘onhover’ attribute bound to 164Query code in this script block. When we hover over a HBox, it will trigger 164Query that iterates through all DOM node, selecting for those with the same column and row and changes their fill to yellow.

#inside script tag
dom = {}
...
for(i in range(1, n)) {
for(j in range(1,n)) {
...
child.onhover = [native stringFormat (‘q(lambda (node) { node.i == %s or node.j == %s }):fill(‘yellow’), [i, j]), native stringformat(‘q(lambda (nocde) { node.i == %s or node.j == %s}):fill(‘orange’), [i, j])]
...
layoutDOM(dom)
#end script tag

b) Dealing with Text: Highlighting words, changing the color of links on hover
We will try to provide some parsing for elements in BAH webpages. The first is highlighting words in the DOM that match a word that the user enters; this allows for searching for quicker parsing of webpages. High-level-wise, this code will grab all the words on the page, filter that set of words by selecting for those that match our search word and then changing the fill of those words to red. The second functionality is highlighting links when the mouse hovers over them.

For word-highlighting:
q('_Word'):filter(lambda(n){ n.word == searchword }):fill('red')

For changing colors of links:
q(‘_Links’):bind(onhover, [“q('this'):fill('pink')","q('this'):fill('default')”] )

c) A game – LightsOut
In this example, we make a small game that is much more easily implemented using 164Query. The game is LightsOut. Initially all the boxes on the board are white, and the goal is cover all the squares on the grid with a certain color, let’s say black. When a user clicks a node, that node as well as every other node vertically or horizontally adjacent to it, changes color as well. The color changes work in a toggle-like fashion: if the nodes are originally white they then become black after the click, and vice versa.

To do this, we assign each HBox a unique klass (specifying row and column number) and make use of 164Query’s ability to select nodes based on klass. Upon creation, Q objects can take in a list of id’s, which represents selecting for those nodes in the DOM whose id is contained in the list. With these nodes in hand, we bind a toggle event to them.

Sample Code:
q(['02', '11', '12', '22']):toggle_fill('black','white')

2. Outline of Programming Model
164Query is built on top of 164 as a library written in 164. 164Query revolves around the use of Q objects and the ‘q()’ function. All 164Query queries start with ‘q(args)’ instantiating a Q object, setting the Q object’s class field to args (usually some sort of selector), and then returning this Q object for method chaining. Supported selectors include a list of DOM-node id’s, lambdas, klass-type, and reserved keywords like _Words, which will grab all the words in the DOM. The lambda selector was implemented to expand the power of the library, in that it provides users with the tools to create their own selector functions. While all the selectors provided by 164Query can be implemented using lambda, we provide the ones that we felt users would use more frequently for convenience’s sake. These selectors will be stored in the ‘klass’ field of Q.

164Query queries thus abstract away the iterating over the DOM nodes and filtering the set down to those desired nodes. After the right nodes are selected, a variety of scripting-related events can subsequently be bound to these nodes that we selected, via method-chaining calls to functions in the Q class. Examples include binding events, unbinding events, and toggling the fill of the node. Each of these functions makes use the workhorse ‘each()’, which takes in a lambda to carry out on nodes, and does a preorder of the nodes in the DOM, filters nodes based on the initial selector instantiated in the Q object, calls the lambda it was passed in, and then returns the node to allow for method chaining.

The following is a list of operations supported in 164Query:
a) Selectors
1) q([klass-list]) – match elements with klass name matching any of names in klass-list
2) q(‘klass-name’) – match elements with a given klass name
3) q(lambda() { ... }) – match elements which satisfy the selector lambda function
4) q(‘this’) – when used in an attribute in the BAH tag, specifies the current node
5) q(‘_NodeType’) – matches all elements in the DOM of a given node type
6) filter(fn) – keeps on elements from the set of matched elements where the specified function returns a non-false value
7) empty – matches all elements that have no children
c) Events
1) bind – binds a handler to one event (like click)
2) unbind - opposite of bind, it removes bound events from each of matched elements 3) onhover - simulates hovering (moving mouse on and off)
4) onclick - triggers the click event of each matched element
5) ondblclick - triggers the dblclick event of each matched element
d) DOM-modifications
1) fill – changes the fill of the DOM node
2) font – changes the font of the DOM node
3) toggle_fill – toggles between two different colors
e) User Input
1) user_input – gets a string typed in from the user

To facilitate the use of 164Query, we added a new BAH DOM node, called Script. Script nodes will contain 164 or 164Query code, which will be run before the DOM is laid out. This was implemented by storing the code in the Script block in one of the attributes of the Script object. During the DOM layout, an extra pass was made which looked did a preorder on the DOM looking Script nodes and executing their code. Only after the Script nodes’ code was executed was the DOM laid out.

Finally, we added support for image-display (not as extra credit from the previous project) to make websites more lively. Img’s were implemented by creating an Img class that extended the Node class. Img objects have their own ComputeWidth, LayoutAndComputeHeight, and Rendering functions, which override those inherited in the Node class, and will be used during the DOM layout. Mainly these functions call the right canvas functions to display the image.

Part IV
First alternative implementation: Make 164Query a new language built on top of 164.
Front End: If 164Query is another language built on top of 164, we would need a compiler to compile it into 164 code. This 164 code will subsequently be parsed into an AST and turn that into byte-code.
Core Language: The core language is still 164.
Internal representation: An alternative way of representing the program in the interpreter/compiler is using 164 code itself, which will be turned into 164 bytecode.
Interpreter/Compiler: We could either create a new compiler that compiles 164Query into 164 or modify the 164-interpreter to understand 164Query code. In the latter alternative, the 164-interpreter would need to do another pass to turn 164Query code into 164,
Debugging: This would involve looking at the compiled 164Query code to see if it is being translated into the correct 164 code. This can be tested by running the interpreter on the 164 code generated from 164Query, writing 164 code that the 164Query should be translated into and 164 or bytecode is equivalent.

Second alternative implementation: Embed 164Query into 164 by writing 164Query in 164.
Front End: None really because we can handle 164-code as before, so the 164-code will be parsed into an AST and then translated into bytecode. The problem is that we are limited to what the 164-language provides for us, but it saves us the time of writing a compiler or an interpreter.
Core Language: 164 is the core language. We do not really desugar any features because all these features are written in 164.
Internal Representation: The program can be represented in the interpreter/compiler as bytecode.
Interpreter/Compiler: We do not need to interpret or compile the language because in this implementation, 164Query is implemented in 164. We did not really have a choice of how to represent the code because 164 is naturally turned into bytecode.
Debugging: This will be done in a manner similar to how we debugged 164: with print statements and looking at output. To make sure we are writing legal 164-code, we will probably need to iteratively comment/uncomment pieces of code to see where the parsing errors lie. We will similarly do this for making sure we are not making any parsing errors in the BAH grammar.

Friday, December 11, 2009

Three Sample Programs

Dealing with Text: Highlighting words/text, changing the color of hovered links
We will try to provide some parsing for elements in BAH webpages. When a user presses an alphanumeric character, it will trigger an event handler that highlights all words containing that character. Also the DOM will detect whenever the mouse cursor goes over the link, and will change the color of the link's font.

For text highlighting:
q("Words"):bind("click", lambda(self) {self.fill = "yellow"})
q(".all"):empty():contains("a"):trigger("default")

For changing colors on links:
q(".Links"):bind("hover", lambda(self) { self.fill = "red" })

Matching Game
For this example, we try to emulate the memory game in which users have to match pairs of identical pictures on a board. Originally the square-filled board will be covered, with the pictures that each square hides concealed. Clicking a covered square will reveal the hidden picture. After two pictures have been matched, clicking on those squares corresponding to these pictures will not hide the pictures once more. The goal is to find all pairs of identical pictures as quickly as possible.

All squares will have a click event-handler that changes the background to a certain image. One click will change the plain square color to an image color and another click will revert this.

q("Squares"):bind("click", switchImages)
q("MatchedSquares"):unbind()

Following a cursor on a grid
In this instance, the DOM will consist of a grid of squares. The squares in the grid will change color depending on the location of the mouse cursor. All the squares in the same row and column as the (x,y) coordinates of the mouse will change to a different color. So in a sense, the squares in the graph will "follow" the location of the cursor. These lit-up squares will reveal the row and column that the mouse is on.

This example will necessitate efficient selecting of nodes in the DOM. We can then filter the nodes based on x and y coordinate, and of these selected nodes, we trigger the deafult event handler that we initially put into the DOM.

q(".HBox"):filter("lambda(self,x,y):
if (self.x_c == x) {
if (self.y_c == y) {
return 1
}
}
return 0
"):trigger("default")

Friday, November 20, 2009

HW3

CS164 HW3 - Final Project Proposal
Part I
1. We want to embed a baby version of jQuery into the 164 language. With its control structures and iterators, the 164 language is well-suited for DOM layout; however, we have no clean way of modifying the DOM. One solutions for this would be to have programmers manually traverse the DOM with JavaScript-like functions. These functions would be able to traverse the DOM, select DOM nodes, or add events. While this sounds like a feasible solution, because modifying the DOM is a task that will be done frequently, we want to design a cleaner abstraction for this functionality. As an example, what if we wanted to change the color of all the links on a page that contain a certain word? Without this baby version of jQuery, we would have to write a function that first grabs all correct links in the DOM. Then we would write a for loop that iterates over all of these links and adds event listeners to all of these links such that their color changes appropriately. It would be much cleaner to abstract away the iteration and adding of event listeners. What jQuery does for JavaScript is facilitate the ease with which the DOM is modified, and we hope to add this same feature to the 164-language. This way, we would have a universal method of changing DOM elements which is readily understandable. We do not rely on a programmer-designed family of functions; we rely on the programming-language's implementation.

2. With the example described previously, although it is not difficult to write code that grabs links, iterates over these links, and adds the appropriate event listeners, it leaves significant room for error. As a result of breaking up the task into many different sub-parts, each step is now prone to error. Furthermore, the increase in code size of the original method also contributes to the difficulty of writing clean code for these kind of DOM-manipulation tasks. It seems that without the correct plumbing, debugging code would be difficult because programmers would have to do deal with all the details and would not be able to focus on the main idea of the program. By creating a jQuery-like library for the 164-language, we abstract away complexity and give programmers the tools to write readable and more error-free code.

3. This problem is worth solving because it makes it easier for us to modify the DOM and helps with adding scripting features to BAH webpages. We would no longer have to create functions for grabbing all a certain kind of node, iterators for nodes, etc. since we are making it part of the language itself. Because of the confined nature of this problem, we are left with few other options than extending the functionality of the 164-language. In extending project 3, we hope to allow the 164-language to do more than just layout the BAH.

Part II

$("exit").click(lambda (event) {
alert("Thanks for visiting!")
}

This code will grab all the tags whose id is 'exit', and then add an event handler to those links such that when the link is clicked, the webpage will show a pop-up window with the specified text passed into alert().

Implementation-wise, we can have $ be a reserved keyword which stands for a function that operates on the DOM. Inside this function, it will do a traversal of the DOM and return an iterator over the dictionary of tags whose id is "exit". Each of these references to an "exit" tag will call a click method which will bind an click event handler to that tag using the lambda argument that was passed in and modify the DOM accordingly.

def $(string) {
tags = traverse DOM and return tags who have string as id
def i = 0
lambda () {
def cur = i
i = i+1
return tags[cur]
}
}

def click(func) {
get a pointer to 'self'
change the DOM by making a new event handler
}
Part III
  1. The domain: a few small programs that we hope to be able to write:
    1. Events: Launch code when website is ready by a "ready event", checks the document and waits until it's ready to run the script
    2. Special Effects: cause a link to fade in or fade out when it is clicked.
    3. Selectors: select an object in order to bind event handlers to it, such as selecting a link to attach a mouse-over event listener to it.
  2. Outline of programming model:
    1. Objects: Selectors, Traversing, Events, Effects
    2. Operations:
      1. Selectors
        1. id - matches a single element with given id attribute
        2. element - matches all elements with given tag name
        3. selector1, selector2, selectorN - matches combined results of all specified selectors
        4. first - matches first selected element
        5. last -matches last selected element
        6. eq(index) - matches a single element by its index
        7. contains(text) - matches elements which contain the given text
        8. empty - matches all elements that have no children
      2. Traversing
        1. filter(fn) - keeps only elements from the set of matched elements where the specified function returns a non-false value
        2. slice(start,end) - selects a subset of the matched elements.
      3. Events
        1. ready - binds a function to be executed when DOM is ready
        2. bind - binds a handler to one event (like click)
        3. one - binds a handler to one or more events to be executed once for each matched element
        4. trigger - trigger an event on every matched element
        5. triggerHandler - triggers all bound event handlers on an element (for a specific event type) WITHOUT executing the browser's default actions
        6. unbind - opposite of bind, it removes bound events from each of matched elements
        7. hover - simulates hovering (moving mouse on and off)
        8. click - triggers the click event of each matched element
        9. click(fn) - binds a function to the click event of each matched element
        10. dblclick - triggers the dblclick event of each matched element
        11. dblclick(fn) - binds a function to the dblclick event of each matched element
        12. ...etc mouse and keyboard-related binders
      4. Effects
        1. show - displays matched elements if they are hidden
        2. hide - hides elements if they are shown
        3. fadeIn - fade an object in with variable speed
        4. fadeOut - fade an object out with variable speed
    3. Abstraction mechanism - our 164Query will be built on top of our 164 language meaning all the abstraction mechanisms afforded to us in 164 is at our disposal for 164Query.
Part IV
Alternative implementation 1:
frontend: Translate the input scripts into 164 code with a library. This requires the user to include the 164Query library everytime the user wishes to write 164Query code. This is probably the more preferable option when compared with modifying the 164 code interpreter as there is no installation required. Also, it allows for quick future updates by changing the 164Query library.
core language: 164 code is the core language. The desugaring stage depends on the frontend implementation. In this case, the desugaring happens in the 164Query library.
internal representation: Program can be represented as 164 bytecode.
debugging: Debugging will be done through testcases with the small programs described in part 3. Unfortunately, because most of the test are user interface related, many tests will have to be run manually.


Alternative implementation 2:
frontend: modify the 164 interpreter to also handle 164Query code. This allows the user to bypass importing libraries, but all users will have to update their 164 interpreters. In a real browser, this is equivalent to updating all users' browser installations which may be a larger hassle than including libraries.
core language: 164 code is the core language. The desugaring stage depends on the frontend implementation. In this case, the desugaring happens in the 164 interpreter.
internal representation: Program can be represented as 164 bytecode.
debugging: Debugging will be done through testcases with the small programs described in part 3. Unfortunately, because most of the test are user interface related, many tests will have to be run manually. We will have to make sample webpages and interact with them to see if they indeed have the desired functionality.