001package com.randomnoun.common.jessop;
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.io.PrintWriter;
008
009import javax.script.ScriptException;
010
011/** Each target language we intend to support within jessop must have an implementation of this interface. 
012 * Developers wishing to implement this interface should use the {@link AbstractJessopScriptBuilder} abstract class.
013 * 
014 * <p>Implementations of this class should return the language it supports (and the default script engine name) via the
015 * {@link #getLanguage()} and {@link #getDefaultScriptEngineName()} methods.
016 * 
017 * <p>These values will be used to select the correct JessopScriptBuilder identified in the 
018 * <code>&lt;%@ jessop language="xxx"%&gt;</code>
019 * declaration in the jessop source file.
020 * 
021 * <p>When this class is instantiated, the caller will invoke {@link #setPrintWriter(PrintWriter)} and 
022 * {@link #setTokeniserAndDeclarations(Tokeniser, JessopDeclarations)}.
023 * 
024 * <p>As the Tokeniser parses the jessop source file, it will invoke emit() methods on this class.
025 * As these methods are called, this class should generate code in the target language via the printWriter.
026 * 
027 * <p>Care should be taken to ensure that code in the target language script is on the same line number
028 * as the corresponding code on the input script, to make error messages more developer-friendly.
029 * 
030 * @author knoxg
031 */
032public interface JessopScriptBuilder {
033        // lines are source line numbers; try to keep these intact in the generated script
034        
035        /** Returns the name of the language that this scriptBuilder can parse; e.g. "javascript" or "python2".
036         * 
037         * <p>This is used to register this JessopScriptBuilder in the registry and is used to lookup the JessopScriptBuilder
038         * from the language defined in the jessop script declaration.
039         * 
040         * @return the name of the language that this scriptBuilder can parse; e.g. "javascript" or "python2".
041         */
042        String getLanguage();                                             
043        
044        /** Returns the name of the script engine that is used to evaluate this script; e.g. "rhino" or "jython"
045         * 
046         * @return the name of the script engine that is used to evaluate this script; e.g. "rhino" or "jython"
047         */
048        String getDefaultScriptEngineName();                             
049
050        /** Returns the name of the default exceptionConverter class that should be used for the default script engine,
051         * or null if no converter is required.
052         * 
053         * <p>Changing the engine in the jessop declaration will reset the the converter to null. 
054         * 
055         * @return the name of the default exceptionConverter class that should be used for the default script engine
056         */
057        String getDefaultExceptionConverterClassName();                             
058
059        /** Returns the name of the default bindingsConverter class that should be used for the default script engine,
060         * or null if no converter is required.
061         * 
062         * <p>Changing the engine in the jessop declaration will reset the the converter to null. 
063         * 
064         * @return the name of the default bindingsConverter class that should be used for the default script engine
065         */
066        String getDefaultBindingsConverterClassName();                             
067
068        
069        /** Sets the printWriter that this class will write to during emit() methods
070         * 
071         * @param pw the printWriter that this class will write to during emit() methods
072         */
073        void setPrintWriter(PrintWriter pw);
074        
075        /** Sets the tokeniser and declaration that are in effect at the start of parsing. This allows this
076         * ScriptBuilder to switch ScriptBuilders.
077         * 
078         * @param t tokeniser that is processing the jessop source
079         * @param declarations jessop declarations that are in effect
080         */
081        void setTokeniserAndDeclarations(Tokeniser t, JessopDeclarations declarations);
082        
083        /** Called by the tokeniser and requests that this JessopScriptBuilder generate code to generate some text output.
084         * 
085         * <p>This method should escape the output and generate code that outputs this text in the implementation language.
086         *  
087         * @param line jessop source line number that begins this text output
088         * @param s the text to output; may include newlines.
089         */
090        void emitText(int line, String s);        
091        
092        /** Called by the tokeniser and requests that this JessopScriptBuilder generate code to generate some evaluated output.
093         * i.e. process a <code>&lt;%= ... %&gt;</code> expression.
094         * 
095         * <p>This method should generate the code to evaluate and output the contents of the <code>&lt;%= ... %&gt;</code> expression.
096         * 
097         * <p>This method should attempt to preserve line numbers between the jessop source file and the generated code file.
098         * 
099         * @param line jessop source line number that begins this text output.
100         * @param s the contents of the <code>&lt;%= ... %&gt;</code> expression.
101         */
102        void emitExpression(int line, String s);  // <%= ... %>
103        
104
105        /** Called by the tokeniser and requests that this JessopScriptBuilder copy the included code into the generated script.
106         * i.e. process a <code>&lt;% ... %&gt;</code> scriptlet. (The 'scriptlet' term is the term used in the JSP specification)
107         * 
108         * <p>This method should generate the same code that is contained within the <code>&lt;% ... %&gt;</code> scriptlet.
109         * 
110         * <p>This method should attempt to preserve line numbers between the jessop source file and the generated code file.
111         * 
112         * <p>This scriptlet may not be syntactically correct by itself and may require further scriptlets to function, e.g.
113         * <pre>
114         * &lt;% if (a &gt; b) { %&gt;
115         * something
116         * &lt;% } %&gt;
117         * </pre>
118         * 
119         * @param line jessop source line number that begins this scriptlet.
120         * @param s the contents of the <code>&lt;%= ... %&gt;</code> expression.
121         */
122        void emitScriptlet(int line, String s);
123
124        /** Called by the tokeniser and requests that this JessopScriptBuilder process a <code>&lt;%@ ... %&gt;</code> directive.
125         * 
126         * <p>The exact semantics of these declarations can be defined per-language, but 'jessop' declarations 
127         * should be processed by the AbstractJessopScriptBuilder, i.e. declarations that are in the form
128         * <code>&lt;%@ jessop language="xxx" %&gt;</code>
129         * 
130         * <p>Ideally, there's only one declaration, at the top of the source script.
131         * 
132         * @param line jessop source line number that begins this directive
133         * @param s the contents of the <code>&lt;%@ ... %&gt;</code> directive
134         * @throws ScriptException
135         */
136        void emitDeclaration(int line, String s) throws ScriptException; 
137
138        /** Returns the value of any jessop declarations that are in effect.
139         * 
140         * <p>Used to maintain declarations when switching JessopScriptBuilders, and to retrieve declarations after the script is built.
141         */
142        JessopDeclarations getDeclarations();
143        
144}