Itty Bitty Programming Language Functions And Macros Assignment
In a series of assignments, we will build the Itty Bitty Programming Language (IBPL). The inspiration for these assignments is MUPL by Dan Grossman and his team at UW.
One can build an IBPL Abstract Syntax Tree (AST) with the following expressions:
Contents
Expressions
(struct IdentifierExp (name) #:transparent)
(struct IntExp (value) #:transparent)
(struct AddExp (left_exp right_exp) #:transparent)
(struct IfGreaterExp (left_exp right_exp then_body_exp else_body_exp) #:transparent)
(struct NilExp () #:transparent)
(struct IsNilExp (exp) #:transparent)
(struct ConsExp (car_exp cdr_exp) #:transparent)
(struct CarOfConsExp (cons_exp) #:transparent)
(struct CdrOfConsExp (cons_exp) #:transparent)
(struct LetExp (binding_name binding_exp body_exp) #:transparent)
(struct FunctionExp (name_option parameter_name body_exp) #:transparent)
(struct CallExp (function_exp argument_exp) #:transparent)
Code To Implement
Note: the syntax descriptions below are adapted from Prof. Grossman's MUPL syntax descriptions.
Macros
Expanding the Language
IBPL is a small language, but we can write Racket functions that act like IBPL macros so that users of these functions feel like IBPL is larger. The Racket functions produce IBPL expressions that could then be put inside larger IBPL expressions or passed to evaluate
. Also do not use evaluate
(we are creating a program, not running it).
file: | src/main/racket/ibpl/functions_and_macros/macros.rkt | |
functions: | IbIfNil IbLet* IbIfEq |
IbIfNil
Write a Racket function IbIfNil
that takes three IBPL expressions e1, e2, and e3. It returns a IBPL expression that when run evaluates e1 and if the result is IBPL’s NilExp then it evaluates e2 and that is the overall result, else it evaluates e3 and that is the overall result.
(define (IbIfNil exp then_body_exp else_body_exp)
(error 'not-yet-implemented))
IbLet*
Write a Racket function IbLet*
that takes a Racket list of bindings ’((s1 . e1) ... (si
. ei) ... (sn . en)) and a final IBPL expression en+1. In each pair, assume si
is a Racket string and ei
is a IBPL expression. IbLet*
returns a IBPL expression whose value is en+1 evaluated in an
environment where each si
is a variable bound to the result of evaluating the corresponding ei
for 1 ≤ i ≤ n. The bindings are done sequentially, so that each ei
is evaluated in an environment
where s1 through si−1 have been previously bound to the values e1 through ei−1.
(struct binding (name exp) #:transparent)
(define (IbLet* bindings body_exp)
(error 'not-yet-implemented))
IbIfEq
Write a Racket function IbIfEq that takes four IBPL expressions e1, e2, e3, and e4 and returns a IBPL expression that acts like IfGreaterExp except e3 is evaluated if and only if e1 and e2 are equal integers. Assume none of the arguments to IbIfEq use the IBPL variables _x or _y. Use this assumption so that when an expression returned from IbIfEq is evaluated, e1 and e2 are evaluated exactly once each.
(define (IbIfEq left_exp right_exp then_body_exp else_body_exp)
(error 'not-yet-implemented))
Functions
file: | src/main/racket/ib-map-add-n/functions_and_macros/functions.rkt | |
functions: | ib-double ib-sum-curry ib-call-with-one ib-map ib-call-with-one |
ib-double
(define ib-double
'not-yet-implemented)
ib-sum-curry
(define ib-sum-curry
'not-yet-implemented)
ib-call-with-one
(define ib-call-with-one
'not-yet-implemented)
ib-map
(define ib-map
'not-yet-implemented)
ib-map-add-n
(define ib-map-add-n
(LetExp "map" ib-map
'not-yet-implemented-notice-map-is-now-in-IBPL-scope))
Test
file: | test_functions_and_macros.rkt | Test |
source folder: | src/test/racket/ibpl/functions_and_macros |
note: ensure that you have removed all printing to receive credit for any assignment.