| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.weex.el.parse; |
| |
| import java.lang.reflect.Array; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| /** |
| * Created by furture on 2017/8/28. |
| */ |
| public class Operators { |
| |
| |
| public static Object dot(Token left, Token right, Object context){ |
| if(left == null || right == null){ |
| return null; |
| } |
| Object leftValue = left.execute(context); |
| if(leftValue == null){ |
| return null; |
| } |
| Object value = null; |
| if(right.getType() != Token.TYPE_IDENTIFIER){ |
| Object identifter = right.execute(context); |
| if(identifter instanceof Double){ |
| identifter = ((Double) identifter).intValue(); |
| } |
| String key = identifter == null ? "" : identifter.toString().trim(); |
| value = Operators.el(leftValue, key); |
| }else{ |
| value = right.execute(leftValue); |
| } |
| if(value != null){ |
| return value; |
| } |
| return specialKey(leftValue, right.getToken()); |
| } |
| |
| /** |
| * get key's value on object |
| * */ |
| public static Object el(Object context, String key){ |
| if(context == null){ |
| return null; |
| } |
| // TODO |
| // if(context instanceof CellRenderContext){ |
| // if(WXEnvironment.isApkDebugable()){ |
| // throw new IllegalArgumentException("rong context CellRenderContext, you should pass it's stack"); |
| // } |
| // context = ((CellRenderContext) context).stack; |
| // } |
| if(context instanceof ArrayStack){ |
| ArrayStack stack = (ArrayStack) context; |
| for(int index=stack.size()-1; index >= 0; index--){ |
| Object value = stack.get(index); |
| if(value instanceof Map){ |
| Map map = (Map) value; |
| if(map.containsKey(key)){ |
| return map.get(key); |
| } |
| } |
| } |
| } |
| if(context instanceof Stack){ |
| Stack stack = (Stack) context; |
| for(int index=stack.size()-1; index >= 0; index--){ |
| Object value = stack.get(index); |
| if(value instanceof Map){ |
| Map map = (Map) value; |
| if(map.containsKey(key)){ |
| return map.get(key); |
| } |
| } |
| } |
| } |
| |
| if(context instanceof Map){ |
| return ((Map) context).get(key); |
| } |
| |
| if(context instanceof List){ |
| List list = (List) context; |
| try{ |
| return list.get(Integer.parseInt(key)); |
| }catch (Exception e){} |
| } |
| if(context.getClass().isArray()){ |
| try{ |
| return Array.get(context, Integer.parseInt(key)); |
| }catch (Exception e){} |
| } |
| return null; |
| } |
| |
| public static Object specialKey(Object leftValue, String key){ |
| if("length".equals(key)){ |
| if(leftValue instanceof CharSequence){ |
| return ((CharSequence) leftValue).length(); |
| } |
| if(leftValue instanceof Map){ |
| return ((Map) leftValue).size(); |
| } |
| if(leftValue instanceof Map){ |
| return ((Map) leftValue).size(); |
| } |
| if(leftValue instanceof List){ |
| return ((List) leftValue).size(); |
| } |
| if(leftValue.getClass().isArray()){ |
| return Array.getLength(leftValue); |
| } |
| } |
| return null; |
| } |
| |
| public static Object plus(Token left, Token right, Object context){ |
| Object leftValue = null; |
| Object rightValue = null; |
| if(left != null){ |
| leftValue = left.execute(context); |
| } |
| if(right != null){ |
| rightValue = right.execute(context); |
| } |
| if(leftValue instanceof CharSequence || rightValue instanceof CharSequence){ |
| if(leftValue == null){ |
| return rightValue; |
| } |
| return leftValue.toString() + (rightValue == null ? "" : rightValue.toString()); |
| } |
| if(leftValue instanceof Number || rightValue instanceof Number){ |
| return getNumber(leftValue) + getNumber(rightValue); |
| } |
| if(leftValue == null && rightValue == null){ |
| return null; |
| } |
| if(leftValue == null){ |
| return rightValue.toString(); |
| } |
| return leftValue.toString() + (rightValue == null ? "" : rightValue.toString()); |
| } |
| |
| |
| public static Object sub(Token left, Token right, Object context){ |
| Object leftValue = null; |
| Object rightValue = null; |
| if(left != null){ |
| leftValue = left.execute(context); |
| } |
| if(right != null){ |
| rightValue = right.execute(context); |
| } |
| return getNumber(leftValue) - getNumber(rightValue); |
| } |
| |
| public static Object div(Token left, Token right, Object context){ |
| Object leftValue = null; |
| Object rightValue = null; |
| if(left != null){ |
| leftValue = left.execute(context); |
| } |
| if(right != null){ |
| rightValue = right.execute(context); |
| } |
| return getNumber(leftValue)/getNumber(rightValue); |
| } |
| |
| public static Object mul(Token left, Token right, Object context){ |
| Object leftValue = null; |
| Object rightValue = null; |
| if(left != null){ |
| leftValue = left.execute(context); |
| } |
| if(right != null){ |
| rightValue = right.execute(context); |
| } |
| return getNumber(leftValue)*getNumber(rightValue); |
| } |
| |
| public static Object mod(Token left, Token right, Object context){ |
| Object leftValue = null; |
| Object rightValue = null; |
| if(left != null){ |
| leftValue = left.execute(context); |
| } |
| if(right != null){ |
| rightValue = right.execute(context); |
| } |
| return (getNumber(leftValue))%(getNumber(rightValue)); |
| } |
| |
| /** |
| * condition expression |
| * */ |
| public static Object condition(Token selfs, Token first, Token second, Object context){ |
| boolean value = false; |
| if(selfs != null){ |
| value = isTrue(selfs.execute(context)); |
| } |
| if(value){ |
| if(first != null){ |
| return first.execute(context); |
| } |
| }else{ |
| if(second != null){ |
| return second.execute(context); |
| } |
| } |
| return null; |
| } |
| |
| |
| /** |
| * is token value is true |
| * */ |
| public static boolean tokenTrue(Token selfs, Object context) { |
| if(selfs == null){ |
| return false; |
| } |
| Object value = selfs.execute(context); |
| return isTrue(value); |
| } |
| |
| /** |
| * get token number |
| * */ |
| public static double tokenNumber(Token self, Object context) { |
| if(self == null){ |
| return 0; |
| } |
| Object value = self.execute(context); |
| return getNumber(value); |
| } |
| |
| |
| |
| /** |
| * isEquls operation |
| * */ |
| public static boolean isEquals(Token left, Token right, Object context){ |
| if(left == null && right == null){ |
| return true; |
| } |
| Object leftValue = null; |
| if(left != null){ |
| leftValue = left.execute(context); |
| } |
| Object rightValue = null; |
| if(right != null) { |
| rightValue = right.execute(context); |
| } |
| if(leftValue == null){ |
| if(rightValue == null){ |
| return true; |
| } |
| if(rightValue instanceof CharSequence){ |
| if(isEmpty(rightValue.toString())){ |
| return true; |
| } |
| } |
| return false; |
| } |
| if(rightValue == null){ |
| if(isEmpty(leftValue.toString())){ |
| return true; |
| } |
| return false; |
| } |
| if(leftValue instanceof Number){ |
| if(rightValue instanceof Number){ |
| return ((Number) leftValue).doubleValue() == ((Number) rightValue).doubleValue(); |
| } |
| return ((Number) leftValue).doubleValue() == getNumber(rightValue); |
| } |
| if(rightValue instanceof Number){ |
| return getNumber(leftValue) == ((Number) rightValue).doubleValue(); |
| } |
| if(leftValue instanceof CharSequence |
| || rightValue instanceof CharSequence){ |
| return leftValue.toString().trim().equals(rightValue.toString().trim()); |
| } |
| return leftValue.equals(rightValue); |
| } |
| |
| |
| /** |
| * check whether value is true |
| * */ |
| public static boolean isTrue(Object value){ |
| if(value == null){ |
| return false; |
| } |
| if(value instanceof Number){ |
| return ((Number) value).doubleValue() != 0; |
| } |
| String bool = value.toString().trim(); |
| if("false".equals(bool) |
| || "undefined".equals(bool) |
| || "null".equals(bool)){ |
| return false; |
| } |
| if(isEmpty(bool)){ |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * check String value is empty |
| * */ |
| public static boolean isEmpty(String value){ |
| if (value == null){ |
| return true; |
| } |
| for(int i=0; i<value.length(); i++){ |
| if(value.charAt(i) != ' '){ |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| /** |
| * get number |
| * */ |
| public static double getNumber(Object value){ |
| if(value == null){ |
| return 0; |
| } |
| if(value instanceof Number){ |
| return ((Number) value).doubleValue(); |
| } |
| try{ |
| return Double.parseDouble(value.toString()); |
| }catch (Exception e){return 0;} |
| } |
| |
| public static boolean isOpEnd(String op){ |
| return isOpEnd(op.charAt(0)); |
| } |
| /** |
| * op end, has none operation, should not enter operator stack. |
| * */ |
| public static boolean isOpEnd(char op){ |
| if(op == BRACKET_END |
| || op == ARRAY_END |
| || op == SPACE |
| || op == ARRAY_SEPRATOR){ |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * is not |
| * */ |
| public static boolean isDot(String opStr){ |
| char op = opStr.charAt(0); |
| return op == DOT || op == ARRAY_START; |
| } |
| |
| |
| |
| |
| public static final char BRACKET_END = ')'; |
| public static final String BRACKET_END_STR = ")"; |
| public static final char BRACKET_START = '('; |
| public static final String BRACKET_START_STR = "("; |
| public static final char QUOTE = '"'; |
| public static final char SINGLE_QUOTE = '\''; |
| public static final char DOT = '.'; |
| public static final String DOT_STR = "."; |
| public static final char ARRAY_START = '['; |
| public static final String ARRAY_START_STR = "["; |
| public static final char ARRAY_SEPRATOR = ','; |
| public static final String ARRAY_SEPRATOR_STR = ","; |
| public static final char ARRAY_END = ']'; |
| public static final String ARRAY_END_STR = "]"; |
| public static final String SPACE_STR = " "; |
| public static final char SPACE = ' '; |
| public static final char BLOCK_START = '{'; |
| public static final String BLOCK_START_STR = "{"; |
| public static final char BLOCK_END = '}'; |
| public static final String BLOCK_END_STR = "}"; |
| public static final char DOLLAR = '$'; |
| public static final String DOLLAR_STR = "$"; |
| |
| /** |
| * condition |
| * */ |
| public static final char CONDITION_IF = '?'; |
| public static final String CONDITION_IF_STRING = "?"; |
| public static final char CONDITION_IF_MIDDLE = ':'; |
| |
| |
| |
| /** |
| * match |
| * */ |
| public static final String PLUS ="+"; |
| public static final String SUB = "-"; |
| public static final String MUL = "*"; |
| public static final String DIV = "/"; |
| public static final String MOD = "%"; |
| |
| |
| |
| public static final String AND = "&&"; |
| public static final String OR = "||"; |
| /** |
| * and operator |
| * */ |
| public static final String EQUAL = "==="; |
| public static final String EQUAL2 = "=="; |
| public static final String NOT_EQUAL = "!=="; |
| public static final String NOT_EQUAL2 = "!="; |
| public static final String AND_NOT = "!"; |
| |
| |
| public static final String G = ">"; |
| public static final String GE = ">="; |
| public static final String LE = "<="; |
| public static final String L = "<"; |
| |
| |
| |
| |
| |
| /** |
| * https://github.com/jquery/esprima/blob/master/src/parser.ts |
| * */ |
| public static Map<String, Integer> OPERATORS_PRIORITY = new HashMap<>(); |
| static { |
| OPERATORS_PRIORITY.put(BLOCK_END_STR, 0); |
| OPERATORS_PRIORITY.put(BRACKET_END_STR, 0); |
| OPERATORS_PRIORITY.put(SPACE_STR, 0); |
| OPERATORS_PRIORITY.put(ARRAY_SEPRATOR_STR, 0); |
| OPERATORS_PRIORITY.put(ARRAY_END_STR, 0); |
| |
| |
| OPERATORS_PRIORITY.put(OR, 1); |
| OPERATORS_PRIORITY.put(AND, 1); |
| |
| OPERATORS_PRIORITY.put(EQUAL, 2); |
| OPERATORS_PRIORITY.put(EQUAL2, 2); |
| OPERATORS_PRIORITY.put(NOT_EQUAL, 2); |
| OPERATORS_PRIORITY.put(NOT_EQUAL2, 2); |
| |
| OPERATORS_PRIORITY.put(G, 7); |
| OPERATORS_PRIORITY.put(GE, 7); |
| OPERATORS_PRIORITY.put(L, 7); |
| OPERATORS_PRIORITY.put(LE, 8); |
| |
| OPERATORS_PRIORITY.put(PLUS, 9); |
| OPERATORS_PRIORITY.put(SUB, 9); |
| OPERATORS_PRIORITY.put(MUL, 10); |
| OPERATORS_PRIORITY.put(DIV, 10); |
| OPERATORS_PRIORITY.put(MOD, 10); |
| OPERATORS_PRIORITY.put(AND_NOT, 11); |
| |
| OPERATORS_PRIORITY.put(DOT_STR, 15); |
| |
| OPERATORS_PRIORITY.put(ARRAY_START_STR, 16); |
| |
| |
| OPERATORS_PRIORITY.put(BRACKET_START_STR, 17); |
| OPERATORS_PRIORITY.put(BLOCK_START_STR, 17); |
| |
| |
| } |
| |
| |
| public static final Map<String,Object> KEYWORDS = new HashMap<>(); |
| static { |
| KEYWORDS.put("null", null); |
| KEYWORDS.put("true", Boolean.TRUE); |
| KEYWORDS.put("false", Boolean.FALSE); |
| KEYWORDS.put("undefined", null); |
| } |
| |
| } |