Difference between revisions of "Itty Bitty Programming Language Functions And Macros Assignment"
(→IbLet*) |
|||
Line 37: | Line 37: | ||
===IbLet*=== | ===IbLet*=== | ||
− | Write a Racket function <code>IbLet*</code> that takes a Racket list of bindings | + | Write a Racket function <code>IbLet*</code> that takes a Racket list of bindings (list (binding s<sub>1</sub> e<sub>1</sub>) ... (binding s<sub>i</sub> |
− | + | e<sub>i</sub>) ... (binding s<sub>n</sub> e<sub>n</sub>)) and a final IBPL expression e<sub>n+1</sub>. In each pair, assume s<sub>i</sub> | |
− | is a Racket string and e<sub>i</sub> | + | is a Racket string and e<sub>i</sub> is an IBPL expression. <code>IbLet*</code> returns a IBPL expression whose value is e<sub>n+1</sub> evaluated in an |
− | is | ||
environment where each s<sub>i</sub> | environment where each s<sub>i</sub> | ||
is a variable bound to the result of evaluating the corresponding e<sub>i</sub> | is a variable bound to the result of evaluating the corresponding e<sub>i</sub> |
Revision as of 03:29, 1 December 2023
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 (list (binding s1 e1) ... (binding si
ei) ... (binding sn en)) and a final IBPL expression en+1. In each pair, assume si
is a Racket string and ei is an 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
Bind to the Racket variable ib-map
a IBPL FunctionExp that acts like map (as we used extensively
in ML). Your function should be curried: it should take a IBPL FunctionExp and return a IBPL
function that takes a IBPL list and applies the function to every element of the list returning a
new IBPL list. Recall a IBPL list is NilExp or a ConsExp where the second component is a IBPL list.
(define ib-map
'not-yet-implemented)
ib-map-add-n
Bind to the Racket variable ib-map-add-n
a IBPL function that takes an IBPL integer i and
returns a IBPL function that takes a IBPL list of IBPL IntExps and returns a new IBPL list of
IBPL integers that adds i to every element of the list. Use ib-map
(a use of LetExp
is given to
you to make this easier).
(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 | ![]() |
source folder: | src/test/racket/ibpl/functions_and_macros |
note: ensure that you have removed all printing to receive credit for any assignment.