All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dakusui.logias.lisp.func.control.Do Maven / Gradle / Ivy

package com.github.dakusui.logias.lisp.func.control;

import static java.lang.String.format;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import com.github.dakusui.logias.lisp.Context;
import com.github.dakusui.logias.lisp.s.Pair;
import com.github.dakusui.logias.lisp.s.Sexp;
import com.github.dakusui.logias.lisp.s.SexpIterator;
import com.github.dakusui.logias.lisp.s.Symbol;


public class Do extends ControlFunc {
	ThreadLocal> updaters = new ThreadLocal>();
	
	@Override
	public Sexp invoke(Context context, Sexp... params) {
		this.updaters.set(new LinkedList());
		return super.invoke(context, params);
	}
	
	@Override
	protected Sexp perform(Context context, Sexp... params) {
		if (params == null || params.length < 2) {
			throw new RuntimeException();
		}
		SexpIterator i = params[0].iterator().assumeList();
		if (!i.hasNext()) {
			throw new RuntimeException();
		}
		
		Sexp cond = i.next();
		Sexp[] statements = Arrays.copyOfRange(params, 1, params.length);
		List updaters = this.updaters.get();
		while (Sexp.nil.equals(eval(context, cond))) {
			for (Sexp cur : statements) {
				eval(context, cur);
			}
			for (Pair pair : updaters) {
				Symbol s = (Symbol) pair.car();
				context.bind(s.name(), eval(context, pair.cdr()));
			}
		}
		
		Sexp ret = Sexp.nil;
		while (i.hasNext()) {
			ret = eval(context, i.next());
		}
		return ret;
	}

	@Override
	protected void assign(Context context, Sexp cur) {
		if (cur.isAtom()) {
			throw new RuntimeException("Each element in variable definition section cannot be an atom.");
		}
		SexpIterator i = cur.iterator().assumeList();
		if (!i.hasNext()) {
			throw new RuntimeException();
		}
		Sexp s = i.next();
		if (!(s instanceof Symbol)) {
			throw new RuntimeException(format("<%s> is not a symbol.", s));
		}
		Symbol symbol = (Symbol) s;
		
		if (!i.hasNext()) {
			throw new RuntimeException(format("Initial value for <%s> is not given.", symbol));
		}
		Sexp initialValue = i.next();
		context.bind(symbol.name(), eval(context, initialValue));
		
		List updaters = this.updaters.get();
		if (i.hasNext()) {
			Sexp updater = i.next();
			updaters.add(new Pair(symbol, updater));
			if (i.hasNext()) {
				throw new RuntimeException("Too many members for a list in variable definition section.");
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy