Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ go run main.go flipbook.flip

## Language Design

5. SwirlEffect: This function applies a rotation transformation to each page of a flipbook, with the angle of rotation increasing for each subsequent page. The syntax is as follows:

***swirl [Book ObjType variable] [Rotation Rate INT];***

### Rules:
1. There are two type of objects in this language: Book and Image.

Expand All @@ -36,7 +40,7 @@ go run main.go flipbook.flip

3.2 Integers: They are any positive integer.

4. There are four types of Statements implemented right now: new, insert, keyframe, save. Every Statement must end with a semicolon.
4. There are five types of Statements implemented right now: new, insert, keyframe, save, swirl. Every Statement must end with a semicolon.

4.1 ***New***: It creates a new object
Syntax -
Expand All @@ -61,7 +65,16 @@ go run main.go flipbook.flip
***save [Book ObjType variable] outputNameString***

## Example program
Lets animate apple falling over newton's head.
Lets animate apple falling over newton's head with a swirl effect.
```
new book bookone = ((1600,1600), 25);
new image newton = ((100,100), "newton.png");
insert newton bookone from page 1 to 25 at (600,1270);
new image melon = ((100,100), "melon.png");
insert melon bookone from page 1 to 25 at (600,0);
keyframe melon bookone positionY (1,0) to (25, 1000);
swirl bookone 10;
save bookone "out.pdf";
```
new book bookone = ((1600,1600), 25);
new image newton = ((100,100), "newton.png");
Expand Down Expand Up @@ -90,5 +103,4 @@ KeyWords= { new, at, to, set, image, book, scale, insert, from, page, keyframe,,
1. Compelete the document: Due to the limitation of time, The documentation is not very resourceful.
2.Clean Up the Code: Due to the same reason, I couldnt get the chance to properly refactor code and comment it.
3. Add Expression pevaluation via Pratt's Parser technique
4. Add an analouge of Functions as Effects like swirl
5. Add more properties like opacity and more statements like 'set'.
4. Add more properties like opacity and more statements like 'set'.
64 changes: 54 additions & 10 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ import (
"github.com/Krishanu230/Flipbook-Language/ast"
"github.com/Krishanu230/Flipbook-Language/object"

"github.com/disintegration/imaging"
)

func SwirlEffect(pages []object.PageProperty, rotationRate int) {
for i, page := range pages {
rotationAngle := i * rotationRate
for _, img := range page.ImagesProps {
img.Image = imaging.Rotate(img.Image, float64(rotationAngle), color.Transparent)
}
}
"github.com/signintech/gopdf"
)

var (
NULL = &object.Null{}
)

//eval a ast node. recursive nature
// eval a ast node. recursive nature
func Eval(node ast.Node, env *object.Environment) object.Object {
switch node := node.(type) {

Expand Down Expand Up @@ -42,6 +52,21 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
return val
}

case *ast.SwirlEffectStatement:
val := evalSwirlEffect(node, env)
if isError(val) {
return val
}
}

func evalSwirlEffect(node *ast.SwirlEffectStatement, env *object.Environment) object.Object {
r := evalIdentifier(node.Book, env)
book, ok := r.(*object.Book)
if !ok {
return r
}
SwirlEffect(book.Pages, node.RotationRate.Value)
return &object.Null{}
case *ast.SaveStatement:
val := evalSave(node, env)
if isError(val) {
Expand All @@ -51,7 +76,7 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
return nil
}

//eval a bunch of statements by passing them to Eval()
// eval a bunch of statements by passing them to Eval()
func evalStatements(sts []ast.Statement, env *object.Environment) object.Object {
var result object.Object

Expand All @@ -62,7 +87,7 @@ func evalStatements(sts []ast.Statement, env *object.Environment) object.Object
return result
}

//resolve an identifier
// resolve an identifier
func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
val, ok := env.Get(node.Value)
if ok {
Expand All @@ -71,7 +96,7 @@ func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object
return newError("identifier not found: " + node.Value)
}

//evaluate New type of statements
// evaluate New type of statements
func evalNew(inp *ast.NewStatement, env *object.Environment) object.Object {
st := *inp
if st.DType.Value == "image" {
Expand All @@ -89,7 +114,7 @@ func evalNew(inp *ast.NewStatement, env *object.Environment) object.Object {
return &object.Null{}
}

//evaluate Insert statements
// evaluate Insert statements
func evalInsert(inp *ast.InsertStatement, env *object.Environment) object.Object {
//env.Print()
r := evalIdentifier(inp.Image, env)
Expand Down Expand Up @@ -125,7 +150,7 @@ func evalInsert(inp *ast.InsertStatement, env *object.Environment) object.Object
return &object.Null{}
}

//evaluate keyframe statements
// evaluate keyframe statements
func evalKeyframe(inp *ast.KeyframeStatement, env *object.Environment) object.Object {
r := evalIdentifier(inp.Image, env)
img, ok := r.(*object.Image)
Expand Down Expand Up @@ -177,11 +202,30 @@ func evalKeyframe(inp *ast.KeyframeStatement, env *object.Environment) object.Ob
}

func evalSave(inp *ast.SaveStatement, env *object.Environment) object.Object {
ix := 0
iy := 0
r := evalIdentifier(inp.Book, env)
book, ok := r.(*object.Book)
if !ok {
return r
}
imgObj := evalIdentifier(inp.Image, env)
img, ok := imgObj.(*object.Image)
if !ok {
return imgObj
}
pdf = gopdf.GoPdf{}
pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: float64(book.DimX), H: float64(book.DimY)}})
for pno, page := range book.Pages {
pdf.AddPage()
for _, img := range page.ImagesProps {
rotatedImg := img.Image
pdf.Image(rotatedImg, float64(ix), float64(iy), nil)
}
}
if !ok {
return r
}
fname := inp.OutputName.Value
pw := book.DimX
ph := book.DimY
Expand All @@ -192,7 +236,7 @@ func evalSave(inp *ast.SaveStatement, env *object.Environment) object.Object {
for pno, page := range book.Pages {
pdf.AddPage()
for _, img := range page.ImagesProps {
imgpath := img.Image.Filename
imgpath := img.Filename
//// TODO: implement scale property change by using a better library for pdf
/*iw := int(img.Image.DimX * (0))
ih := int(img.Image.DimX * (0))
Expand All @@ -201,8 +245,8 @@ func evalSave(inp *ast.SaveStatement, env *object.Environment) object.Object {
println("ERROR1")
return newError("Image " + fname + " size larger than the page " + strconv.Itoa(pno))
}*/
ix := img.PosX
iy := img.PosY
ix = img.PosX
iy = img.PosY
if (ix > pw) || (iy > ph) {
return newError("Image " + fname + " position beyond the page " + strconv.Itoa(pno))
}
Expand All @@ -215,7 +259,7 @@ func evalSave(inp *ast.SaveStatement, env *object.Environment) object.Object {
return &object.Null{}
}

//Helper Functions
// Helper Functions
func isError(obj object.Object) bool {
if obj != nil {
return obj.Type() == object.ERROR_OBJ
Expand Down
47 changes: 47 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package evaluator

import (
"testing"

"github.com/Krishanu230/Flipbook-Language/ast"
"github.com/Krishanu230/Flipbook-Language/object"
)

func TestSwirlEffect(t *testing.T) {
pages := []object.PageProperty{
{ImagesProps: []object.ImageProperty{{Image: object.Image{Rotation: 0}}}},
{ImagesProps: []object.ImageProperty{{Image: object.Image{Rotation: 0}}}},
}
SwirlEffect(pages, 10)
if pages[0].ImagesProps[0].Image.Rotation != 0 || pages[1].ImagesProps[0].Image.Rotation != 10 {
t.Errorf("SwirlEffect did not correctly update the rotation of the images")
}
}

func TestEvalSwirlEffect(t *testing.T) {
env := object.NewEnvironment()
env.Set("bookone", &object.Book{Pages: []object.PageProperty{
{ImagesProps: []object.ImageProperty{{Image: object.Image{Rotation: 0}}}},
{ImagesProps: []object.ImageProperty{{Image: object.Image{Rotation: 0}}}},
}})
node := &ast.SwirlEffectStatement{Book: &ast.Identifier{Value: "bookone"}, RotationRate: &ast.IntegerLiteral{Value: 10}}
evalSwirlEffect(node, env)
book, _ := env.Get("bookone")
if book.(*object.Book).Pages[0].ImagesProps[0].Image.Rotation != 0 || book.(*object.Book).Pages[1].ImagesProps[0].Image.Rotation != 10 {
t.Errorf("evalSwirlEffect did not correctly update the rotation of the images")
}
}

func TestEvalSave(t *testing.T) {
env := object.NewEnvironment()
env.Set("bookone", &object.Book{Pages: []object.PageProperty{
{ImagesProps: []object.ImageProperty{{Image: object.Image{Rotation: 0}}}},
{ImagesProps: []object.ImageProperty{{Image: object.Image{Rotation: 0}}}},
}})
node := &ast.SaveStatement{Book: &ast.Identifier{Value: "bookone"}, OutputName: &ast.StringLiteral{Value: "out.pdf"}}
evalSave(node, env)
book, _ := env.Get("bookone")
if book.(*object.Book).Pages[0].ImagesProps[0].Image.Rotation != 0 || book.(*object.Book).Pages[1].ImagesProps[0].Image.Rotation != 10 {
t.Errorf("evalSave did not correctly update the rotation of the images")
}
}
4 changes: 4 additions & 0 deletions lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func TestNextToken(t *testing.T) {
{token.SCALE, "scale"},
{token.INT, "10"},
{token.SEMICOLON, ";"},
{token.SWIRL, "swirl"},
{token.IDN, "bookone"},
{token.INT, "10"},
{token.SEMICOLON, ";"},
}

l := NewLexer(input)
Expand Down