package code.lang;

import code.instr.Instruction;
import code.modules.CurryModule;
import code.space.Computation;
import code.stuff.Logger;
import code.stuff.Tracer;
import code.symbols.*;
import code.term.*;
import code.type.*;
import static code.type.PredefinedTypes.*;
import static code.type.TypeFactory.*;

import java.io.*;
import java.util.Vector;

/**
 * @author Sergio Antoy
 * @since 3/7/2005
 */
public class CharModule extends CurryModule {
    // public static final String moduleName = "$Char";
    public static final String moduleName = "Prelude";

    public CharModule() {
        super(moduleName, new Vector(), null, 0, createSymbols(), false);
    }

    private static Vector createSymbols() {
        Vector v = new Vector();
        v.add(charTypeSymbol);

        v.add(chrOperation);
        v.add(ordOperation);
        return v;
    }

    private final static TypeSymbol charTypeSymbol =
            new TypeSymbol(moduleName, charTypeName, 1, Symbol.Public);

    private final static DataSymbol chrOperation =
            new OperationSymbol(moduleName,
                    "chr",
                    DataSymbol.toplevel,
                    1,
                    DataSymbol.NonInfix,
                    DataSymbol.NonInfix,
                    Symbol.Public,
		    makeFunctionType(intType, charType),
         	    new Instruction[]{ new chrInstruction(),}
	     );

    public static class chrInstruction implements Instruction {
        public void execute(Computation computation) {
            Term term = computation.getTerm();
	    Term argument = term.getArgument((byte) 0);
	    switch (argument.getKind()) {
            case DataSymbol.UnboundVariable:
		computation.selfSetState(Computation.RESIDUATING);
		break;
            case DataSymbol.Operation:
		computation.push(argument);
		break;
	    case DataSymbol.Failure:
		Term fail = SuccessModule.termFail;
		if (Tracer.reduction)
		    Tracer.traceRewrite(computation, term, fail);
		term.update(fail);
		break;
            default:
		int intValue = ((TermImplInt) argument.getRepresentation()).value;
		char charValue = (char) intValue;
		Term reduct = new Term(charValue);
                if (Tracer.reduction) 
		    Tracer.traceRewrite(computation, term, reduct);
                term.update(reduct);
		break;
	    }
        }

        public String printAsTxtLoadable() {
            return "external function \"chr\"";
        }

    }


    private final static DataSymbol ordOperation =
            new OperationSymbol(moduleName,
                    "ord",
                    DataSymbol.toplevel,
                    1,
                    DataSymbol.NonInfix,
                    DataSymbol.NonInfix,
                    Symbol.Public,
		    makeFunctionType(charType, intType),
         	    new Instruction[]{ new ordInstruction(),}
	     );

    public static class ordInstruction implements Instruction {
        public void execute(Computation computation) {
            Term term = computation.getTerm();
	    Term argument = term.getArgument((byte) 0);
	    switch (argument.getKind()) {
            case DataSymbol.UnboundVariable:
		computation.selfSetState(Computation.RESIDUATING);
		break;
            case DataSymbol.Operation:
		computation.push(argument);
		break;
	    case DataSymbol.Failure:
		Term fail = SuccessModule.termFail;
		if (Tracer.reduction)
		    Tracer.traceRewrite(computation, term, fail);
		term.update(fail);
		break;
            default:
		char charValue = ((TermImplChar) argument.getRepresentation()).value;
		int intValue = (int) charValue;
		Term reduct = new Term(intValue);
                if (Tracer.reduction) 
		    Tracer.traceRewrite(computation, term, reduct);
                term.update(reduct);
		break;
	    }
        }

        public String printAsTxtLoadable() {
            return "external function \"ord\"";
        }

    }

}

