CS 3520 Homework 9

Due: Wednesday, November 15th, 2023 11:59pm

Difficulty:  ★★★☆

Start with class_inherit.rhm, which combines class.rhm, inherit.rhm, and inherit_parse.rhm into a single file.

You may find it nicer to work with class.rhm, inherit.rhm, and inherit_parse.rhm as separate files, but you must combine them into a single file for handin. To combine the files: append them in the listed order, then remove the second and third #lang shplait lines and remove all import forms.

Part 1 — Instantiating Object

In the starting code, new Object() doesn’t work, even though Object is supposed to be a built-in class with no fields and no methods. Fix the implementation to that new Object() produces an instance of Object.

  check: interp_prog([],
                     'new Object()')
         ~is 'object'
  check: interp_prog(['class Fish(size, color):
                         extends Object'],
                     'new Fish(1, 2)')
         ~is 'object'

Part 2 — Conditional via select

Add select:

  <Exp> = ...
        | select <Exp>: <Exp>

The first expression in select should produce a number result, while the second expression should produce an object. If the number is 0, select calls the zero method of the object. If the number is not 0, select calls the nonzero method of the object. In each case, select calls the method with the argument 0. The select form has lowest precedence.

  check: interp_prog(['class Snowball(size):
                        extends Object
                        method zero(arg): this
                        method nonzero(arg):
                          new Snowball(1 + this.size)'],
                     '(select 0: new Snowball(1)).size')
         ~is '1'
  check: interp_prog(['class Snowball(size):
                        extends Object
                        method zero(arg): this
                        method nonzero(arg):
                          new Snowball(1 + this.size)'],
                     '(select 1 + 2: new Snowball(1)).size')
         ~is '2'

The result is up to you when select gets a non-number result for its first subexpression, but a “not a number” error is sensible. Similarly, the result is up to you when the second subexpression’s result is not an object or does not have a zero or nonzero method.

You will probably find it easiest to extend and test the Exp layer, then then ExpI layer, and then the parse and interp_prog layer.

Part 3 — is_a

Add is_a:

  <Exp> = ...
        | <Exp> is_a <Sym>

An expression <Exp> is_a <Sym> produces 0 if the result of <Exp> is an object that is an instance of the class named by <Sym> or any of its subclasses. It should produce 1 if the result of <Exp> is any other object. Note that <Exp> is_a Object should produce 0 as long as the value of <Exp> is an object. The is_a operator’s precedence should be immediately lower than +.

Note that you will have to introduce a notion of superclasses into the Class layer, even though method inheritance remains the job of the ClassI layer.

Example:

  check: interp_prog(['class Fish(size, color):
                         extends Object'],
                     'new Fish(1, 2) is_a Object')
         ~is '0'
  check: interp_prog(['class Fish(size, color):
                         extends Object'],
                     'new Object() is_a Fish')
         ~is '1'
  check: interp_prog(['class Fish(size, color):
                         extends Object'],
                     'new Fish(1, 2) is_a Fish')
         ~is '0'
  check: interp_prog(['class Fish(size, color):
                         extends Object',
                      'class Shark(teeth):
                         extends Fish'],
                     'new Shark(1, 2, 3) is_a Fish')
         ~is '0'
  check: interp_prog(['class Fish(size, color):
                         extends Object',
                      'class Shark(teeth):
                         extends Fish',
                      'class Hammerhead():
                         extends Shark'],
                     'new Hammerhead(1, 2, 3) is_a Fish')
         ~is '0'
  check: interp_prog(['class PlainFish(size):
                         extends Object',
                      'class ColorFish(color):
                         extends PlainFish',
                      'class Bear(size, color):
                         extends Object
                         method rate_food(arg):
                           (arg is_a ColorFish) + arg.color'],
                     '(new Bear(100, 5)).rate_food(new ColorFish(10, 3))')
         ~is '3'

The result is up to you if <Exp> in <Exp> is_a <Sym> does not produce an object or if <Sym> is not the name of a class.


Last update: Wednesday, November 15th, 2023
mflatt@cs.utah.edu