3
* Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
* Code distributed by Google as part of the polymer project is also
8
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
13
import * as estree from 'estree';
14
import {LiteralValue} from './descriptors';
16
// useful tool to visualize AST: http://esprima.org/demo/parse.html
19
* converts literal: {"type": "Literal", "value": 5, "raw": "5" }
22
function literalToValue(literal: estree.Literal): LiteralValue {
27
* converts unary to string
29
function unaryToValue(unary: estree.UnaryExpression):string {
30
var argValue = expressionToValue(unary.argument);
31
if (argValue === undefined)
33
return unary.operator + argValue;
37
* converts identifier to its value
38
* identifier { "type": "Identifier", "name": "Number }
40
function identifierToValue(identifier: estree.Identifier):string {
41
return identifier.name;
45
* Function is a block statement.
47
function functionDeclarationToValue(
48
fn: estree.FunctionDeclaration): LiteralValue {
49
if (fn.body.type == "BlockStatement")
50
return blockStatementToValue(fn.body);
53
function functionExpressionToValue(
54
fn: estree.FunctionExpression): LiteralValue {
55
if (fn.body.type == "BlockStatement")
56
return blockStatementToValue(fn.body);
59
* Block statement: find last return statement, and return its value
61
function blockStatementToValue(
62
block: estree.BlockStatement): LiteralValue {
63
for (var i=block.body.length - 1; i>= 0; i--) {
64
if (block.body[i].type === "ReturnStatement")
65
return returnStatementToValue(<estree.ReturnStatement>block.body[i]);
70
* Evaluates return's argument
72
function returnStatementToValue(ret: estree.ReturnStatement): LiteralValue {
73
return expressionToValue(ret.argument);
77
* Enclose containing values in []
79
function arrayExpressionToValue(arry: estree.ArrayExpression): string {
81
for (var i=0; i<arry.elements.length; i++) {
82
var v = expressionToValue(arry.elements[i]);
94
* Make it look like an object
96
function objectExpressionToValue(obj: estree.ObjectExpression): string {
98
for (var i=0; i<obj.properties.length; i++) {
99
var k = expressionToValue(obj.properties[i].key);
100
var v = expressionToValue(obj.properties[i].value);
105
value += '"' + k + '": ' + v;
112
* BinaryExpressions are of the form "literal" + "literal"
114
function binaryExpressionToValue(
115
member: estree.BinaryExpression): number|string {
116
if (member.operator == "+") {
117
// We need to cast to `any` here because, while it's usually not the right
118
// thing to do to use '+' on two values of a mix of types because it's
119
// unpredictable, that is what the original code we're evaluating does.
120
return <any>expressionToValue(member.left) + expressionToValue(member.right);
126
* MemberExpression references a variable with name
128
function memberExpressionToValue(member: estree.MemberExpression): string {
129
return expressionToValue(member.object) + "." + expressionToValue(member.property);
133
* Tries to get the value of an expression. Returns undefined on failure.
135
export function expressionToValue(valueExpression: estree.Node): LiteralValue {
136
switch(valueExpression.type) {
138
return literalToValue(<estree.Literal>valueExpression);
139
case 'UnaryExpression':
140
return unaryToValue(<estree.UnaryExpression>valueExpression);
142
return identifierToValue(<estree.Identifier>valueExpression);
143
case 'FunctionDeclaration':
144
return functionDeclarationToValue(<estree.FunctionDeclaration>valueExpression);
145
case 'FunctionExpression':
146
return functionExpressionToValue(<estree.FunctionExpression>valueExpression);
147
case 'ArrayExpression':
148
return arrayExpressionToValue(<estree.ArrayExpression>valueExpression);
149
case 'ObjectExpression':
150
return objectExpressionToValue(<estree.ObjectExpression>valueExpression);
152
return identifierToValue(<estree.Identifier>valueExpression);
153
case 'MemberExpression':
154
return memberExpressionToValue(<estree.MemberExpression>valueExpression);
155
case 'BinaryExpression':
156
return binaryExpressionToValue(<estree.BinaryExpression>valueExpression);
162
export var CANT_CONVERT = 'UNKNOWN';