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}