001package com.randomnoun.common.jessop.lang; 002 003/* (c) 2016 randomnoun. All Rights Reserved. This work is licensed under a 004 * BSD Simplified License. ( http://www.randomnoun.com/bsd-simplified.html ) 005 */ 006 007import java.util.ArrayList; 008import java.util.List; 009 010import org.apache.log4j.Logger; 011 012import com.randomnoun.common.jessop.AbstractJessopScriptBuilder; 013import com.randomnoun.common.jessop.JessopScriptBuilder; 014 015public class LispJessopScriptBuilder extends AbstractJessopScriptBuilder implements JessopScriptBuilder { 016 017 Logger logger = Logger.getLogger(LispJessopScriptBuilder.class); 018 int outputLine = 1; // current line number in the target script; 019 int lastScriptletLine = 1; // the last line number of the last scriptlet (used for suppressEol) 020 021 public LispJessopScriptBuilder() { 022 } 023 private void skipToLine(int line) { 024 while (outputLine < line) { print("\n"); } 025 } 026 private void print(String s) { 027 // logger.info("** PRINT " + s); 028 pw.print(s); 029 for (int i=0; i<s.length(); i++) { 030 if (s.charAt(i)=='\n') { outputLine++; } 031 } 032 } 033 034 035 private static List<String> escapeLisp(String string) { 036 // lisp doesn't appear to have an inline escape syntax. so that's terrific, isn't it. 037 // instead, you need to put in ~a placeholders which are then filled by 038 // (code-char #x000d) parameters to the format function, or in abcl, a possibly-nonstandard 039 // '#\\U000D parameter. 040 041 // also, '~' characters need to be doubled-up. 042 List<String> result = new ArrayList<String>(); 043 result.add(""); 044 045 StringBuilder sb = new StringBuilder(string.length()); 046 //String escapeChars = "\u0007" + "\u0008" + "\u000f" + "\n" + "\r" + "\u0009" + "\u000b" + "\u001b" + "\\" + "\""; 047 //String backslashChars = "abfnrtve\\\""; 048 for (int i = 0; i<string.length(); i++) { 049 char ch = string.charAt(i); 050 if (ch=='~') { 051 sb.append("~~"); 052 } else if (ch=='\\') { 053 sb.append("\\\\"); 054 } else if (ch=='"') { 055 sb.append("\\\""); 056 } else if (ch>=32 && ch<=127) { 057 sb.append(ch); 058 } else { 059 sb.append("~a"); 060 String hex = Long.toString(ch, 16); 061 result.add("'#\\U" + "0000".substring(0, 4-hex.length()) + hex); 062 } 063 } 064 result.set(0, sb.toString()); 065 return result; 066 } 067 068 @Override 069 public void emitText(int line, String s) { 070 //if (outputLine == line) { print ("; "); } 071 skipToLine(line); 072 s = suppressEol(s, declarations.isSuppressEol() && lastScriptletLine == line); 073 List<String> formatParams = escapeLisp(s); 074 print("(format t \"" + formatParams.get(0) + "\""); 075 for (int i=1; i<formatParams.size(); i++) { 076 print(" " + formatParams.get(i)); 077 } 078 print(")"); 079 lastScriptletLine = 0; // don't suppress eols on this line 080 } 081 @Override 082 public void emitExpression(int line, String s) { 083 //if (outputLine == line) { print ("; "); } 084 skipToLine(line); 085 print("(format t \"~a\" " + s + ")"); // 'aesthetically' print the value of s 086 lastScriptletLine = 0; // don't suppress eols on this line 087 } 088 @Override 089 public void emitScriptlet(int line, String s) { 090 // if (outputLine == line) { print ("; "); } 091 skipToLine(line); 092 print(s); 093 lastScriptletLine = line; 094 for (int i=0; i<s.length(); i++) { if (s.charAt(i)=='\n') { lastScriptletLine++; } } 095 } 096 @Override 097 public String getLanguage() { 098 return "lisp"; 099 } 100 @Override 101 public String getDefaultScriptEngineName() { 102 return "ABCL"; 103 } 104 @Override 105 public String getDefaultExceptionConverterClassName() { 106 // return "com.randomnoun.common.jessop.engine.JRubyExceptionConverter"; 107 return null; 108 } 109 110 111 112}