/* --------------------------------------------------------- * * __________ D E L T A S C R I P T * * (_________() * * / === / - A fast, dynamic scripting language * * | == | - Version 4.13.11.0 * * / === / - Developed by Adam R. Nelson * * | = = | - 2011-2013 * * / === / - Distributed under GNU LGPL v3 * * (________() - http://github.com/ar-nelson/deltascript * * * * --------------------------------------------------------- */ package com.sector91.delta.script.instrs; import java.util.Iterator; import com.sector91.delta.script.DScriptErr; import com.sector91.delta.script.DScriptExecutor; import com.sector91.delta.script.objects.DS_Blank; import com.sector91.delta.script.objects.DS_Callable; import com.sector91.delta.script.objects.DS_Iterable; import com.sector91.delta.script.objects.DS_List; import com.sector91.delta.script.objects.DS_Object; import com.sector91.delta.script.objects.DS_Scope; import com.sector91.delta.script.objects.DS_Tag; final class DoInstr extends DSInstr { DoInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { DS_Object lastVal = null; for (DSInstr instr : tail) { lastVal = instr.exec(scope, executor); if (executor.returnBreak || executor.loopBreak || executor.loopContinue) break; } return lastVal; } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.DO;} } final class IfInstr extends DSInstr { IfInstr(int start, short len, String car, DSInstr[] cdr) {super(start, len, car, cdr);} @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { if (tail[0].exec(scope, executor).booleanValue()) return tail[1].exec(scope, executor); return DS_Blank.BLANK; } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.IF;} } final class CondInstr extends DSInstr { CondInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { for (int i=0; i<tail.length; i++) { final DSInstr branch = tail[i]; if (branch.tail()[0].exec(scope, executor).booleanValue()) return branch.tail()[1].exec(scope, executor); } return DS_Blank.BLANK; } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.COND;} } final class BranchInstr extends DSInstr { BranchInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { final DS_Object var = tail[0].exec(scope, executor); if (var instanceof DS_Callable) { final DS_Callable callable = (DS_Callable)var; for (int i=1; i<tail.length; i++) { final DSInstr branch = tail[i]; final DS_Object arg=branch.tail()[0].exec(scope, executor); if (branch.tail().length == 1) return arg; else if (callable.call(arg).booleanValue()) return branch.tail()[1].exec(scope, executor); } } else { for (int i=1; i<tail.length; i++) { final DSInstr branch = tail[i]; final DS_Object arg=branch.tail()[0].exec(scope, executor); if (branch.tail().length == 1) return arg; else if (var.equals(arg)) return branch.tail()[1].exec(scope, executor); } } return DS_Blank.BLANK; } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.BRANCH;} } final class LoopInstr extends DSInstr { LoopInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { DS_Object lastVal = DS_Blank.BLANK; final DSInstr loopInstr = tail[0]; while (true) { lastVal = loopInstr.exec(scope, executor); if (executor.returnBreak || executor.loopBreak) {executor.loopBreak = false; break;} if (executor.loopContinue) {executor.loopContinue = false; continue;} } return lastVal; } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.LOOP;} } final class ForInstr extends DSInstr { public final DS_Tag cachedTag; ForInstr(int start, short len, String head, DSInstr[] tail) { super(start, len, head, tail); cachedTag = DS_Tag.tag(head); } @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { DS_Object lastVal = DS_Blank.BLANK; final DS_Object seq = tail[0].exec(scope, executor); if (seq instanceof DS_Iterable) { final Iterator<DS_Object> iter = ((DS_Iterable)seq).iterator(); final DSInstr loopInstr = tail[1]; while (iter.hasNext()) { scope.setLocal(cachedTag, iter.next()); lastVal = loopInstr.exec(scope, executor); if (executor.returnBreak || executor.loopBreak) {executor.loopBreak = false; break;} if (executor.loopContinue) {executor.loopContinue = false; continue;} } } else throw new DScriptErr("Expected Iterable for loop;" + " got " + seq.getTypeName() + " instead.", DScriptErr.T_INVALID_TYPE, DScriptErr.T_NOT_ITERABLE); return lastVal; } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.FOR;} } final class ReturnInstr extends DSInstr { ReturnInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Object exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { if (executor.functionCall) { executor.returnBreak = true; return tail[0].exec(scope, executor); } else throw new DScriptErr("Cannot return outside of a" + " function."); } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.RETURN;} } final class BreakInstr extends DSInstr { BreakInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Blank exec(DS_Scope scope, DScriptExecutor executor) { executor.loopBreak = true; return DS_Blank.BLANK; } @Override public InstrType type() {return InstrType.BREAK;} } final class ContinueInstr extends DSInstr { ContinueInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Blank exec(DS_Scope scope, DScriptExecutor executor) { executor.loopContinue = true; return DS_Blank.BLANK; } @Override public InstrType type() {return InstrType.CONTINUE;} } final class ExpandInstr extends DSInstr { ExpandInstr(int start, short len, String head, DSInstr[] tail) {super(start, len, head, tail);} @Override public DS_Iterable exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { try { final DS_Object obj = tail[0].exec(scope, executor); if (obj instanceof DS_Iterable) return (DS_Iterable)obj; throw new DScriptErr("Only iterable objects may be expanded" + " with '...'; failed to expand object of type " + obj.getTypeName() + ".", this); } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} } @Override public InstrType type() {return InstrType.EXPAND;} } final class ComprehensionInstr extends DSInstr { public final DS_Tag cachedTag; ComprehensionInstr(int start, short len, String head, DSInstr[] tail) { super(start, len, head, tail); cachedTag = DS_Tag.tag(head); } @Override public DS_Iterable exec(DS_Scope scope, DScriptExecutor executor) throws DScriptErr { final DS_List iterable = new DS_List(); try { final DS_Object seq = tail[0].exec(scope, executor); if (seq instanceof DS_Iterable) { final Iterator<DS_Object> iter = ((DS_Iterable)seq).iterator(); final DSInstr loopInstr = tail[1]; while (iter.hasNext()) { scope.setLocal(cachedTag, iter.next()); DS_Object result = loopInstr.exec(scope, executor); if (executor.returnBreak || executor.loopBreak) {executor.loopBreak = false; break;} if (executor.loopContinue) {executor.loopContinue = false; continue;} iterable.add(result); } } else throw new DScriptErr("Expected Iterable for" + " comprehension; got " + seq.getTypeName() + " instead.", DScriptErr.T_INVALID_TYPE, DScriptErr.T_NOT_ITERABLE); } catch (DScriptErr ex) {throw rethrow(ex);} catch (RuntimeException ex) {throw rethrow(ex);} return iterable; } @Override public InstrType type() {return InstrType.COMPRH;} }