/**
 * Support for classes.
 */
module php/reflect/oo/classes
signature
  constructors
    Instance : Class * Id -> Instance
    Class    : ClassName  -> Class

strategies

  /**
   * Creates a new class instance
   *
   * -> Class
   */
  classes_new-instance =
    !Instance(<?Class(_)>, <new> ())

  /**
   * Returns true of the class is an instance of  
   * the desired name.
   *
   * @type Class -> Bool
   **/
  classes_instanceof(|name) =
    ?Instance(Class(name), _)

  /**
   * Gets the class for a given name.
   *
   * @type Name -> Class
   */
  classes_get-class =
    !Class(<id>)

  /**
   * Returns the field table of the class.
   *
   * @type _ -> HashTable
   */
  classes_get-fieldtbl =
    table-hashtable
    ; hashtable-get(new-hashtable |"fields")

strategies

  classes_get-instance-field(|name) =
    ?Instance(_, x)
    ; classes_get-fieldtbl
    ; hashtable-get(|(x, name))

  classes_get-instance-field(ifnot | name) =
    ?this@Instance(_, x)
    ; classes_get-fieldtbl
    ; hashtable-get(<ifnot> this |(x, name))

  classes_set-instance-field(|name, value) =
    ?Instance(_, x)
    ; where(
        classes_get-fieldtbl
        ; hashtable-put(|(x, name), value)
      )

  classes_get-class-field(|name) =
    ?Instance(_, Class(x))
    ; classes_get-fieldtbl
    ; hashtable-get(|x)

strategies

  hashtable-get(ifnot | key) =
    hashtable-get(|key)
    <+ where(ifnot => value)
       ; hashtable-put(|key, value)
       ; !value

  /**
   * Avoid the choice operator in hashtable push if we know that the key exists.
   * Also, fails if the key does not exist.
   */
  hashtable-push-existing(|key, value) =
    where(hashtable-get(|key) => previous)
    ; hashtable-put(|key, [value | previous])