/* * Vitry, copyright (C) Hans Hoglund 2011 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * See COPYING.txt for details. */ package vitry.runtime; import static vitry.Build.*; import static vitry.runtime.Context.*; import static vitry.runtime.struct.Seqs.*; import java.math.BigInteger; import java.util.Iterator; import vitry.Build; import vitry.runtime.error.*; import vitry.runtime.parse.*; import vitry.runtime.struct.*; import vitry.runtime.util.*; /** * Standard interpreter. * * This implementation optimizes tail calls to interpreted functions, * but not to compiled functions. * * @author Hans Hoglund */ public class Interpreter implements Eval { /* * Main branches * * These correspond directly to token types. */ private static final int NAT_EXPR = VitryParser.Natural; private static final int FLOAT_EXPR = VitryParser.Float; private static final int COMPLEX_EXPR = VitryParser.Complex; private static final int STR_EXPR = VitryParser.String; private static final int OP_EXPR = VitryParser.Op; private static final int SYMBOL_EXPR = VitryParser.Symbol; private static final int FN_EXPR = VitryParser.Fn; private static final int LEFT_EXPR = VitryParser.Left; private static final int QUOTE_EXPR = VitryParser.Quote; private static final int PAR_EXPR = VitryParser.Par; private static final int BRA_EXPR = VitryParser.Bra; private static final int ANG_EXPR = VitryParser.Ang; private static final int LET_EXPR = VitryParser.Let; private static final int DO_EXPR = VitryParser.Do; private static final int ASSIGN_EXPR = VitryParser.Assign; private static final int IF_EXPR = VitryParser.If; private static final int MATCH_EXPR = VitryParser.Match; private static final int DELAY_EXPR = VitryParser.Delay; private static final int APPLY_EXPR = VitryParser.Apply; private static final int OPS_EXPR = VitryParser.Ops; private static final int TYPE_EXPR = VitryParser.Type; private static final int MODULE_DECL = VitryParser.Module; private static final int IMPORT_DECL = VitryParser.Import; private static final int EXPORT_DECL = VitryParser.Export; private static final int IMPLICIT_DECL = VitryParser.Implicit; private static final int FIXITY_DECL = VitryParser.Fixity; private static final int TYPE_DECL = VitryParser.TypeDecl; /* * Sub-branches * * Interpreter constructs used as simple subroutines. * Must be negative to avoid collisions. */ private static final int UPDATE_EXPR = -1; private static final int DELIMITER_EXPR = -2; private static final int FRAME_EXPR = -3; /* * Reserved in case we want to jump into the default branch * (which raises an unknown expression error). */ private static final int UNKNOWN = Integer.MIN_VALUE; private final VitryRuntime runtime; private ModuleProvider moduleProvider; private Context standardContext; public Interpreter(VitryRuntime runtime) { this(runtime, null); } public Interpreter(VitryRuntime runtime, ModuleProvider moduleProvider) { this.runtime = runtime; this.moduleProvider = moduleProvider; this.standardContext = (new Context() .define(DELIMITER, PAR) .define(SIDE, RIGHT) .define(QUOTED, FALSE) .define(MUTABLE, FALSE)); } public Interpreter(VitryRuntime runtime, ModuleProvider moduleProvider, Context standardContext) { this.runtime = runtime; this.moduleProvider = moduleProvider; this.standardContext = standardContext; } public boolean acceptsParserTokens() { return true; } public boolean acceptsUserTokens() { return true; } /** * Returns the runtime system owning this interpreter. */ public VitryRuntime getRuntime() { return runtime; } /** * Returns the source from which this interpreter imports dependencies for * created modules (may be null) */ public ModuleProvider getModuleProvider() { return moduleProvider; } /** * Set the source from which to imports dependencies for. */ public void setModuleProvider(ModuleProvider moduleProvider) { this.moduleProvider = moduleProvider; } /** * Get the context used for generated functions and modules. */ public Context getStandardContext() { return standardContext; } /** * Set the context used for generated functions and modules. */ public void setStandardContext(Context standardContext) { this.standardContext = standardContext; } public Object eval(Object expr) throws ParseError, VitryError, ResolveError { return eval(expr, runtime.getPrelude()); } public final Object eval(Object expr, Module module) throws ParseError, LinkageError, VitryError { return eval(expr, this.standardContext, module.getValues(), module); } public final Object eval(Object expr, Context context, Env<Symbol, Object> frame, Module module) throws ParseError, LinkageError, VitryError { Object exOp = null; Seq<Pattern> exTail = null; int branch = 0; main : while (true) { if (branch >= 0) { try { if (isSelfEvaluating(expr)) { if (expr instanceof Symbol) return lookup((Symbol) expr, context, frame); else return expr; } else { if (isAcceptedToken(expr)) { exOp = expr; exTail = null; } else { exOp = head((Seq<Pattern>) expr); exTail = tail((Seq<Pattern>) expr); } branch = Parsing.getTokenType(exOp); } } catch (Exception e) { throwUnknownForm(expr); } } switch (branch) { case NAT_EXPR: return evalNat(exOp); case FLOAT_EXPR: return evalDouble(exOp); case COMPLEX_EXPR: return evalComplex(exOp); case STR_EXPR: return evalString(exOp); case OP_EXPR: return lookupOp(exOp, context, frame); case SYMBOL_EXPR: return lookupExpr(exOp, context, frame); case FN_EXPR: return new InterpretedFunction(init(exTail), last(exTail), frame, module, this); case LEFT_EXPR: context = context.extend(SIDE, LEFT); branch = UPDATE_EXPR; continue; case QUOTE_EXPR: context = context.extend(QUOTED, TRUE); branch = UPDATE_EXPR; continue; case UPDATE_EXPR: branch = 0; expr = exTail.head(); continue; case PAR_EXPR: context = context.extend(DELIMITER, PAR).define(QUOTED, FALSE); branch = DELIMITER_EXPR; continue; case BRA_EXPR: context = context.extend(DELIMITER, BRA).define(QUOTED, FALSE); branch = DELIMITER_EXPR; continue; case ANG_EXPR: context = context.extend(DELIMITER, ANG).define(QUOTED, FALSE); branch = DELIMITER_EXPR; continue; case LET_EXPR: context = context.extend(MUTABLE, FALSE).define(DELIMITER, PAR) .define(QUOTED, FALSE).define(SIDE, RIGHT); branch = FRAME_EXPR; continue; case DO_EXPR: context = context.extend(MUTABLE, TRUE).define(DELIMITER, PAR) .define(QUOTED, FALSE).define(SIDE, RIGHT); branch = FRAME_EXPR; continue; case OPS_EXPR: // FIXME only prelude fixities // expr = Rewriting.ops(module.getFixities(), context).rewrite(exTail); expr = Rewriting.opsRewriter(getRuntime().getPrelude().getFixities(), context).rewrite(exTail); continue; case DELAY_EXPR: expr = Rewriting.delayRewriter().rewrite(exTail); continue; case IF_EXPR: if (!(eval(first(exTail), context, frame, module).equals(FALSE))) expr = second(exTail); else expr = third(exTail); continue; case DELIMITER_EXPR: { branch = 0; Symbol delim = context.getDelimiter(); if (isNil(exTail)) { return evalNullary(delim, context, frame); } else { Object bound = frame.lookup(delim); if (!isOperatorExpr(exTail.head()) && bound instanceof Product) { return evalUnary((Function) second((Product) bound), exTail.head(), context, frame, module); } expr = exTail.head(); continue; } } case FRAME_EXPR: { branch = 0; Seq<?> assignments = init(exTail); expr = last(exTail); frame = frame.extend(); if (!Seqs.isNil(assignments)) { for (Object a : assignments) eval(a, context, frame, module); } continue; } case ASSIGN_EXPR: { Object left = eval(first(exTail), context, frame, module); Object right = eval(second(exTail), context, frame, module); if (left instanceof LeftCont) { ((LeftCont) left).invoke(right, frame); } else { try { if (!left.equals(VitryRuntime.WILDCARD)) { if (context.isMutable()) frame.assoc((Symbol) left, right); else frame.define((Symbol) left, right); } } catch (ClassCastException e) { throwAssignment(left); } } return right; } case APPLY_EXPR: { Function fn = (Function) eval(exTail.head(), context.extend(SIDE, RIGHT), frame, module); Seq<?> args = exTail.tail(); if (fn.isInvertible() && context.isLeftSide()) return new ApplyCont((InvertibleFunction) fn, args, context, frame, module, this); else { if (fn.isCompiled()) return ((Function) fn).applyVar(evalAll(args, context, frame, module)); else { InterpretedFunction ifn = (InterpretedFunction) fn; Env<Symbol, Object> callFrame = frame; context = this.standardContext; frame = ifn.environment.extend(); SeqIterator<?> par = ifn.parameters.seqIterator(); SeqIterator<?> arg = args.seqIterator(); while (par.hasNext() && arg.hasNext()) { Object name = eval(par.next(), context, frame, ifn.module); Object value = eval(arg.next(), context, callFrame, module); if (name instanceof LeftCont) { ((LeftCont) name).invoke(value, frame); } else { try { if (!name.equals(VitryRuntime.WILDCARD)) frame.define((Symbol) name, value); } catch (ClassCastException e) { throwAssignment(name); } } } if (par.hasNext()) { return new InterpretedFunction(par.following(), ifn.body, frame, ifn.module, ifn.interpreter); } if (!arg.hasNext()) { expr = ifn.body; continue; } else { Function res = (Function) eval(ifn.body, context, frame, module); return res.applyVar(evalAll(arg.following(), context, callFrame, module)); } } } } case MATCH_EXPR: { Object value = eval(exTail.head(), context, frame, module); Seq<Pattern> cases = exTail.tail(); Env<Symbol, Object> topFrame = frame; match : for (Pattern c : cases) { Seq<Pattern> caseTail = ((Seq<Pattern>) c).tail(); Object left = eval(first(caseTail), context, frame, module); expr = second(caseTail); frame = topFrame.extend(); try { if (left instanceof LeftCont) { ((LeftCont) left).invoke(value, frame, true); } else { // TODO allow other symbols pointing to types to evade matching // This must be implemented in AbstractLeftCont as well! if (shouldBind(left)) { try { if (!left.equals(VitryRuntime.WILDCARD)) frame.define((Symbol) left, value); } catch (ClassCastException e) { throwAssignment(left); } } else { match(value, left); } } } catch (VitryError e) { continue match; } continue main; } throw new MatchingError(value); } case TYPE_EXPR: { // TODO native types Object left = eval(first(exTail), context, frame, module); Object right = eval(second(exTail), context.extend(SIDE, RIGHT), frame, module); if (context.isLeftSide()) { return new TypeCont(left, right); } else { if (right instanceof Type) return ((Type) right).tag(Native.wrap(left)); else { match(left, right); return left; } } } case MODULE_DECL: { Seq<Symbol> name = (Seq<Symbol>) evalAllQuoted(exTail.head(), context, frame, module); Seq<?> declarations = exTail.tail(); return new InterpretedModule(name, declarations, this); } case IMPORT_DECL: { // TODO 'as' syntax Seq<Symbol> name = (Seq<Symbol>) evalAllQuoted(exTail.head(), context, frame, module); module.importModule(moduleProvider.forName(name)); return module; } case EXPORT_DECL: throwNotSupported(); case IMPLICIT_DECL: throwNotSupported(); case FIXITY_DECL: throwNotSupported(); case TYPE_DECL: throwNotSupported(); case UNKNOWN: default: throwUnknownForm(expr, exOp); } } } static void match(Object a, Object b) throws VitryError { Pattern bp; boolean m; if (b instanceof Pattern) bp = (Pattern) b; else bp = Native.wrap(b); if (a instanceof Pattern) m = ((Pattern) a).matchFor(bp); else m = bp.match(a); if (!m) TypeError.throwMismatch(a, b); } static final boolean shouldBind(Object left) { // if (left.equals(Context.PAR)) return false; // if (left.equals(Context.BRA)) return false; // if (left.equals(Context.ANG)) return false; return (left instanceof Symbol); } static BigInteger evalNat(Object expr) { return VitryRuntime.intFrom(expr.toString()); } static Double evalDouble(Object expr) { return Double.valueOf(expr.toString()); } static Object evalComplex(Object expr) { return throwComplex(); } static Symbol evalOperator(Object expr, Symbol delimiter) { if (delimiter == PAR) return Symbol.intern("(" + expr + ")"); if (delimiter == BRA) return Symbol.intern("[" + expr + "]"); if (delimiter == ANG) return Symbol.intern("{" + expr + "}"); // There should not be any other delimiters throw new AssertionError(); } static Symbol evalSymbol(Object expr) { return Symbol.intern(expr.toString()); } static String evalString(Object expr) { String str = Strings.unescape(expr.toString()); return str.substring(1, str.length() - 1); } Object evalNullary(Symbol delim, Context context, Env<Symbol, Object> frame) { if (context.shouldLookup()) { Object obj = frame.lookup(delim); if (obj instanceof Product) return first((Product) obj); else return obj; } else return delim; } Object evalUnary(Function f, Object expr, Context context, Env<Symbol, Object> frame, Module module) { Object v = eval(expr, context, frame, module); if (context.isLeftSide() && f.isInvertible()) return new UnaryCont((InvertibleFunction) f, v); else return f.apply(v); } Seq<?> evalAll(Seq<?> exprs, final Context context, final Env<Symbol, Object> frame, final Module module) { return exprs.map(new StandardFunction.Unary() { public Object apply(Object e) throws InvocationError { return eval(e, context, frame, module); } }); } Seq<?> evalAllQuoted(Object expr, Context context, Env<Symbol, Object> frame, Module module) { return evalAll((Seq<?>) expr, context.extend(QUOTED, TRUE), frame, module); } Object lookupExpr(Object expr, Context context, Env<Symbol, Object> frame) { return lookup(evalSymbol(expr), context, frame); } Object lookupOp(Object expr, Context context, Env<Symbol, Object> frame) { return lookup(evalOperator(expr, context.getDelimiter()), context, frame); } Object lookup(Symbol expr, Context context, Env<Symbol, Object> frame) { if (context.shouldLookup()) return frame.lookup(expr); else return expr; } static boolean isSelfEvaluating(Object expr) { return ! (expr instanceof Pattern) || (expr instanceof Atom && !(expr instanceof VitryToken)); } static final boolean isAcceptedToken(Object expr) { return expr instanceof VitryToken; } /** * Whether the given pattern is headed by an Ops token. * * (This is not the same predicate as the one used in the * rewriting class). */ static final boolean isOperatorExpr(Object o) { if (o instanceof Seq) { Seq<?> s = (Seq<?>) o; return (length(s) >= 2 && isOpsToken(first(s))); } return false; } private static boolean isOpsToken(Object o) { if (o instanceof Pattern) { return Parsing.getTokenType((Pattern) o) == VitryParser.Ops; } return false; } static final <T> T throwAssignment(Object id) { throw new ParseError("Can not assign to non-symbol " + id); } static final <T> T throwNotSupported() { throw new ParseError("Does not support this feature yet"); } static final <T> T throwComplex() { throw new ParseError("Does not support complex numbers yet"); } static final void throwUnknownForm(Object tree) { throw new ParseError("Unknown form in tree " + Strings.limit(tree.toString(), TRACE_LIMIT)); } static final void throwUnknownForm(Object tree, Object form) { throw new ParseError("Unkown form '" + form + "' in tree " + Strings.limit(tree.toString(), TRACE_LIMIT)); } } final class InterpretedFunction extends RestFunction implements Arity { /* * Unevaluated parameters and body. */ public final Seq<?> parameters; public final Object body; /** * Containing module. */ public final Module module; /* * Creating interpreter */ final Interpreter interpreter; public final int arity; public InterpretedFunction(Seq<?> params, Object body, Module module, Interpreter interpreter) { this(params, body, module.getValues(), module, interpreter); } public InterpretedFunction(Seq<?> params, Object body, Env<Symbol, Object> env, Module module, Interpreter interpreter) { super(env); this.body = body; this.parameters = params; this.arity = length(params); this.module = module; this.interpreter = interpreter; } public int getArity() { return arity; } public boolean isCompiled() { return false; } public Object applyVar(Seq<?> args) { Context context = interpreter.getStandardContext(); Env<Symbol, Object> frame = this.environment.extend(); SeqIterator<?> par = this.parameters.seqIterator(); SeqIterator<?> arg = args.seqIterator(); while (par.hasNext() && arg.hasNext()) { Object name = interpreter.eval(par.next(), context, frame, this.module); Object value = arg.next(); if (name instanceof LeftCont) { ((LeftCont) name).invoke(value, frame); } else { try { if (!name.equals(VitryRuntime.WILDCARD)) frame.define((Symbol) name, value); } catch (ClassCastException e) { Interpreter.throwAssignment(name); } } } if (par.hasNext()) { return new InterpretedFunction(par.following(), this.body, frame, this.module, this.interpreter); } if (!arg.hasNext()) { return this.interpreter.eval(this.body, context, frame, this.module); } else { Function res = (Function) this.interpreter.eval(this.body, context, frame, this.module); return res.applyVar(arg.following()); } } } final class InterpretedModule extends Module { /** * Unevaluated declarations. */ private Seq<?> declExprs; final Interpreter interpreter; public InterpretedModule(Seq<Symbol> name, Seq<?> declExprs, Interpreter interpreter) { super(name); this.declExprs = declExprs; this.interpreter = interpreter; this.importModule(interpreter.getRuntime().getPrelude()); this.evalDeclarations(); } public boolean isCompiled() { return false; } private void evalDeclarations() { /* * TODO finish evalDeclarations * * We have to sort and evaluate in the rough order * - exports * - imports * - types * - implicits * - values */ for (Object expr : declExprs) { Object decl = Rewriting.topLevelRewriter().rewrite((Seq<Pattern>) expr); Object val = interpreter.eval(decl, interpreter.getStandardContext(), values, this); } } } /** * Represents an unfinished left-side computation, such as destructuring. * * Evaluating left-side expression may result in a LeftCont instance, * which is typically handled separately by the evaluator. */ interface LeftCont { /** * Invoke this continuation, passing a right-side value for further * processing. */ public void invoke(Object value, Env<Symbol, Object> frame); public void invoke(Object value, Env<Symbol, Object> frame, boolean matching); } abstract class AbstractLeftCont implements LeftCont { private boolean matching = false; public void invoke(Object value, Env<Symbol, Object> frame, boolean matching) { this.matching = matching; this.invoke(value, frame); } protected void finish(Object key, Object val, Env<Symbol, Object> frame) throws BindingError { if (key instanceof LeftCont) { ((LeftCont) key).invoke(val, frame, this.matching); } else { if (this.matching && !(Interpreter.shouldBind(key))) { Interpreter.match(val, key); } else { try { if (!key.equals(VitryRuntime.WILDCARD)) frame.define((Symbol) key, val); } catch (ClassCastException e) { Interpreter.throwAssignment(key); } } } } } final class UnaryCont extends AbstractLeftCont { private final InvertibleFunction structor; private final Object key; public UnaryCont(InvertibleFunction structor, Object key) { this.structor = structor; this.key = key; } public void invoke(Object val, Env<Symbol, Object> frame) { Object v = structor.applyVarInverse(val).head(); finish(key, v, frame); } } final class TypeCont extends AbstractLeftCont { private final Object left; private final Object right; public TypeCont(Object left, Object right) { this.left = left; this.right = right; } public void invoke(Object val, Env<Symbol, Object> frame) { Interpreter.match(val, right); finish(left, val, frame); } } final class ApplyCont extends AbstractLeftCont { private final InvertibleFunction fn; private final Seq<?> params; private final Context context; private final Env<Symbol, Object> frame; private Module module; private final Interpreter interpr; public ApplyCont(InvertibleFunction fn, Seq<?> args, Context context, Env<Symbol, Object> frame, Module module, Interpreter interpr) { this.fn = fn; this.params = args; this.context = context; this.frame = frame; this.module = module; this.interpr = interpr; } public void invoke(Object value, Env<Symbol, Object> frame) { Seq<?> args = fn.applyVarInverse(value); Iterator<?> par = params.iterator(); Iterator<?> arg = args.iterator(); while (par.hasNext() && arg.hasNext()) { Object key = interpr.eval(par.next(), context, this.frame, module); Object val = arg.next(); finish(key, val, frame); } if (par.hasNext() || arg.hasNext()) { TypeError.throwWrongCount(value); } } }