3D Modeling Domain Specific Language (DSL) in ART
What is it?
This is my coursework for the CS3480 - Software Language Engineering module.
We were tasked with creating two different programming languages for a
specific domain.
I decided to go for the 3D modelling option, and create a
DSL less bloated than OpenSCAD.
Throughout this module we made use of the ART(Ambiguity Retained
Translation) toolkit
This provided an intuitive way to write logic based
programming language specifications in a programmer oriented way.
the background
There are two separate programming language specifications for 2 different 3D modeling related Domain Specific Languages (DSLs):- One specification was written using Executable Structural Operational Semantics (SOS)
- The other using Attribute Grammar rules
The commands used to interact with the JavaFx plugin were implemented in a stack like way.
Note: the image in the photo is some quick example I did to demonstrate the
language
For a taste of what features it had and what it looked like, look
bellow:
For a more detailed deep dive check out my Github linked above
Language 1 - eSOS reduction semantics
(if (and (> 2 1) true) (!print 2!) (!print 3!))
!:= x 2! (++ x)
!:= x 2! (-- x) !print x!
!:= x 4! |while (> x 1) (-- x) !print 2!|
(index ( list 1 2 3 4 ) 2)
|for !:= i 6! (/= i 4) (-- i)
!print i!|
[let (!:= a 3! !:= b 4!) !print a! !print b!]
(switch 3 (case 3 !print 4!)
(case 2 !print 5!
(break)))
(try
(if (< 1 2)
(error))
(catch
!print error!)
(end
!print resolve!))
: double [(x) !print (* x 2)!]
[func double 2]
[funcall ( (x y) !print (+ x y)!) 2 3]
|map ( (x) (return (* (+ x 1) 2))) (1 2 3 4 5)|
(plugin 'init')
(cube 10 20 30)
|for !:= i 0! (/= i 3) (++ i)
(sphere 5) (cylinder 20 20)
(move (* i 40) 0 0)
(colour (% i 2) 0 0)
(pop) |
Language 2 - Attribute Grammar Rules
(+ 2 2 3 3) == 10
(* 10 2 10) == 200
(- 100 10 10 10 10 10 10) == 40
(> 4 3 2) == 1
(>= 4 4 3 3) == 1
(assert (/= 2 3))
(if (= 1 1) 2 (else 0)) == 2
(switch 3 (case 3 (print (+ 4 2))) (case 3 (print 2)) (case 5 (print 5)) (case 3 (print 222)))
(try (print 2) (error) (print 5) (catch (print 3) (print 4)))
(:= a 5) (let((:= a 2) (:= b 3)) (:= a 5) (assert (= a 5)) (assert (= b (- a 2))))
(:= x (list 1 2 3 4)) (index x 2) == 3
(:= i 2)
(defun times2 ( b )
(return (* b 2)))
(defun times4 ( a )
(return (* 2 (times2 a))))
(times4 2) == 8
(defun higherOrder ( func1 func2 x)
(return (+ (func1 x) (func2 x))))
(defun times2 ( a )
(return (* a 2)))
(defun times4 ( a )
(return (* a 4)))
(higherOrder times2 times4 5) ==30
(defun recursive ( a )
(if (= a 0)
(return 1)
(else (-- a)
(recursive a)))
(print a))
(recursive 10) == 1
(defun functionsList ()
(return
(list
(lambda ()(return 2))
(lambda () (return 3)))))
(assert (= (funcall (index (functionsList) 0)) 2))
(assert (= (funcall (index (functionsList) 1)) 3))
(defun makeCounter (x)
(let ((:= count test))
(print test)
(let ((:= z 1))
(return (list
(lambda (y) (:= count (+ count y z))(++ z))
(lambda () (return count)))))))
(defun increaseCounter (counter x)
(funcall (index counter 0) x))
(defun getCount (counter)
(return (funcall (index counter 1))))
(:= test 3)
(:= counter (makeCounter 5))
(increaseCounter counter 1)
(increaseCounter counter 2)
(getCount counter) == 9
(defun makeCounter (x)
(let ((:= count x))
(return (list
(lambda (y) (:= count (+ count y)))
(lambda () (return count))))))
(defun increaseCounter (counter x)
(funcall (index counter 0) x))
(defun getCount (counter)
(return (funcall (index counter 1))))
(:= counter (makeCounter 5))
(increaseCounter counter 1)
(increaseCounter counter 2)
(getCount counter) == 8
(plugin 'init')
(defun makeCounter (x)
(let ((:= count x))
(return (list
(lambda (y) (:= count (+ count y)))
(lambda () (return count))))))
(defun increaseCounter (counter x)
(funcall (index counter 0) x))
(defun getCount (counter)
(return (funcall (index counter 1))))
(defun wheelPair (dist1 dist2)
(cylinder 30 10)
(colour 1 1 1)
(cylinder 10 30)
(colour 0 1 0)
(rotate 'z' 90)
(move dist1 dist2 0)
(pop))
(defun body ()
(cylinder 50 500)
(rotate 'x' 0)
(move 50 200 (- 40))
(colour 1 1 0)
(pop))
(defun front ()
(cylinder 20 50)
(rotate 'x' 90)
(colour 1 1 0)
(move 0 0 (- 40))
(sphere 45)
(colour 1 0 0)
(move 50 (- 20) (- 40))
(pop))
(defun middle ()
(cube 80 250 100)
(move 50 250 (- 60))
(colour 0 1 0)
(pop))
(defun wheels()
(for (:= counter (makeCounter 0)) (< (getCount counter) 4) (increaseCounter counter 1)
(let ((:= vertDist (* 150 (getCount counter))))
(wheelPair 0 vertDist)
(wheelPair 100 vertDist))) (pop))
(body) (front) (middle) (wheels)