, , , , , , , ,

[SOLVED] Csci 3155 : project 2 (lettuce with figs)

$25

File Name: Csci_3155_:_project_2_(lettuce_with_figs).zip
File Size: 386.22 KB

5/5 - (1 vote)
5/5 – (1 vote)

This project extends the Lettuce language with arithmetic, let bindings, function calls and recursive functions with an extra value type: figures. We will augment the language with operations that can allow us to

  • Draw figures made up of rectangles, lines, triangles and circles.
  • Place these figures besides each other
  • Rotate these figures

Your assigment for this project will include:

  • Complete the interpreter for this language based on the semantics that are provided.
  • Write some programs to generate some of the example figures shown.

As previously, you are given some code that includes code we have written for Lettuce with arithmetic and Booleans from the notebooks. Your job is to write the missing code. Please read this documentation properly.

Beta Notice: As always, we make up things as we go along. Please feel free to point out ambiguities/ask for clarifications on piazza.

Running the code and submitting

Environment setup is the same as for project 1.

Submission instructions are same as for project 1. Run the command checkAndZipSubmission to create a submission.zip file.

The Language Extension

We will extend Lettuce to allow us to write programs like thus

let a = rectangle(1) in
   let b = circle(0.5) in
      a/b

a is assigned to a rectangle of side length 1 (it will be a square) and b to a circle of radius 0.5. Thus a,b are of type Figures

We will define the division of two figures as placing the figure a on top of figure b.

The result should place a rectangle on top of a circle like thus.

We are using the / operator to operate both on numbers or figures. This is an example of operator overloading.

Likewise we will overload other operators as follows:

Operator Argument 1 Type Argument 2 Type Meaning
+ Number Number Add two numbers
+ Figure(f1) Figure(f2) Make a composite figure by overlapping the two figures f1, f2
* Number Number Multiply two numbers
* Figure(f1) Figure(f2) Make a composite figure by placing figure f2 to the right of figure f1
/ Number Number Division
/ Figure(f1) Figure(f2) Place figure f1 on top of figure f2
/ Figure(f1) Number (d) Rotate figure f1 around (0,0) by angle d in radians
Number Number Subtract

Note that all other operations are meaningless. For instance, trying to subtract one figure from other leads to error. Likewise, adding a number to a figure leads to an error.

The table above is going to be very important. Please refer back to it when you interpret the programs below.

What does the program below do?

let f1 = triangle(1) in 
  (f1 * f1)/f1

The star operator places two triangles one besides other and the / operator places a new triangle on top.

The language allows functions as well:

let f = function (x) 
      rectangle(x) * ((triangle(x)/triangle(x)) * circle(x))
      in 
    f(1) + f(2) / f(3)

Can you try interpreting what figure will be generated by the program above?

We will also include recursion and now interesting things happen.


letrec serp = function (x)
       if (x <= 1)
       then (triangle(x)*triangle(x))/triangle(x)
       else (
           let f = serp(x-1) in
               (f * f) / f
            ) in
       serp(5)

Or try this one

letrec mandala = function (x)
    let ang = 3.1415/10 in
    if (x <= 1)
    then rectangle(2)+triangle(2)
    else (rectangle(2)+triangle(2))+(mandala(x-1)/ang)
  in
  mandala(20)

Intrigued? Interested in bringing this language to life? March on forward.

Abstract Syntax of LettuceWithFig

We will have the following abstract syntax borrowed from the language with recursive calls. Note that the key extensions are shown in red.

A program is simply a expression wrapped around the TopLevel constructor.

ProgramTopLevel(Expr)Program→TopLevel(Expr)

Expressions are given as follows:

ExprConst(Double)ConstBool(Boolean)Ident(String)Rectangle(Expr)Triangle(Expr)Circle(Expr)Line(Expr)Plus(Expr,Expr)Minus(Expr,Expr)Mult(Expr,Expr)Div(Expr,Expr)Geq(Expr,Expr)Gt(Expr,Expr)Eq(Expr,Expr)Neq(Expr,Expr)And(Expr,Expr)Or(Expr,Expr)Not(Expr)IfThenElse(Expr,Expr,Expr)Let(String,Expr,Expr)LetRec(String,String,Expr,Expr)FunDef(String,Expr)FunCall(Expr,Expr)Creation of Basic Shapes for FiguresArithmetic Operators are overloaded for figures as discussed previouslylet bindingsrecursive definitionanonymous functionfunction callExpr→Const(Double)→ConstBool(Boolean)→Ident(String)→Rectangle(Expr)Creation of Basic Shapes for Figures→Triangle(Expr)→Circle(Expr)→Line(Expr)→Plus(Expr,Expr)Arithmetic Operators are overloaded for figures as discussed previously→Minus(Expr,Expr)→Mult(Expr,Expr)→Div(Expr,Expr)→Geq(Expr,Expr)→Gt(Expr,Expr)→Eq(Expr,Expr)→Neq(Expr,Expr)→And(Expr,Expr)→Or(Expr,Expr)→Not(Expr)→IfThenElse(Expr,Expr,Expr)→Let(String,Expr,Expr)let bindings→LetRec(String,String,Expr,Expr)recursive definition→FunDef(String,Expr)anonymous function→FunCall(Expr,Expr)function call

Canvas: A value type for representing figures.

We are first going to define a value type called Canvas. A canvas is going to collect a bunch of shapes with coordinates. We will define some basic operations on canvases:

  • creating a canvas with a single shape.
  • bounding box for a canvas.
  • overlap of two canvases.
  • placing one canvas on top of another to yield a new canvas.
  • placing one canvas to the left of another to yield a new canvas.
  • rotation of a canvas.

A canvas is of the form Canvas({o1,,on})Canvas({o1,…,on}), wherein o1,,ono1,…,on are the objects in the canvas. Each object oioi is itself one of the following:

  • Polygon({(x0,y0),,(xk1,yk1)})Polygon({(x0,y0),…,(xk−1,yk−1)}): A polygon whose vertex coordinates are specified.
  • Circle((xc,yc),r)Circle((xc,yc),r): A circle with the specified center (xc,yc)(xc,yc) and radius.

Example of Canvas

Consider a canvas

Canvas ( { 
    Polygon( { (0,0), (1,0), (0.5,0.5) } ) , 
    Circle ( (1,1), 1) , 
    Polygon( { (1,1), (2,1), (2,2), (1,2) }  ) 
    } ) 

Canvases are going to be a value type for our interpreter along with numbers, booleans, closures and (nominally) error.

Operations on canvas.

Bounding Box of a canvas.

A bounding box for a canvas cc is given by boundingBox(c)boundingBox(c) which is a tuple of 44 numbers of the form (xmin,xmax,ymin,ymax)(xmin,xmax,ymin,ymax) where

  • xminxmin is the smallest xx coordinate for any object in the canvas.
  • xmaxxmax is the largest xx coordinate for any object in the canvas.
  • yminymin is the smallest yy coordinate for any object in the canvas.
  • ymaxymax is the largest yy corrdinate for any object in the canvas.

Once again consider the example canvas from before:

Canvas ( { 
    Polygon( { (0,0), (1,0), (0.5,0.5) } ) , 
    Circle ( (1,1), 1) , 
    Polygon( { (1,1), (2,1), (2,2), (1,2) }  ) 
    } ) 

Its bounding box is given by (0,2,0,2)(0,2,0,2) with xmin=ymin=0xmin=ymin=0 and xmax=ymax=2xmax=ymax=2.

Translate operation on a canvas

Given a Canvas object cc , its translation by (xShift,yShift)(xShift,yShift) is denoted translate(c,xShift,yShift)translate(c,xShift,yShift) and yields a new canvas.

The translate operation adds the value xShift to all x coordinates of the object in the canvas and yShift to all y coordinates of the object in the canvas.

Once again consider the example canvas from before:

Canvas ( { 
    Polygon( { (0,0), (1,0), (0.5,0.5) } ) , 
    Circle ( (1,1), 1) , 
    Polygon( { (1,1), (2,1), (2,2), (1,2) }  ) 
    } ) 

We wish to perform a translation by (2,3)(2,3) where xShift = 2 and yShift = 3. The result will be the canvas.

Canvas ( { 
    Polygon( { (2,3), (3,3), (2.5,3.5) } ) , 
    Circle ( (3,4), 1) , 
    Polygon( { (3,4), (4,4), (4,5), (3,5) }  ) 
    } ) 

Rotation Operation on a canvas.

Given a Canvas object cc , its rotation by θθ in radians is denoted rotate(c,θ)rotate(c,θ) and yields a new canvas.

Recall from your calculus class that rotating a point (x,y)(x,y) by angle θθ in radians yields

x=xcos(θ)ysin(θ),   y=xsin(θ)+ycos(θ)x′=xcos⁡(θ)−ysin⁡(θ),   y′=xsin⁡(θ)+ycos⁡(θ)

As an example, let us rotate the canvas from before:

Canvas ( { 
    Polygon( { (0,0), (1,0), (0.5,0.5) } ) , 
    Circle ( (1,1), 1) , 
    Polygon( { (1,1), (2,1), (2,2), (1,2) }  ) 
    } ) 

by 3030∘ or π6π6 radians.

Rotating a canvas is given by rotating each object in the canvas.

  • Rotating a polygon is given by applying rotation by θθ to each vertex
  • Rotating a circle is given by applying rotation by θθ to the center of the circle. Radius is unchanged.

Overlapping one canvas with other.

Let c1:Canvas(O1)c1:Canvas(O1) with objects in set O1O1 and likewise c2:Canvas(O2)c2:Canvas(O2). We define the canvas

overlap(c1,c2)=Canvas(O1O2)overlap(c1,c2)=Canvas(O1∪O2)

The new canvas has objects which are simply the union of objects from canvases c1 and c2.

Placing one canvas on top of another

The placeTop operator will place one canvas on top of another. Let us consider the operation of placing canvas c2 on top of canvas c1. To achieve this, we are going to first

  • translate the objects in canvas c2 by a shiftX and shiftY that we will compute.
  • next we will make a new canvas that combines the objects in both.

Let c1:Canvas(O1)c1:Canvas(O1) and c2:Canvas(O2)c2:Canvas(O2) be the two canvases. The operation placeTop(c1,c2)placeTop(c1,c2) is defined as follows:

  • Let (xmin,1,xmax,1,ymin,1,ymax,1)(xmin,1,xmax,1,ymin,1,ymax,1) be the result of boundingBox(c1)boundingBox(c1).
  • Let (xmin,2,xmax,2,ymin,2,ymax,2)(xmin,2,xmax,2,ymin,2,ymax,2) be the result of boundingBox(c2)boundingBox(c2).
  • Define xShift=(xmax,1xmin,1)/2(xmax,2xmin,2)/2xShift=(xmax,1−xmin,1)/2−(xmax,2−xmin,2)/2.
  • Define yShift=(ymax,1ymin,1)yShift=(ymax,1−ymin,1).
  • Let c^2c^2 be the canvas obtained by transate(c2,xShift,yShift)transate(c2,xShift,yShift)
  • Define the result of placeTop(c1,c2)=overlap(c1,c^2)placeTop(c1,c2)=overlap(c1,c^2).

The calculations above sound somewhat arbitrary but can be easily justified if you look at the figure above.

Placing one canvas to the right of another

The placeRight operator will place one canvas on top of another. Let us consider the operation of placing canvas c2 to the right of canvas c1. To achieve this, we are going to first

  • translate the objects in canvas c2 by a shiftX and shiftY that we will compute.
  • next we will make a new canvas that combines the objects in both.

Let c1:Canvas(O1)c1:Canvas(O1) and c2:Canvas(O2)c2:Canvas(O2) be the two canvases. The operation placeRight(c1,c2)placeRight(c1,c2) is defined as follows:

  • Let (xmin,1,xmax,1,ymin,1,ymax,1)(xmin,1,xmax,1,ymin,1,ymax,1) be the result of boundingBox(c1)boundingBox(c1).
  • Let (xmin,2,xmax,2,ymin,2,ymax,2)(xmin,2,xmax,2,ymin,2,ymax,2) be the result of boundingBox(c2)boundingBox(c2).
  • Define xShift=(xmax,1xmin,1)xShift=(xmax,1−xmin,1).
  • Define yShift=(ymax,1ymin,1)/2(ymax,2ymin,2)/2yShift=(ymax,1−ymin,1)/2−(ymax,2−ymin,2)/2.
  • Let c^2c^2 be the canvas obtained by transate(c2,xShift,yShift)transate(c2,xShift,yShift)
  • Define the result of placeRight(c1,c2)=overlap(c1,c^2)placeRight(c1,c2)=overlap(c1,c^2).

The calculations above sound somewhat arbitrary but can be easily justified if you look at the figure above.

Task 1

Implement the canvas operations using the data structures defined in the file MyCanvas.scala. Please follow the given scheme and do not modify existing code.

Your results must pass the unit tests provided under CanvasTests

Interpreting Lettuce With Figs.

We will interpret our language now. We will have the following value types:

  • NumValue(Double)
  • BoolValue(Boolean)
  • Closure(String, Expression, Environment)
  • FigValue(Canvas)
  • Error

Note that we will not really consider error and just throw an exception whenever we encounter error.

For your convenience the operations over values are defined in the file Value.scala. Notice some refactoring is happening to help out with implementing the operator.

  • You may want to modify the functions
    • ValueOps.plus, ValueOps.mult, ValueOps.divide, ValueOps.minus and so on.

The semantics of Lettuce with Figs are going to inherit all the existing semantic rules used for handling

  • arithmetic
  • booleans
  • comparisons
  • function calls
  • let bindings
  • recursion

    The additional rules need to deal with operations over figures. We provide these rules below.

Semantics of Figs.

The first few rules specify the creation of basic figures.

  

The rule for a rectangle is as follows:

evalExpr(e,σ)=v, vRevalExpr(Rectangle(e),σ)=Canvas({Polygon({(0,0),(0,v),(v,v),(v,0)})})  (rectangle-ok)evalExpr(e,σ)=v, v∈RevalExpr(Rectangle(e),σ)=Canvas({Polygon({(0,0),(0,v),(v,v),(v,0)})})  (rectangle-ok)

The rule tells us how to create a rectangle whose side length is given by the expression e. The error rules for this is simple and left to the reader.

The rule for a triangle is as follows:

evalExpr(e,σ)=v, vRevalExpr(Triangle(e),σ)=Canvas({Polygon({(0,0),(v,0),(v2,3v2)})})  (triangle-ok)evalExpr(e,σ)=v, v∈RevalExpr(Triangle(e),σ)=Canvas({Polygon({(0,0),(v,0),(v2,3v2)})})  (triangle-ok)

Note that the vertex (v2,3v2)(v2,3v2) ensures that the triangle is equilateral.

The rules for a circle and line are as follows:

evalExpr(e,σ)=v, vRevalExpr(Circle(e),σ)=Canvas({Circle((v,v),v)})  (circle-ok)evalExpr(e,σ)=v, v∈RevalExpr(Circle(e),σ)=Canvas({Circle((v,v),v)})  (circle-ok)

evalExpr(e,σ)=v, vRevalExpr(Line(e),σ)=Canvas({Polygon({(0,0),(v,0)})})  (line-ok)evalExpr(e,σ)=v, v∈RevalExpr(Line(e),σ)=Canvas({Polygon({(0,0),(v,0)})})  (line-ok)

The rule for error is simple:

evalExpr(e,σ)=v, vR, T{Line,Circle,Rectangle,Triangle}evalExpr(T(e),σ)=error  (basic-shape-error)evalExpr(e,σ)=v, v∉R, T∈{Line,Circle,Rectangle,Triangle}evalExpr(T(e),σ)=error  (basic-shape-error)

Overloading Arithmetic Operators on Figures

We will talk about the semantics of arithmetic operators on figures. Here is the helpful table from before.

Operator Argument 1 Type Argument 2 Type Meaning
+ Number Number Add two numbers
+ Figure(f1) Figure(f2) Make a composite figure by overlapping the two figures f1, f2
* Number Number Multiply two numbers
* Figure(f1) Figure(f2) Make a composite figure by placing figure f2 to the right of figure f1
/ Number Number Division
/ Figure(f1) Figure(f2) Place figure f1 on top of figure f2
/ Figure(f1) Number (d) Rotate figure f1 around (0,0) by angle d in radians
Number Number Subtract

Rules for arithmetic opertations:

Rule for Plus

evalExpr(e1,σ)=v1, v1R, evalExpr(e1,σ)=v2, v2R, evalExpr(Plus(e1, e2),σ)=v1+v2  (plus-numbers-ok)evalExpr(e1,σ)=v1, v1∈R, evalExpr(e1,σ)=v2, v2∈R, evalExpr(Plus(e1, e2),σ)=v1+v2  (plus-numbers-ok)

The rule above is the usual rule for plus. We also have a rule for plus involving figures.

evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2=Canvas(O2)evalExpr(Plus(e1, e2),σ)=overlap(v1,v2)  (plus-figures-ok)evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2=Canvas(O2)evalExpr(Plus(e1, e2),σ)=overlap(v1,v2)  (plus-figures-ok)

We are not writing the error rules. But note that adding any other combination of values other than a number plus number or figure plus figure results in an error.

Rule For Multiplication

evalExpr(e1,σ)=v1, v1R, evalExpr(e1,σ)=v2, v2R, evalExpr(Mult(e1, e2),σ)=v1×v2  (mult-numbers-ok)evalExpr(e1,σ)=v1, v1∈R, evalExpr(e1,σ)=v2, v2∈R, evalExpr(Mult(e1, e2),σ)=v1×v2  (mult-numbers-ok)

The rule above is the usual rule for multiplication of numbers. We also have a rule involving figures.

evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2=Canvas(O2)evalExpr(Plus(e1, e2),σ)=placeRight(v1,v2)  (mult-figures-ok)evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2=Canvas(O2)evalExpr(Plus(e1, e2),σ)=placeRight(v1,v2)  (mult-figures-ok)

Note Place the figure generated by e2 to the right of that generated by e1.

Similarly we are skipping error rules that cover all other combinations (other than multiplying a number by a number or multiplying a figure by a figure)

Rule for Division

Division of two numbers (usual rule):

evalExpr(e1,σ)=v1, v1R, evalExpr(e1,σ)=v2, v2R, v20evalExpr(Div(e1, e2),σ)=v1/v2  (div-numbers-ok)evalExpr(e1,σ)=v1, v1∈R, evalExpr(e1,σ)=v2, v2∈R, v2≠0evalExpr(Div(e1, e2),σ)=v1/v2  (div-numbers-ok)

Division of one figure by another:

evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2=Canvas(O2)evalExpr(Div(e1, e2),σ)=placeTop(v2,v1)  (div-figures-ok)evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2=Canvas(O2)evalExpr(Div(e1, e2),σ)=placeTop(v2,v1)  (div-figures-ok)

Note Place the figure generated by e1 on top of that generated by e2.

Division of a figure by a number:

evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2RevalExpr(Div(e1, e2),σ)=rotate(v1,v2)  (div-figure-number)evalExpr(e1,σ)=v1, v1=Canvas(O1) evalExpr(e1,σ)=v2, v2∈RevalExpr(Div(e1, e2),σ)=rotate(v1,v2)  (div-figure-number)

Note Rotate the figure generated by e1 using the angle in radians that expression e2 evaluates to.

Rule for Other Operations

The rules for the other operations, let bindings, function definitions, function calls and recursion remain unchanged.

Task 2: Write the Interpreter

Your job is to fill in the missing code for the interpreter.

The interpreter is defined in the file Interpreter.scala.

The value types are in Value.scala

The environment (for handling recursion as well) is defined in Environment.scala.

You can throw an IllegalArgumentException whenever you encounter an error. A string message should be added to the exception to indicate why you fail.

Reviews

There are no reviews yet.

Only logged in customers who have purchased this product may leave a review.

Shopping Cart
[SOLVED] Csci 3155 : project 2 (lettuce with figs)
$25