1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting.language;
18 
19 import com.googlecode.android_scripting.rpc.MethodDescriptor;
20 import com.googlecode.android_scripting.rpc.ParameterDescriptor;
21 
22 import java.util.HashMap;
23 import java.util.Map;
24 
25 /**
26  * Represents the programming language supported by the SL4A.
27  *
28  */
29 public class Language {
30 
31   private final static Map<Character, String> AUTO_CLOSE_MAP = buildAutoCloseMap('[', "[]", '{',
32       "{}", '(', "()", '\'', "''", '"', "\"\"");
33 
34   /** Returns the initial template for newly created script. */
getContentTemplate()35   public String getContentTemplate() {
36     StringBuilder content = new StringBuilder(getImportStatement());
37     if (content.length() != 0) {
38       content.append('\n');
39     }
40     content.append(getRpcReceiverDeclaration(getDefaultRpcReceiver()));
41     return content.toString();
42   }
43 
44   /** Returns the Android package import statement. */
getImportStatement()45   protected String getImportStatement() {
46     return "";
47   }
48 
49   /** Returns the RPC receiver declaration. */
getRpcReceiverDeclaration(String rpcReceiver)50   protected String getRpcReceiverDeclaration(String rpcReceiver) {
51     return "";
52   }
53 
54   /** Returns the default RPC receiver name. */
getDefaultRpcReceiver()55   protected String getDefaultRpcReceiver() {
56     return "droid";
57   }
58 
59   /**
60    * Returns the string containing opening and closing tokens if the input is an opening token.
61    * Returns {@code null} otherwise.
62    */
autoClose(char token)63   public String autoClose(char token) {
64     return AUTO_CLOSE_MAP.get(token);
65   }
66 
67   /** Returns the RPC call text with given parameter values. */
getRpcText(String content, MethodDescriptor rpc, String[] values)68   public final String getRpcText(String content, MethodDescriptor rpc, String[] values) {
69     return getMethodCallText(getRpcReceiverName(content), rpc.getName(),
70         rpc.getParameterValues(values));
71   }
72 
73   /** Returns the RPC receiver found in the given script. */
getRpcReceiverName(String content)74   protected String getRpcReceiverName(String content) {
75     return getDefaultRpcReceiver();
76   }
77 
78   /** Returns the method call text in the language. */
getMethodCallText(String receiver, String method, ParameterDescriptor[] parameters)79   protected String getMethodCallText(String receiver, String method,
80       ParameterDescriptor[] parameters) {
81     StringBuilder result =
82         new StringBuilder().append(getApplyReceiverText(receiver)).append(getApplyOperatorText())
83             .append(method).append(getLeftParametersText());
84     String separator = "";
85     for (ParameterDescriptor parameter : parameters) {
86       result.append(separator).append(getValueText(parameter));
87       separator = getParameterSeparator();
88     }
89     result.append(getRightParametersText());
90 
91     return result.toString();
92   }
93 
94   /** Returns the apply receiver text. */
getApplyReceiverText(String receiver)95   protected String getApplyReceiverText(String receiver) {
96     return receiver;
97   }
98 
99   /** Returns the apply operator text. */
getApplyOperatorText()100   protected String getApplyOperatorText() {
101     return ".";
102   }
103 
104   /** Returns the text to the left of the parameters. */
getLeftParametersText()105   protected String getLeftParametersText() {
106     return "(";
107   }
108 
109   /** Returns the text to the right of the parameters. */
getRightParametersText()110   protected String getRightParametersText() {
111     return ")";
112   }
113 
114   /** Returns the parameter separator text. */
getParameterSeparator()115   protected String getParameterSeparator() {
116     return ", ";
117   }
118 
119   /** Returns the text of the quotation. */
getQuote()120   protected String getQuote() {
121     return "\"";
122   }
123 
124   /** Returns the text of the {@code null} value. */
getNull()125   protected String getNull() {
126     return "null";
127   }
128 
129   /** Returns the text of the {{@code true} value. */
getTrue()130   protected String getTrue() {
131     return "true";
132   }
133 
134   /** Returns the text of the false value. */
getFalse()135   protected String getFalse() {
136     return "false";
137   }
138 
139   /** Returns the parameter value suitable for code generation. */
getValueText(ParameterDescriptor parameter)140   protected String getValueText(ParameterDescriptor parameter) {
141     if (parameter.getValue() == null) {
142       return getNullValueText();
143     } else if (parameter.getType().equals(String.class)) {
144       return getStringValueText(parameter.getValue());
145     } else if (parameter.getType().equals(Boolean.class)) {
146       return getBooleanValueText(parameter.getValue());
147     } else {
148       return parameter.getValue();
149     }
150   }
151 
152   /** Returns the null value suitable for code generation. */
getNullValueText()153   private String getNullValueText() {
154     return getNull();
155   }
156 
157   /** Returns the string parameter value suitable for code generation. */
getStringValueText(String value)158   protected String getStringValueText(String value) {
159     // TODO(igorkarp): do not quote expressions once they could be detected.
160     return getQuote() + value + getQuote();
161   }
162 
163   /** Returns the boolean parameter value suitable for code generation. */
getBooleanValueText(String value)164   protected String getBooleanValueText(String value) {
165     if (value.equals(Boolean.TRUE.toString())) {
166       return getTrue();
167     } else if (value.equals(Boolean.FALSE.toString())) {
168       return getFalse();
169     } else {
170       // If it is neither true nor false it is must be an expression.
171       return value;
172     }
173   }
174 
buildAutoCloseMap(char c1, String s1, char c2, String s2, char c3, String s3, char c4, String s4, char c5, String s5)175   private static Map<Character, String> buildAutoCloseMap(char c1, String s1, char c2, String s2,
176       char c3, String s3, char c4, String s4, char c5, String s5) {
177     Map<Character, String> map = new HashMap<Character, String>(5);
178     map.put(c1, s1);
179     map.put(c2, s2);
180     map.put(c3, s3);
181     map.put(c4, s4);
182     map.put(c5, s5);
183     return map;
184   }
185 }
186