001/* 002 * This file is part of OCaml-Java runtime. 003 * Copyright (C) 2007-2013 Xavier Clerc. 004 * 005 * OCaml-Java runtime is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU Lesser General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * OCaml-Java runtime is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.ocamljava.runtime.wrappers; 020 021import org.ocamljava.runtime.kernel.NativeApply; 022import org.ocamljava.runtime.values.BlockValue; 023import org.ocamljava.runtime.values.Value; 024 025/** 026 * The {@code OCamlLazy} class is the wrapper class for OCaml values of 027 * type {@code 'a lazy_t}. 028 * 029 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a> 030 * @version 2.0 031 * @since 2.0 032 */ 033public final class OCamlLazy<T extends OCamlValue> extends OCamlValue { 034 035 /** Wrapper for nested value. */ 036 private final Wrapper<T> wrapper; 037 038 /** 039 * Constructs a new instance wrapping the passed value. 040 * @param w wrapper for nested value - should not be {@code null} 041 * @param v value to wrap - should not be {@code null} 042 */ 043 private OCamlLazy(final Wrapper<T> w, final Value v) { 044 super(v); 045 assert w != null : "null w"; 046 this.wrapper = w; 047 } // end constructor(Wrapper<T>, Value) 048 049 /** 050 * {@inheritDoc} 051 */ 052 @Override 053 public Wrapper<? extends OCamlLazy<T>> getWrapper() { 054 return OCamlLazy.wrapper(this.wrapper); 055 } // end method 'getWrapper()' 056 057 /** 058 * {@inheritDoc} 059 */ 060 @Override 061 public Wrapper<? extends OCamlValue> getWrapper(final int idx) { 062 switch (idx) { 063 case 0: return this.wrapper; 064 default: return OCamlUnit.WRAPPER; 065 } // end switch 066 } // end method 'getWrapper(int)' 067 068 /** 069 * Returns the wrapped value. 070 * @return the wrapped value if already forced, or {@code null} otherwise 071 */ 072 public T get() { 073 if (this.value.isLong()) { 074 return this.wrapper.wrap(this.value); 075 } else { 076 switch (this.value.getTag()) { // XXX quid lazy imbriques ? 077 case BlockValue.LAZY_TAG: return null; 078 case BlockValue.FORWARD_TAG: return this.wrapper.wrap(this.value.get0()); 079 default: return this.wrapper.wrap(this.value); 080 } // end switch 081 } // end if/else 082 } // end method 'get()' 083 084 /** 085 * Returns the wrapped value, by forcing it if necessary. 086 * @return the wrapped value 087 */ 088 public T force() { 089 if (this.value.isLong()) { 090 return this.wrapper.wrap(this.value); 091 } else { 092 switch (this.value.getTag()) { // XXX quid lazy imbriques ? 093 case BlockValue.LAZY_TAG: 094 try { 095 // XXX what is the state of a lazy value when (first) evaluation has raised an exception? 096 final Value res = NativeApply.apply(this.value.get0(), Value.UNIT); 097 this.value.setTag(BlockValue.FORWARD_TAG); 098 this.value.set0(res); 099 return this.wrapper.wrap(res); 100 } catch (final Throwable t) { 101 assert false : "exception during lazy evaluation"; 102 return null; // XXX 103 } // end try/catch 104 case BlockValue.FORWARD_TAG: return this.wrapper.wrap(this.value.get0()); 105 default: return this.wrapper.wrap(this.value); 106 } // end switch 107 } // end if/else 108 } // end method 'force()' 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public int hashCode() { 115 return this.value.hashCode(); 116 } // end method 'hashCode()' 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override 122 public boolean equals(final Object obj) { 123 if (obj instanceof OCamlLazy) { 124 final OCamlLazy<?> that = (OCamlLazy) obj; 125 return this == that; 126 } else { 127 return false; 128 } // end if/else 129 } // end method 'equals(Object)' 130 131 /** 132 * {@inheritDoc} 133 */ 134 @Override 135 public String toString() { 136 final StringBuilder sb = new StringBuilder(); 137 sb.append("OCamlLazy("); 138 final T v = get(); 139 if (v == null) { 140 sb.append("..."); 141 } else { 142 sb.append(this.wrapper.wrap(v.value()).toString()); 143 } // end if/else 144 sb.append(")"); 145 return sb.toString(); 146 } // end method 'toString()' 147 148 /** 149 * Constructs a new {@code 'a lazy_t} value, and wraps it. 150 * @param v value to wrap 151 * @return a new {@code OCamlLazy} instance wrapping the passed value 152 */ 153 @SuppressWarnings("unchecked") 154 public static <T extends OCamlValue> OCamlLazy<T> create(final T v) { 155 return new OCamlLazy<T>((Wrapper<T>) v.getWrapper(), 156 Value.createBlock(BlockValue.FORWARD_TAG, v.value())); 157 } // end method 'create(T)' 158 159 /** 160 * Constructs a new {@code 'a lazy_t} value, and wraps it. 161 * @param w wrapper for nested value - should not be {@code null} 162 * @param c closure computing the value 163 * @return a new {@code OCamlLazy} instance wrapping the passed value 164 */ 165 public static <T extends OCamlValue> OCamlLazy<T> create(final Wrapper<T> w, 166 final OCamlFunction<OCamlUnit, T> c) { 167 final Value clos = c.getClosure(OCamlUnit.WRAPPER); 168 return new OCamlLazy<T>(w, Value.createBlock(BlockValue.LAZY_TAG, clos)); 169 } // end method 'create(Wrapper<T>, OCamlFunction<OCamlUnit, T>)' 170 171 /** 172 * Wraps the passed value. 173 * @param w wrapper for nested value - should not be {@code null} 174 * @param v value to wrap - should not be {@code null} 175 * @return a new {@code OCamlLazy} instance wrapping the passed value 176 */ 177 public static <T extends OCamlValue> OCamlLazy<T> wrap(final Wrapper<T> w, 178 final Value v) { 179 assert v != null : "null v"; 180 return new OCamlLazy<T>(w, v); 181 } // end method 'wrap(Wrapper<T>, Value)' 182 183 /** 184 * Returns a wrapper for {@code OCamlLazy} values. 185 * @param w wrapper for nested value - should not be {@code null} 186 * @return a wrapper for {@code OCamlLazy} values 187 */ 188 @SuppressWarnings("unchecked") 189 public static <T extends OCamlValue> Wrapper<? extends OCamlLazy<T>> wrapper(final Wrapper<T> w) { 190 return new ComposedWrapper<OCamlLazy<T>>(w) { 191 /** 192 * {@inheritDoc} 193 */ 194 @Override 195 public OCamlLazy<T> wrap(final Value v) { 196 return new OCamlLazy<T>(w, v); 197 } // end method 'wrap(Value)' 198 }; // end anonymous inner-class 199 } // end method 'wrapper()' 200 201} // end class 'OCamlLazy'