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