public List<String> getPropertyNames(){ List<String> propNames = new ArrayList<String>(); ObjectLiteral ol = (ObjectLiteral)this.getNode(); for (ObjectProperty op : ol.getElements()){ AstNode left = op.getLeft(); if (left instanceof Name){ propNames.add(((Name)left).getIdentifier()); } else if (left instanceof StringLiteral){ String identifier = ConstraintGenUtil.removeQuotes(((StringLiteral)left).toSource()); propNames.add(identifier); } else { System.err.println(left.getClass().getName() + " " + left.toSource()); throw new Error("unsupported case in getPropertyNames()"); } } return propNames; }
public static List<String> getPropertyNames(ObjectLiteral ol){ List<String> propNames = new ArrayList<String>(); for (ObjectProperty op : ol.getElements()){ AstNode left = op.getLeft(); if (left instanceof Name){ propNames.add(((Name)left).getIdentifier()); } else if (left instanceof StringLiteral){ String identifier = ConstraintGenUtil.removeQuotes(((StringLiteral)left).toSource()); propNames.add(identifier); } else { System.err.println(left.getClass().getName() + " " + left.toSource()); throw new Error("unsupported case in getPropertyNames()"); } } return propNames; }
/** * Create constraints for a map literal. */ private ITypeTerm processObjectLiteralForMap(ObjectLiteral o) { ITypeTerm expTerm = findOrCreateMapLiteralTerm(o); for (ObjectProperty prop : o.getElements()){ AstNode left = prop.getLeft(); AstNode right = prop.getRight(); if (left instanceof StringLiteral){ // for map literal o = { name_1 : exp_1, ..., name_k : exp_k } generate // a constraint |exp_i| <: MapElem(|o|) ITypeTerm mapAccessTerm = findOrCreateIndexedTerm(expTerm, o.getLineno()); ITypeTerm valTerm = processExpression(right); processCopy(right, valTerm, mapAccessTerm, o.getLineno(), (solution) -> genericTypeError("map does not have a homogenous value type", locationOf(prop)) .withNote("map value type is " + describeTypeOf(mapAccessTerm, solution)) .withNote("key " + left.toSource() + " has type " + describeTypeOf(valTerm, solution))); } } return expTerm; }
/** * conservative check that returns false only for terms that obviously do not represent methods * * TODO move this code inside ITypeTerm?? * @param t * @return */ private boolean possiblyAMethodTerm(ITypeTerm t) { if (ConstraintGenUtil.isNullUndefinedLitOrVoidOp(t)) { return false; } if (t instanceof ExpressionTerm) { ExpressionTerm et = (ExpressionTerm) t; AstNode node = et.getNode(); if (node != null) { return !(node instanceof NumberLiteral || node instanceof StringLiteral); } } return !(t instanceof ArrayLiteralTerm || t instanceof MapLiteralTerm || t instanceof ObjectLiteralTerm || t instanceof TypeConstantTerm); }
void decompile(AstNode node) { switch (node.getType()) { case Token.ARRAYLIT: decompileArrayLiteral((ArrayLiteral)node); break; case Token.OBJECTLIT: decompileObjectLiteral((ObjectLiteral)node); break; case Token.STRING: decompiler.addString(((StringLiteral)node).getValue()); break; case Token.NAME: decompiler.addName(((Name)node).getIdentifier()); break; case Token.NUMBER: decompiler.addNumber(((NumberLiteral)node).getNumber()); break; case Token.GETPROP: decompilePropertyGet((PropertyGet)node); break; case Token.EMPTY: break; case Token.GETELEM: decompileElementGet((ElementGet) node); break; case Token.THIS: decompiler.addToken(node.getType()); break; default: Kit.codeBug("unexpected token: " + Token.typeToName(node.getType())); } }
private String getDirective(AstNode n) { if (n instanceof ExpressionStatement) { AstNode e = ((ExpressionStatement) n).getExpression(); if (e instanceof StringLiteral) { return ((StringLiteral) e).getValue(); } } return null; }
private StringLiteral createStringLiteral() { int pos = ts.tokenBeg, end = ts.tokenEnd; StringLiteral s = new StringLiteral(pos, end - pos); s.setLineno(ts.lineno); s.setValue(ts.getString()); s.setQuoteCharacter(ts.getQuoteChar()); return s; }
/** * Tests if an object literal is a map by checking that * all properties are quoted. * In JavaScript, both double quotes and single quotes are * supported but for now we assume double quotes are used. * * Empty object literals are assumed to be maps. */ static boolean isMap(ObjectLiteral o){ boolean result = true; for (ObjectProperty prop : o.getElements()){ AstNode left = prop.getLeft(); result = result && (left instanceof StringLiteral); } return result; }
/** * Syntactically identify module imports */ private boolean isSyntacticModuleRequire(FunctionCall fc) { AstNode target = fc.getTarget(); if (target instanceof Name) { Name name = (Name)target; return name.getIdentifier().equals("require") && fc.getArguments().size() == 1 && fc.getArguments().get(0) instanceof StringLiteral; } else { return false; } }
/** * for string constants, returns an ITerm representing the expression. A separate * equality constraint is generated that equates that term to string */ private ITypeTerm processStringLiteral(StringLiteral n) { ITypeTerm expTerm = findOrCreateExpressionTerm(n); ITypeTerm stringConst = findOrCreateTypeTerm(StringType.make(), n.getLineno()); addTypeEqualityConstraint(expTerm, stringConst, n.getLineno(), null); return expTerm; }
/** * Find the textual name of the given node. */ @Nullable private String nameOf(final AstNode node) { if (node instanceof Name) { return ((Name) node).getIdentifier(); } else if (node instanceof PropertyGet) { PropertyGet prop = (PropertyGet) node; return String.format("%s.%s", nameOf(prop.getTarget()), nameOf(prop.getProperty())); } else if (node instanceof StringLiteral) { return ((StringLiteral) node).getValue(); } return null; }
/** * Return string literal value. */ private String stringLiteral(final AstNode node) { checkState(node instanceof StringLiteral, node, "Expected string literal only"); //noinspection ConstantConditions StringLiteral string = (StringLiteral) node; return string.getValue(); }
/** * Returns string literal or array of string literals. * * @see #stringLiteral(AstNode) * @see #arrayStringLiteral(AstNode) */ private List<String> stringLiterals(final AstNode node) { // string literal or array of string literals if (node instanceof StringLiteral) { return Collections.singletonList(stringLiteral(node)); } else if (node instanceof ArrayLiteral) { return arrayStringLiteral(node); } else { throw reportError(node, "Expected string literal or array of string literal only"); } }
protected static String safeGetString(AstNode node){ if(node.getType() == Token.STRING){ StringLiteral sl = (StringLiteral)node; return sl.getValue(); }else if(node.getType()==Token.NUMBER){ NumberLiteral nl = (NumberLiteral)node; return nl.getValue(); }else{ return node.getString(); } }
private boolean extractMethodName(AstNode node, StringBuilder sb) { if (node.getType() == Token.ADD) { InfixExpression infix = (InfixExpression) node; return extractMethodName(infix.getLeft(), sb) && extractMethodName(infix.getRight(), sb); } else if (node.getType() == Token.STRING) { sb.append(((StringLiteral) node).getValue()); return true; } else { return false; } }
private String getJavaMethod(AstNode node) { if (!(node instanceof StringLiteral)) { return null; } String str = ((StringLiteral) node).getValue(); if (!str.startsWith("$$JSO$$_")) { return null; } return str.substring("$$JSO$$_".length()); }
private Node transformString(StringLiteral node) { decompiler.addString(node.getValue()); return Node.newString(node.getValue()); }
/** * This method generates constraints for all relevant AstNodes. It delegates its work to various * processXXX() methods that handle AstNodes of type XXX. */ @Override public boolean visit(AstNode node) { if (node instanceof VariableInitializer){ processVariableInitializer(node); } else if (node instanceof ReturnStatement){ processReturnStatement((ReturnStatement)node); } else if (node instanceof ExpressionStatement){ processExpressionStatement((ExpressionStatement)node); } else if (node instanceof ForLoop){ processForLoop((ForLoop)node); } else if (node instanceof ForInLoop){ processForInLoop((ForInLoop)node); }else if (node instanceof WhileLoop){ processWhileLoop((WhileLoop)node); } else if (node instanceof DoLoop){ processDoLoop((DoLoop)node); } else if (node instanceof NewExpression){ processNewExpression((NewExpression)node); } else if (node instanceof FunctionCall){ processFunctionCall((FunctionCall)node); } else if (node instanceof ElementGet){ processElementGet((ElementGet)node); } else if (node instanceof FunctionNode){ processFunctionNode((FunctionNode)node); } else if (node instanceof IfStatement){ processIfStatement((IfStatement)node); } else if (node instanceof KeywordLiteral){ processKeywordLiteral((KeywordLiteral)node); } else if (node instanceof SwitchStatement){ processSwitchStatement((SwitchStatement)node); } else if (node instanceof SwitchCase){ processSwitchCase((SwitchCase)node); } else if ((node instanceof AstRoot) || //AstRoot: no constraints need to be generated (node instanceof BreakStatement) || //BreakStatement: no constraints need to be generated (node instanceof VariableDeclaration) || //VariableDeclaration: we generate constraints for its constituent VariableInitializer nodes (node instanceof Name) || //Name: generate constraints for complex expressions that refer to names (node instanceof NumberLiteral) || //NumberLiteral: generate constraints for complex expressions that refer to names (node instanceof StringLiteral) || //StringLiteral: generate constraints for complex expressions that refer to names (node instanceof Assignment) || // Assignment is a special case of InfixExpression (node instanceof ArrayLiteral) || (node instanceof UnaryExpression) || (node instanceof InfixExpression) || (node instanceof ConditionalExpression) || (node instanceof ParenthesizedExpression) || (node instanceof EmptyExpression) || (node instanceof ObjectLiteral) || (node instanceof EmptyStatement) || (node instanceof ContinueStatement) || (node instanceof Scope) || (node instanceof Block)){ // // occurs in programs with for loops -- nothing to be done here? /* nothing */ } else { error("unsupported node " + node.toSource().trim() + " of type: " + node.getClass().getName(), node); } return true; }
/** * Creates constraints for the subtree rooted at a designated expression node, * and returns a constraint variable corresponding to the root of the tree. */ private ITypeTerm processExpression(AstNode n){ ITypeTerm cached = theMap.get(n); if (cached != null) return cached; if (n instanceof Name){ return processVariableReference((Name)n); } else if (n instanceof NumberLiteral){ return processNumericConstant((NumberLiteral)n); } else if (n instanceof StringLiteral){ return processStringLiteral((StringLiteral)n); } else if (ConstraintGenUtil.isBooleanConstant(n)){ return processBooleanConstant(n); } else if (n instanceof UnaryExpression){ return processUnaryExpression((UnaryExpression)n); } else if (n instanceof InfixExpression){ return processInfixExpression((InfixExpression)n); } else if (n instanceof FunctionCall){ return processFunctionCallExpression((FunctionCall)n); } else if (n instanceof ArrayLiteral){ return processArrayLiteral((ArrayLiteral)n); } else if (n instanceof ElementGet){ return processElementGet((ElementGet)n); } else if (n instanceof ParenthesizedExpression) { return processParenthesizedExpression((ParenthesizedExpression)n); } else if (n instanceof ConditionalExpression) { return processConditionalExpression((ConditionalExpression)n); } else if (n instanceof ObjectLiteral) { return processObjectLiteral((ObjectLiteral)n); } else if (n instanceof KeywordLiteral){ return processKeywordLiteral((KeywordLiteral)n); } else if (n instanceof FunctionNode){ return processFunctionNode((FunctionNode)n); } else if (n instanceof EmptyExpression){ return processEmptyExpression((EmptyExpression)n); } else { System.err.println(n.toSource()); return expError("unimplemented case in findOrCreateExpressionVariable: " + n.getClass().getName(), n); } }
@Override public boolean visit(AstNode node) { boolean continueProcessing = true; // We only need to check Object Literals if (node instanceof ObjectLiteral) { List<ObjectProperty> kvProps = null; List<ObjectProperty> props = ((ObjectLiteral) node).getElements(); if (props != null) { // Walk through nodes to check if this is a root bundle with // key/value pairs embedded. for (int i = 0; i < props.size(); i++) { Node left = props.get(i).getLeft(); String name = null; if (left instanceof StringLiteral) { name = ((StringLiteral) left).getValue(); } else if (left instanceof Name) { name = ((Name) left).getIdentifier(); } else { continue; } Node right = props.get(i).getRight(); if (name.equalsIgnoreCase("root")) { // This AMD i18n bundle with "root" object // (key/value pairs) embedded. // For example, // // define({ // "root": { // "msg.hello": "Hello", // "msg.byte": "Bye" // }, // "fr": true, // "de": true // }); // right = removeParenthes(right); if (right instanceof ObjectLiteral) { kvProps = ((ObjectLiteral) right).getElements(); break; } } } } if (kvProps == null) { // This bundle contains key/value pairs in the root Object // directly. // For example, // // define({ // "msg.hello": "Hello", // "msg.byte": "Bye" // }); // kvProps = props; } // Put key/value pairs to elements for (ObjectProperty kv : kvProps) { Node propKey = kv.getLeft(); String key = null; if (propKey instanceof Name) { key = ((Name) propKey).getIdentifier(); } else if (propKey instanceof StringLiteral) { key = ((StringLiteral) propKey).getValue(); } if (key == null) { continue; } Node propVal = kv.getRight(); String val = concatStringNodes(propVal); if (val == null) { continue; } elements.put(key, val); } continueProcessing = false; } return continueProcessing; }
private boolean visit(FunctionCall call) { if (!(call.getTarget() instanceof PropertyGet)) { return true; } PropertyGet propertyGet = (PropertyGet) call.getTarget(); MethodReference methodRef = getJavaMethodSelector(propertyGet.getTarget()); if (methodRef == null || !propertyGet.getProperty().getIdentifier().equals("invoke")) { return true; } for (AstNode arg : call.getArguments()) { arg.visit(this); } MethodReader method = classSource.resolve(methodRef); if (method == null) { diagnostics.error(location, "Java method not found: {{m0}}", methodRef); return false; } int requiredParams = methodRef.parameterCount(); if (!method.hasModifier(ElementModifier.STATIC)) { ++requiredParams; } if (call.getArguments().size() != requiredParams) { diagnostics.error(location, "Invalid number of arguments for method {{m0}}. Expected: " + requiredParams + ", encountered: " + call.getArguments().size(), methodRef); } MethodReference caller = createCallbackMethod(method); MethodReference delegate = repository.methodMap.get(location.getMethod()); repository.callbackCallees.put(caller, methodRef); repository.callbackMethods.computeIfAbsent(delegate, key -> new HashSet<>()).add(caller); validateSignature(method); StringLiteral newTarget = new StringLiteral(); newTarget.setValue("$$JSO$$_" + caller); propertyGet.setTarget(newTarget); return false; }
private void print(StringLiteral node) throws IOException { writer.append(node.getQuoteCharacter()); writer.append(ScriptRuntime.escapeString(node.getValue(), node.getQuoteCharacter())); writer.append(node.getQuoteCharacter()); }
/** * Property keys in object literals can be identifiers or string literals. * This method takes an AST node that was the key of an * <code>ObjectProperty</code> and returns its value, no matter what the * concrete AST node's type. * * @param propKeyNode The AST node for the property key. * @return The property key's value. */ public static final String getPropertyName(AstNode propKeyNode) { // TODO: Does Rhino use any other node type for this? return (propKeyNode instanceof Name) ? ((Name)propKeyNode).getIdentifier() : ((StringLiteral)propKeyNode).getValue(); }