diff --git a/lib/astupdate.js b/lib/astupdate.js index b069cdf..58f9790 100644 --- a/lib/astupdate.js +++ b/lib/astupdate.js @@ -35,11 +35,7 @@ const buildExplicitCases = (patterndecls) => { } const buildDefaultCase = (funcdecl) => { - const defaultcase = { - type: 'SwitchCase', - test: null, - consequent: [] - } + const defaultcase = { type: 'SwitchCase', test: null, consequent: [] } const consequent = { type: 'ReturnStatement' } const arg = funcdecl.declarations[0].init.body consequent.argument = @@ -78,9 +74,7 @@ const isArrowFuncDecl = (decl) => { if ( declarations !== undefined && declarations[0].init.type === 'ArrowFunctionExpression' - ) { - return true - } + ) { return true } return false } diff --git a/lib/estemplate.js b/lib/estemplate.js index 2cfd03a..d6ec7ee 100644 --- a/lib/estemplate.js +++ b/lib/estemplate.js @@ -1,466 +1,458 @@ -const types = require("./operatorPrecedence"); -const notNull = require("./utilityFunctions").notNull; -const notUndefined = require("./utilityFunctions").notUndefined; -const estemplate = {}; +const types = require('./operatorPrecedence') +const notNull = require('./utilityFunctions').notNull +const notUndefined = require('./utilityFunctions').notUndefined +const estemplate = {} const extractExpr = (token) => notUndefined(token) && notNull(token) && - token.type === "ExpressionStatement" + token.type === 'ExpressionStatement' ? token.expression - : token; + : token -estemplate.ast = () => ({ - type: "Program", - body: [], - sourceType: "script", -}); +estemplate.ast = () => ({ type: 'Program', body: [], sourceType: 'script' }) estemplate.literal = (value) => ({ - type: "Literal", + type: 'Literal', value: Number(value), raw: value, - sType: "number", -}); + sType: 'number' +}) estemplate.nullLiteral = (value) => ({ - type: "Literal", + type: 'Literal', value: null, raw: value, - sType: "needsInference", -}); + sType: 'needsInference' +}) estemplate.boolLiteral = (value) => ({ - type: "Literal", - value: !(value === "false"), + type: 'Literal', + value: !(value === 'false'), raw: value, - sType: "bool", -}); + sType: 'bool' +}) estemplate.stringLiteral = (value) => ({ - type: "Literal", + type: 'Literal', value: value, raw: value, - sType: "string", -}); + sType: 'string' +}) -estemplate.identifier = (value) => ({ - type: "Identifier", - name: value, -}); +estemplate.identifier = (value) => ({ type: 'Identifier', name: value }) estemplate.regex = (regex, pattern, flags) => ({ - type: "Literal", + type: 'Literal', value: new RegExp(pattern, flags), raw: regex, regex: { pattern: pattern, - flags: flags, + flags: flags }, - sType: "regexp", -}); + sType: 'regexp' +}) estemplate.declaration = (id, val) => ({ - type: "VariableDeclaration", + type: 'VariableDeclaration', declarations: [ { - type: "VariableDeclarator", + type: 'VariableDeclarator', id, - init: extractExpr(val), - }, + init: extractExpr(val) + } ], - kind: "const", -}); + kind: 'const' +}) estemplate.letDecl = (id, val) => ({ - type: "VariableDeclaration", + type: 'VariableDeclaration', declarations: [ { - type: "VariableDeclarator", + type: 'VariableDeclarator', id, - init: extractExpr(val), - }, + init: extractExpr(val) + } ], - kind: "let", -}); + kind: 'let' +}) estemplate.funcDeclaration = (id, params, body) => ({ - type: "VariableDeclaration", + type: 'VariableDeclaration', declarations: [ { - type: "VariableDeclarator", + type: 'VariableDeclarator', id, init: { - type: "ArrowFunctionExpression", + type: 'ArrowFunctionExpression', id: null, params: params, - body: extractExpr(body) || "", + body: extractExpr(body) || '', generator: false, - expression: - body === undefined || body.type !== "BlockStatement", - }, - }, + expression: body === undefined || body.type !== 'BlockStatement' + } + } ], - kind: "const", -}); + kind: 'const' +}) estemplate.lambdaCall = (params, args, body) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "ArrowFunctionExpression", + type: 'ArrowFunctionExpression', id: null, params: params, - body: extractExpr(body) || "", + body: extractExpr(body) || '', generator: false, - expression: body === undefined || body.type !== "BlockStatement", + expression: body === undefined || body.type !== 'BlockStatement' }, - arguments: args.map(extractExpr), -}); + arguments: args.map(extractExpr) +}) estemplate.letExpression = (params, args, body) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "ArrowFunctionExpression", + type: 'ArrowFunctionExpression', id: null, params: params, - body: extractExpr(body) || "", + body: extractExpr(body) || '', generator: false, - expression: true, + expression: true }, - arguments: args.map(extractExpr), -}); + arguments: args.map(extractExpr) +}) estemplate.memberExpression = (obj, prop) => ({ - type: "ExpressionStatement", + type: 'ExpressionStatement', expression: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: extractExpr(obj), - property: extractExpr(prop), - }, -}); + property: extractExpr(prop) + } +}) estemplate.subscriptExpression = (obj, prop) => ({ - type: "ExpressionStatement", + type: 'ExpressionStatement', expression: { - type: "MemberExpression", + type: 'MemberExpression', computed: true, object: extractExpr(obj), - property: extractExpr(prop), - }, -}); + property: extractExpr(prop) + } +}) estemplate.printexpression = (args) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: { - type: "Identifier", - name: "console", + type: 'Identifier', + name: 'console' }, property: { - type: "Identifier", - name: "log", - }, + type: 'Identifier', + name: 'log' + } }, arguments: args.map((arg) => extractExpr(arg)), - sType: "IO", -}); + sType: 'IO' +}) estemplate.fnCall = (val, args) => - val.name === "print" + val.name === 'print' ? estemplate.printexpression(args) : { - type: "CallExpression", + type: 'CallExpression', callee: extractExpr(val), - arguments: args.map(extractExpr), - }; + arguments: args.map(extractExpr) + } estemplate.lambda = (params, body) => ({ - type: "ExpressionStatement", + type: 'ExpressionStatement', expression: { - type: "ArrowFunctionExpression", + type: 'ArrowFunctionExpression', id: null, params, - body: extractExpr(body) || "", + body: extractExpr(body) || '', generator: false, - expression: body === undefined || body.type !== "BlockStatement", - }, -}); + expression: body === undefined || body.type !== 'BlockStatement' + } +}) estemplate.binaryExpression = (left, op, right) => { - const opType = op === "instanceof" ? "any" : types[op].type; - if (op === "^") return binaryExpr(left, "**", right, opType); - if (op === "++") return binaryExpr(left, "+", right, opType); - if (op === "==") return binaryExpr(left, "===", right, opType); - if (op === "!=") return binaryExpr(left, "!==", right, opType); - return binaryExpr(left, op, right, opType); -}; + const opType = op === 'instanceof' ? 'any' : types[op].type + if (op === '^') return binaryExpr(left, '**', right, opType) + if (op === '++') return binaryExpr(left, '+', right, opType) + if (op === '==') return binaryExpr(left, '===', right, opType) + if (op === '!=') return binaryExpr(left, '!==', right, opType) + return binaryExpr(left, op, right, opType) +} const binaryExpr = (left, op, right, opType) => ({ - type: "BinaryExpression", + type: 'BinaryExpression', operator: op, sType: opType, left: extractExpr(left), - right: extractExpr(right), -}); + right: extractExpr(right) +}) estemplate.unaryExpression = (op, arg) => ({ - type: "UnaryExpression", + type: 'UnaryExpression', operator: op, argument: extractExpr(arg), - prefix: true, -}); + prefix: true +}) estemplate.blockStmt = (body) => ({ - type: "BlockStatement", - body: body, -}); + type: 'BlockStatement', + body: body +}) estemplate.ifthenelse = (condition, result1, result2) => ({ - type: "ExpressionStatement", + type: 'ExpressionStatement', expression: { - type: "ConditionalExpression", + type: 'ConditionalExpression', test: extractExpr(condition), consequent: extractExpr(result1), - alternate: extractExpr(result2), - }, -}); + alternate: extractExpr(result2) + } +}) estemplate.ifStmt = (predicate, consequent) => ({ - type: "IfStatement", + type: 'IfStatement', test: predicate, consequent: { - type: "BlockStatement", - body: [consequent, estemplate.returnStmt(null)], + type: 'BlockStatement', + body: [consequent, estemplate.returnStmt(null)] }, - alternate: null, -}); + alternate: null +}) estemplate.array = (elements) => ({ - type: "ArrayExpression", - elements: elements.map(extractExpr), -}); + type: 'ArrayExpression', + elements: elements.map(extractExpr) +}) estemplate.object = (value) => ({ - type: "ObjectExpression", - properties: extractExpr(value), -}); + type: 'ObjectExpression', + properties: extractExpr(value) +}) estemplate.objectProperty = (key, val) => ({ - type: "Property", + type: 'Property', key: key, computed: false, value: extractExpr(val), - kind: "init", + kind: 'init', method: false, - shorthand: false, -}); + shorthand: false +}) estemplate.comment = (type, val) => ({ type: type, - value: val, -}); + value: val +}) estemplate.ioCall = (ioFunc, args, nextParams = []) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: { - type: "Identifier", - name: "IO", + type: 'Identifier', + name: 'IO' }, - property: ioFunc, + property: ioFunc }, arguments: args.map(extractExpr), - nextParams, -}); + nextParams +}) estemplate.ioBind = (parentIO, ioCall, nextParams = []) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: parentIO, property: { - type: "Identifier", - name: "bind", - }, + type: 'Identifier', + name: 'bind' + } }, arguments: [ioCall].map(extractExpr), - nextParams, -}); + nextParams +}) estemplate.ioMap = (parentIO, pureFunc, nextParams = []) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: parentIO, property: { - type: "Identifier", - name: "map", - }, + type: 'Identifier', + name: 'map' + } }, arguments: [pureFunc].map(extractExpr), - nextParams, -}); + nextParams +}) estemplate.ioThen = (parentIO, func, ioParams) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: parentIO, property: { - type: "Identifier", - name: "then", - }, + type: 'Identifier', + name: 'then' + } }, arguments: [func].map(extractExpr), - ioParams, -}); + ioParams +}) estemplate.ioFunc = (id, args) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: { - type: "Identifier", - name: "IO", + type: 'Identifier', + name: 'IO' }, - property: id, + property: id }, - arguments: args.map(extractExpr), -}); + arguments: args.map(extractExpr) +}) estemplate.defineProp = (objID, key, val, mutable) => ({ - type: "ExpressionStatement", + type: 'ExpressionStatement', expression: { - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: { - type: "Identifier", - name: "Object", + type: 'Identifier', + name: 'Object' }, property: { - type: "Identifier", - name: "defineProperty", - }, + type: 'Identifier', + name: 'defineProperty' + } }, arguments: [ objID, key, { - type: "ObjectExpression", + type: 'ObjectExpression', properties: [ { - type: "Property", + type: 'Property', key: { - type: "Identifier", - name: "value", + type: 'Identifier', + name: 'value' }, computed: false, value: val, - kind: "init", + kind: 'init', method: false, - shorthand: false, + shorthand: false }, { - type: "Property", + type: 'Property', key: { - type: "Identifier", - name: "enumerable", + type: 'Identifier', + name: 'enumerable' }, computed: false, value: { - type: "Literal", + type: 'Literal', value: true, - raw: "true", + raw: 'true' }, - kind: "init", + kind: 'init', method: false, - shorthand: false, + shorthand: false }, { - type: "Property", + type: 'Property', key: { - type: "Identifier", - name: "writable", + type: 'Identifier', + name: 'writable' }, computed: false, value: { - type: "Literal", + type: 'Literal', value: mutable, - raw: mutable.toString(), + raw: mutable.toString() }, - kind: "init", + kind: 'init', method: false, - shorthand: false, + shorthand: false }, { - type: "Property", + type: 'Property', key: { - type: "Identifier", - name: "configurable", + type: 'Identifier', + name: 'configurable' }, computed: false, value: { - type: "Literal", + type: 'Literal', value: mutable, - raw: mutable.toString(), + raw: mutable.toString() }, - kind: "init", + kind: 'init', method: false, - shorthand: false, - }, - ], - }, - ], - }, -}); + shorthand: false + } + ] + } + ] + } +}) estemplate.returnStmt = (args) => ({ - type: "ReturnStatement", - argument: args, -}); + type: 'ReturnStatement', + argument: args +}) estemplate.defaultIOThen = (parentObj) => ({ - type: "CallExpression", + type: 'CallExpression', callee: { - type: "MemberExpression", + type: 'MemberExpression', computed: false, object: parentObj, property: { - type: "Identifier", - name: "then", - }, + type: 'Identifier', + name: 'then' + } }, arguments: [ { - type: "ArrowFunctionExpression", + type: 'ArrowFunctionExpression', id: null, params: [], body: { - type: "Literal", + type: 'Literal', value: null, - raw: "null", + raw: 'null' }, generator: false, - expression: true, - }, - ], -}); + expression: true + } + ] +}) estemplate.expression = (expr) => ({ - type: "ExpressionStatement", - expression: expr, -}); + type: 'ExpressionStatement', + expression: expr +}) /* Module Exports estemplate */ -module.exports = estemplate; +module.exports = estemplate diff --git a/lib/inbuiltMethods.js b/lib/inbuiltMethods.js index 1298f15..b90558e 100644 --- a/lib/inbuiltMethods.js +++ b/lib/inbuiltMethods.js @@ -1,308 +1,208 @@ -/** - * This file contains various methods and properties supported by the parent type. - * Also, the accepted and return types of those methods - */ - -const setValues = ( +/* This file contains various methods and properties supported by the parent type. Also, the accepted and return types of those methods */ +const setValues = (isMethod, isProp, isMutative, paramTypes, returnType) => ({ isMethod, isProp, isMutative, paramTypes, returnType -) => ({ - isMethod, - isProp, - isMutative, - paramTypes, - returnType, -}); +}) const arrayType = { - type: "array", + type: 'array', elemTypes: {}, - commonType: "needsInference", - isHomogeneous: false, -}; + commonType: 'needsInference', + isHomogeneous: false +} const inbuiltProps = { array: { - length: setValues(false, true, false, null, "number"), + length: setValues(false, true, false, null, 'number'), push: setValues(true, false, true, null, null), pop: setValues(true, false, true, null, null), shift: setValues(true, false, true, null, null), unshift: setValues(true, false, true, null, null), splice: setValues(true, false, true, null, null), - slice: setValues( - true, - false, - false, - ["number", "number"], - arrayType - ), - map: setValues(true, false, false, ["needsInference"], arrayType), - filter: setValues( - true, - false, - false, - ["needsInference"], - arrayType - ), - reduce: setValues( - true, - false, - false, - ["needsInference"], - "needsInference" - ), - includes: setValues(true, false, false, ["needsInference"], "bool"), - join: setValues(true, false, false, ["string"], "string"), - toString: setValues(true, false, false, null, "string"), - concat: setValues(true, false, false, ["array"], arrayType), + slice: setValues(true, false, false, ['number', 'number'], arrayType), + map: setValues(true, false, false, ['needsInference'], arrayType), + filter: setValues(true, false, false, ['needsInference'], arrayType), + reduce: setValues(true, false, false, ['needsInference'], 'needsInference'), + includes: setValues(true, false, false, ['needsInference'], 'bool'), + join: setValues(true, false, false, ['string'], 'string'), + toString: setValues(true, false, false, null, 'string'), + concat: setValues(true, false, false, ['array'], arrayType) }, string: { - length: setValues(false, true, false, null, "number"), + length: setValues(false, true, false, null, 'number'), splice: setValues(true, false, true, null, null), - charAt: setValues(true, false, false, ["number"], "string"), - charCodeAt: setValues(true, false, false, ["number"], "number"), - substring: setValues( - true, - false, - false, - ["number", "number"], - "string" - ), - substr: setValues( - true, - false, - false, - ["number", "number"], - "string" - ), - includes: setValues(true, false, false, ["string"], "bool"), - toUpperCase: setValues(true, false, false, null, "string"), - toLowerCase: setValues(true, false, false, null, "string"), - slice: setValues( - true, - false, - false, - ["number", "number"], - "string" - ), - trim: setValues(true, false, false, null, "string"), - trimLeft: setValues(true, false, false, null, "string"), - trimRight: setValues(true, false, false, null, "string"), - startsWith: setValues(true, false, false, ["string"], "bool"), - split: setValues(true, false, false, ["string"], arrayType), - replace: setValues( - true, - false, - false, - ["string", "string"], - "string" - ), - match: setValues(true, false, false, ["string"], "number"), - search: setValues( - true, - false, - false, - ["string", "string"], - "string" - ), - repeat: setValues(true, false, false, ["number"], "string"), + charAt: setValues(true, false, false, ['number'], 'string'), + charCodeAt: setValues(true, false, false, ['number'], 'number'), + substring: setValues(true, false, false, ['number', 'number'], 'string'), + substr: setValues(true, false, false, ['number', 'number'], 'string'), + includes: setValues(true, false, false, ['string'], 'bool'), + toUpperCase: setValues(true, false, false, null, 'string'), + toLowerCase: setValues(true, false, false, null, 'string'), + slice: setValues(true, false, false, ['number', 'number'], 'string'), + trim: setValues(true, false, false, null, 'string'), + trimLeft: setValues(true, false, false, null, 'string'), + trimRight: setValues(true, false, false, null, 'string'), + startsWith: setValues(true, false, false, ['string'], 'bool'), + split: setValues(true, false, false, ['string'], arrayType), + replace: setValues(true, false, false, ['string', 'string'], 'string'), + match: setValues(true, false, false, ['string'], 'number'), + search: setValues(true, false, false, ['string', 'string'], 'string'), + repeat: setValues(true, false, false, ['number'], 'string') }, object: { - toString: setValues(true, false, false, null, "string"), - hasOwnProperty: setValues(true, false, false, ["string"], "bool"), + toString: setValues(true, false, false, null, 'string'), + hasOwnProperty: setValues(true, false, false, ['string'], 'bool') }, regexp: { - exec: setValues(true, false, false, ["string"], "array"), + exec: setValues(true, false, false, ['string'], 'array') }, needsInference: { length: { - spec: setValues(false, true, false, null, "number"), - parentType: "needsInference", + spec: setValues(false, true, false, null, 'number'), + parentType: 'needsInference' }, push: { spec: setValues(true, false, true, null, null), - parentType: arrayType, + parentType: arrayType }, pop: { spec: setValues(true, false, true, null, null), - parentType: arrayType, + parentType: arrayType }, shift: { spec: setValues(true, false, true, null, null), - parentType: arrayType, + parentType: arrayType }, unshift: { spec: setValues(true, false, true, null, null), - parentType: arrayType, + parentType: arrayType }, splice: { spec: setValues(true, false, true, null, null), - parentType: "needsInference", + parentType: 'needsInference' }, slice: { spec: setValues( true, false, false, - ["number", "number"], - "needsInference" + ['number', 'number'], + 'needsInference' ), - parentType: "needsInference", + parentType: 'needsInference' }, map: { - spec: setValues( - true, - false, - false, - ["needsInference"], - arrayType - ), - parentType: arrayType, + spec: setValues(true, false, false, ['needsInference'], arrayType), + parentType: arrayType }, filter: { - spec: setValues( - true, - false, - false, - ["needsInference"], - arrayType - ), - parentType: arrayType, + spec: setValues(true, false, false, ['needsInference'], arrayType), + parentType: arrayType }, reduce: { - spec: setValues( - true, - false, - false, - ["needsInference"], - "needsInference" - ), - parentType: arrayType, + spec: setValues(true, false, false, ['needsInference'], 'needsInference'), + parentType: arrayType }, includes: { - spec: setValues(true, false, false, ["needsInference"], "bool"), - parentType: "needsInference", + spec: setValues(true, false, false, ['needsInference'], 'bool'), + parentType: 'needsInference' }, join: { - spec: setValues(true, false, false, ["string"], "string"), - parentType: arrayType, + spec: setValues(true, false, false, ['string'], 'string'), + parentType: arrayType }, toString: { - spec: setValues(true, false, false, null, "string"), - parentType: "needsInference", + spec: setValues(true, false, false, null, 'string'), + parentType: 'needsInference' }, concat: { - spec: setValues(true, false, false, ["array"], arrayType), - parentType: arrayType, + spec: setValues(true, false, false, ['array'], arrayType), + parentType: arrayType }, charAt: { - spec: setValues(true, false, false, ["number"], "string"), - parentType: "string", + spec: setValues(true, false, false, ['number'], 'string'), + parentType: 'string' }, charCodeAt: { - spec: setValues(true, false, false, ["number"], "number"), - parentType: "string", + spec: setValues(true, false, false, ['number'], 'number'), + parentType: 'string' }, substring: { - spec: setValues( - true, - false, - false, - ["number", "number"], - "string" - ), - parentType: "string", + spec: setValues(true, false, false, ['number', 'number'], 'string'), + parentType: 'string' }, substr: { - spec: setValues( - true, - false, - false, - ["number", "number"], - "string" - ), - parentType: "string", + spec: setValues(true, false, false, ['number', 'number'], 'string'), + parentType: 'string' }, toUpperCase: { - spec: setValues(true, false, false, null, "string"), - parentType: "string", + spec: setValues(true, false, false, null, 'string'), + parentType: 'string' }, toLowerCase: { - spec: setValues(true, false, false, null, "string"), - parentType: "string", + spec: setValues(true, false, false, null, 'string'), + parentType: 'string' }, trim: { - spec: setValues(true, false, false, null, "string"), - parentType: "string", + spec: setValues(true, false, false, null, 'string'), + parentType: 'string' }, trimLeft: { - spec: setValues(true, false, false, null, "string"), - parentType: "string", + spec: setValues(true, false, false, null, 'string'), + parentType: 'string' }, trimRight: { - spec: setValues(true, false, false, null, "string"), - parentType: "string", + spec: setValues(true, false, false, null, 'string'), + parentType: 'string' }, startsWith: { - spec: setValues(true, false, false, ["string"], "bool"), - parentType: "string", + spec: setValues(true, false, false, ['string'], 'bool'), + parentType: 'string' }, split: { - spec: setValues(true, false, false, ["string"], arrayType), - parentType: "string", + spec: setValues(true, false, false, ['string'], arrayType), + parentType: 'string' }, replace: { - spec: setValues( - true, - false, - false, - ["string", "string"], - "string" - ), - parentType: "string", + spec: setValues(true, false, false, ['string', 'string'], 'string'), + parentType: 'string' }, match: { - spec: setValues(true, false, false, ["string"], "number"), - parentType: "string", + spec: setValues(true, false, false, ['string'], 'number'), + parentType: 'string' }, search: { - spec: setValues( - true, - false, - false, - ["string", "string"], - "string" - ), - parentType: "string", + spec: setValues(true, false, false, ['string', 'string'], 'string'), + parentType: 'string' }, repeat: { - spec: setValues(true, false, false, ["number"], "string"), - parentType: "string", + spec: setValues(true, false, false, ['number'], 'string'), + parentType: 'string' }, hasOwnProperty: { - spec: setValues(true, false, false, ["string"], "bool"), - parentType: { type: "object", propTypes: {} }, - }, - }, -}; + spec: setValues(true, false, false, ['string'], 'bool'), + parentType: { type: 'object', propTypes: {} } + } + } +} const inbuiltObjects = { Math: { - type: "object", + type: 'object', propTypes: { - floor: [["number"], "number"], - }, + floor: [['number'], 'number'] + } }, console: { - type: "object", + type: 'object', propTypes: { - log: [["needsInference"], "IO"], - }, - }, -}; + log: [['needsInference'], 'IO'] + } + } +} /* Module export inbuiltProps */ -module.exports = { inbuiltProps, inbuiltObjects }; +module.exports = { inbuiltProps, inbuiltObjects } diff --git a/lib/jsFunctions.js b/lib/jsFunctions.js index 8b4aa88..5dd6d27 100644 --- a/lib/jsFunctions.js +++ b/lib/jsFunctions.js @@ -5,56 +5,56 @@ const jsFunctions = { Number: { - type: "function", - paramTypes: ["string"], - returnType: "number", + type: 'function', + paramTypes: ['string'], + returnType: 'number' }, require: { - type: "function", - paramTypes: ["string"], - returnType: "needsInference", + type: 'function', + paramTypes: ['string'], + returnType: 'needsInference' }, parseInt: { - type: "function", - paramTypes: ["needsInference"], - returnType: "number", + type: 'function', + paramTypes: ['needsInference'], + returnType: 'number' }, parseFloat: { - type: "function", - paramTypes: ["needsInference"], - returnType: "number", + type: 'function', + paramTypes: ['needsInference'], + returnType: 'number' }, String: { - type: "function", - paramTypes: ["needsInference"], - returnType: "string", + type: 'function', + paramTypes: ['needsInference'], + returnType: 'string' }, Object: { - type: "function", - paramTypes: ["needsInference"], - returnType: "object", + type: 'function', + paramTypes: ['needsInference'], + returnType: 'object' }, RegExp: { - type: "function", - paramTypes: ["string"], - returnType: "object", + type: 'function', + paramTypes: ['string'], + returnType: 'object' }, Date: { - type: "function", + type: 'function', paramTypes: [], - returnType: "string", + returnType: 'string' }, isFinite: { - type: "function", - paramTypes: ["number"], - returnType: "boolean", + type: 'function', + paramTypes: ['number'], + returnType: 'boolean' }, isNaN: { - type: "function", - paramTypes: ["number"], - returnType: "boolean", - }, -}; + type: 'function', + paramTypes: ['number'], + returnType: 'boolean' + } +} /* Module exports jsFunctions */ -module.exports = jsFunctions; +module.exports = jsFunctions diff --git a/lib/languageConstructs.js b/lib/languageConstructs.js index 49840a8..59a07e1 100644 --- a/lib/languageConstructs.js +++ b/lib/languageConstructs.js @@ -21,7 +21,7 @@ const languageConstructs = { console: true, return: true, delete: true, - defineProp: true, -}; + defineProp: true +} -module.exports = languageConstructs; +module.exports = languageConstructs diff --git a/lib/parser.js b/lib/parser.js index f656822..af76912 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -114,12 +114,7 @@ const formBinaryExpr = (opStack, operandStack, input, rest) => { opStack.pop() ] const expr = estemplate.binaryExpression(left, op, right) - return formBinaryExpr( - opStack, - operandStack.concat(expr), - input, - rest - ) + return formBinaryExpr(opStack, operandStack.concat(expr), input, rest) } const handlePrecAssoc = (opStack, operandStack, current, rest) => { @@ -127,10 +122,8 @@ const handlePrecAssoc = (opStack, operandStack, current, rest) => { const currentHasHigher = precedence(current) > precedence(opStackTop) const currentHasLower = precedence(current) < precedence(opStackTop) const currentHasEqual = !currentHasLower && !currentHasHigher - const isRightAssociative = - currentHasEqual && associativity(current) === 'R' - const isLeftAssociative = - currentHasEqual && associativity(current) === 'L' + const isRightAssociative = currentHasEqual && associativity(current) === 'R' + const isLeftAssociative = currentHasEqual && associativity(current) === 'L' if (currentHasHigher || isRightAssociative) { return binaryExprParser( @@ -166,13 +159,8 @@ const binaryExprParser = ( let [current, rest] = [null, null] // initialize current and rest of the string to null switch (expect) { case 'operand': { - const maybeOperand = parser.any( - fnCallParser, - expressionParser - )(input); - [current, rest] = notNull(maybeOperand) - ? maybeOperand - : [null, null] + const maybeOperand = parser.any(fnCallParser, expressionParser)(input); + [current, rest] = notNull(maybeOperand) ? maybeOperand : [null, null] return isNull(current) ? null : binaryExprParser( @@ -184,9 +172,7 @@ const binaryExprParser = ( } case 'operator': { const maybeOperator = binaryOperatorParser(input); - [current, rest] = notNull(maybeOperator) - ? maybeOperator - : [null, null] + [current, rest] = notNull(maybeOperator) ? maybeOperator : [null, null] return notNull(current) ? handlePrecAssoc(opStack, operandStack, current, rest) : formBinaryExpr(opStack, operandStack, input, rest) @@ -209,10 +195,7 @@ const ifExprParser = (input) => )(input), (val, rest) => { const [, condition, , , consequent, , , alternate] = val - return [ - estemplate.ifthenelse(condition, consequent, alternate), - rest - ] + return [estemplate.ifthenelse(condition, consequent, alternate), rest] } ) @@ -237,12 +220,7 @@ const letParamsParser = (str, letIdArray = [], letLiteralArray = []) => const letExpressionParser = (input) => maybe( - parser.all( - letParser, - letParamsParser, - inParser, - valueParser - )(input), + parser.all(letParser, letParamsParser, inParser, valueParser)(input), (val, rest) => { const [, [letIdArray, letLiteralArray], , expr] = val const letExpr = estemplate.letExpression( @@ -256,22 +234,14 @@ const letExpressionParser = (input) => /* Helper functions for lambdaParser */ const paramsParser = (input, idArray = []) => - maybe( - parser.all(nonReservedIdParser, spaceParser)(input), - (val, rest) => { - const [val_] = val - return paramsParser(rest, idArray.concat(val_)) - } - ) || [idArray, input] + maybe(parser.all(nonReservedIdParser, spaceParser)(input), (val, rest) => { + const [val_] = val + return paramsParser(rest, idArray.concat(val_)) + }) || [idArray, input] const lambdaParser = (input) => maybe( - parser.all( - slashParser, - paramsParser, - thinArrowParser, - valueParser - )(input), + parser.all(slashParser, paramsParser, thinArrowParser, valueParser)(input), (val, rest) => { const [, params, , expr] = val return [estemplate.lambda(params, expr), rest] @@ -295,8 +265,7 @@ const argsParser = (input, argArray = []) => { const calleeParser = (input) => parser.any(memberExprParser, nonReservedIdParser)(input) -const fnArgsParser = (input) => - parser.any(emptyArgsParser, argsParser)(input) +const fnArgsParser = (input) => parser.any(emptyArgsParser, argsParser)(input) const fnCallParser = (input) => maybe( @@ -440,11 +409,7 @@ const objectParser = (input) => { /* Helper functions for memberExprParser */ const formMemberExpression = (input, obj) => { - const prop = parser.any( - dotParser, - subscriptParser, - identifierParser - )(input) + const prop = parser.any(dotParser, subscriptParser, identifierParser)(input) if (isNull(prop)) return [obj, input] const [exp, rest] = prop if (exp.isSubscript) { @@ -484,22 +449,14 @@ const subscriptParser = (input) => const memberExprParser = (input) => maybe( - parser.any( - arrayParser, - nonReservedIdParser, - parenthesesParser - )(input), + parser.any(arrayParser, nonReservedIdParser, parenthesesParser)(input), (val, rest) => { const obj = val const result = formMemberExpression(rest, obj) let [memExpr, _rest] = result memExpr = - memExpr.type === 'ExpressionStatement' - ? memExpr.expression - : memExpr - return memExpr.type === 'MemberExpression' - ? [memExpr, _rest] - : null + memExpr.type === 'ExpressionStatement' ? memExpr.expression : memExpr + return memExpr.type === 'MemberExpression' ? [memExpr, _rest] : null } ) @@ -516,12 +473,7 @@ const defineStmtParser = (input) => )(input), (val, rest) => { const [, , objID, , key, , value] = val - const definePropStmt = estemplate.defineProp( - objID, - key, - value, - false - ) + const definePropStmt = estemplate.defineProp(objID, key, value, false) return [definePropStmt, rest] } ) @@ -531,19 +483,14 @@ const defineStmtParser = (input) => const makeBlock = (mapBody, cbBody) => estemplate.blockStmt(mapBody.stmts.concat(cbBody)) -const makeReturnArray = (val) => - estemplate.returnStmt(estemplate.array(val)) +const makeReturnArray = (val) => estemplate.returnStmt(estemplate.array(val)) /* IO parsers */ // DOM statements inside parenthesis const parensDOMStmt = (input) => maybe( - parser.all( - openParensParser, - maybeDOMStmt, - closeParensParser - )(input), + parser.all(openParensParser, maybeDOMStmt, closeParensParser)(input), (val, rest) => { const [, expr] = val return [expr, rest] @@ -613,20 +560,12 @@ const ioStmtParser = ( makeBlock( mapBody, makeReturnArray( - parentObj.nextParams.concat( - mapBody.propagate.concat(ioFunc) - ) + parentObj.nextParams.concat(mapBody.propagate.concat(ioFunc)) ) ) ) - parentObj.nextParams = parentObj.nextParams.concat( - mapBody.propagate - ) - const val_ = estemplate.ioBind( - parentObj, - callBack, - parentObj.nextParams - ) + parentObj.nextParams = parentObj.nextParams.concat(mapBody.propagate) + const val_ = estemplate.ioBind(parentObj, callBack, parentObj.nextParams) return [val_, rest] }) @@ -637,11 +576,7 @@ const ioStmtParser = ( const noArgsCallParser = (input) => maybe( parser.all( - parser.any( - memberExprParser, - parenthesesParser, - nonReservedIdParser - ), + parser.any(memberExprParser, parenthesesParser, nonReservedIdParser), spaceParser, openParensParser, closeParensParser @@ -663,9 +598,7 @@ const maybeDOMStmt = (input) => parser.all(domMethodParser, spaceParser, argsParser)(input), (val, rest) => { const [domFunc, , args] = val - const callExpr = estemplate.expression( - estemplate.fnCall(domFunc, args) - ) + const callExpr = estemplate.expression(estemplate.fnCall(domFunc, args)) const expr = rest.str.startsWith('\n') || /^()()$/.test(rest.str) ? estemplate.expression(callExpr) @@ -684,12 +617,7 @@ const maybeBindStmt = (input) => parser.all( bindIDParser, reverseBindParser, - parser.any( - fnCallParser, - maybeDOMStmt, - ioFuncName, - nonReservedIdParser - ) + parser.any(fnCallParser, maybeDOMStmt, ioFuncName, nonReservedIdParser) )(input) const isIOorFuncCall = (maybeIOFunc) => { @@ -739,17 +667,12 @@ const formBindStmt = ( ) => { const cbParams = parentObj.nextParams const callBack = isEmptyArr(mapBody.stmts) - ? estemplate.lambda( - cbParams, - estemplate.array(cbParams.concat(cbBody)) - ) + ? estemplate.lambda(cbParams, estemplate.array(cbParams.concat(cbBody))) : estemplate.lambda( cbParams, makeBlock( mapBody, - makeReturnArray( - cbParams.concat(mapBody.propagate).concat(cbBody) - ) + makeReturnArray(cbParams.concat(mapBody.propagate).concat(cbBody)) ) ) parentObj = estemplate.ioBind(parentObj, callBack, cbParams) @@ -795,14 +718,7 @@ const bindStmt = (maybeBind, parentObj, bindBody, mapBody) => { args, nextParams ) - return formBindStmt( - cbBody, - parentObj, - nextParams, - rest, - bindBody, - mapBody - ) + return formBindStmt(cbBody, parentObj, nextParams, rest, bindBody, mapBody) } /* letStmtParser in IO */ @@ -829,19 +745,16 @@ const letParamsIOParser = (str, letStmtsArray = [], nextParams = []) => let var1 = val1, var2 = val2 */ const maybeLetStmt = (input, parentObj, bindBody, mapBody) => - maybe( - parser.all(letParser, letParamsIOParser)(input), - (val, rest) => { - const [, [letDeclarations, propagatedVals]] = val - mapBody.stmts = mapBody.stmts.concat(letDeclarations) - mapBody.propagate = - !isEmptyArr(mapBody.propagate) && - mapBody.propagate[0].name === propagatedVals[0].name - ? mapBody.propagate.concat(propagatedVals.slice(1)) - : mapBody.propagate.concat(propagatedVals) - return ioBodyParser(rest, parentObj, bindBody, mapBody) - } - ) + maybe(parser.all(letParser, letParamsIOParser)(input), (val, rest) => { + const [, [letDeclarations, propagatedVals]] = val + mapBody.stmts = mapBody.stmts.concat(letDeclarations) + mapBody.propagate = + !isEmptyArr(mapBody.propagate) && + mapBody.propagate[0].name === propagatedVals[0].name + ? mapBody.propagate.concat(propagatedVals.slice(1)) + : mapBody.propagate.concat(propagatedVals) + return ioBodyParser(rest, parentObj, bindBody, mapBody) + }) /* letStmtParser ends here */ @@ -909,9 +822,7 @@ const maybeStmt = (maybeVal, rest, parentObj, bindBody, mapBody) => { if (Array.isArray(handler)) { const [ioFunc, , args] = handler handler = ioFunc - handlerBody = estemplate.defaultIOThen( - estemplate.ioCall(handler, args) - ) + handlerBody = estemplate.defaultIOThen(estemplate.ioCall(handler, args)) } const val = getPredicate(methodName, value)(handlerBody) mapBody.stmts = mapBody.stmts.concat(val) @@ -922,9 +833,7 @@ const maybeStmt = (maybeVal, rest, parentObj, bindBody, mapBody) => { /* Handler function for delete and defineProp */ const makeMap = (parentObj, mapBody) => { const nextParams = parentObj.nextParams - const returnVal = makeReturnArray( - nextParams.concat(mapBody.propagate) - ) + const returnVal = makeReturnArray(nextParams.concat(mapBody.propagate)) const cbBody = makeBlock(mapBody, returnVal) const callBack = estemplate.lambda(nextParams, cbBody) const val = estemplate.ioMap(parentObj, callBack, nextParams) @@ -946,12 +855,7 @@ const maybeDefineStmt = (input, parentObj, bindBody, mapBody) => )(input), (val, rest) => { const [, , objID, , key, , value] = val - const definePropTmpl = estemplate.defineProp( - objID, - key, - value, - true - ) + const definePropTmpl = estemplate.defineProp(objID, key, value, true) mapBody.stmts = mapBody.stmts.concat(definePropTmpl) return ioBodyParser(rest, parentObj, bindBody, mapBody) } @@ -966,10 +870,7 @@ const maybeDeleteStmt = (input, parentObj, bindBody, mapBody) => )(input), (val, rest) => { const [deleteKeyword, , objProp] = val - const deleteTmpl = estemplate.unaryExpression( - deleteKeyword, - objProp - ) + const deleteTmpl = estemplate.unaryExpression(deleteKeyword, objProp) mapBody.stmts = mapBody.stmts.concat(deleteTmpl) return ioBodyParser(rest, parentObj, bindBody, mapBody) } @@ -979,20 +880,14 @@ const maybeDeleteStmt = (input, parentObj, bindBody, mapBody) => /* make final statement */ const getCbBody = (bindBody, parentObj) => { if (bindBody.length === 0) { - if (parentObj.type === 'Identifier') { - return estemplate.fnCall(parentObj, []) - } + if (parentObj.type === 'Identifier') { return estemplate.fnCall(parentObj, []) } return parentObj } const callBack = estemplate.lambda( parentObj.nextParams, estemplate.array([estemplate.fnCall(bindBody[0], [])]) ) - const val = estemplate.ioBind( - parentObj, - callBack, - parentObj.nextParams - ) + const val = estemplate.ioBind(parentObj, callBack, parentObj.nextParams) val.nextParams = parentObj.nextParams return getCbBody(bindBody.slice(1), val) } @@ -1042,13 +937,7 @@ const makeFinalStmt = (input, rest, parentObj, bindBody, mapBody) => { } /* final statement ends here */ -const maybeFinalStmt = ( - finalStmt, - input, - parentObj, - bindBody, - mapBody -) => { +const maybeFinalStmt = (finalStmt, input, parentObj, bindBody, mapBody) => { let [, rest] = finalStmt const result = spaceParser(rest) if (isNull(result)) { @@ -1078,11 +967,7 @@ const maybeIOCallStmt = (maybeIOCall, parentObj, bindBody, mapBody) => { const val = ioID return isEmptyArr(mapBody.stmts) ? ioBodyParser(rest, parentObj, bindBody.concat(val), mapBody) - : ioBodyParser( - rest, - makeMap(parentObj, mapBody), - bindBody.concat(val) - ) + : ioBodyParser(rest, makeMap(parentObj, mapBody), bindBody.concat(val)) } /* @@ -1157,17 +1042,11 @@ const ioParser = (input) => parser.all( nonReservedIdParser, equalSignParser, - parser.any( - doParser, - noArgsCallParser, - ioStmtParser, - nonReservedIdParser - ) + parser.any(doParser, noArgsCallParser, ioStmtParser, nonReservedIdParser) )(input), (initIO, rest) => { const [doID, , maybeDo] = initIO - const isId = - notUndefined(maybeDo.type) && maybeDo.type === 'Identifier' + const isId = notUndefined(maybeDo.type) && maybeDo.type === 'Identifier' const idNotMain = isId && doID.name !== 'main' if (idNotMain) return null const isFunc = @@ -1227,11 +1106,7 @@ const valueParser = (input) => const declParser = (input) => maybe( - parser.all( - nonReservedIdParser, - equalSignParser, - valueParser - )(input), + parser.all(nonReservedIdParser, equalSignParser, valueParser)(input), (val, rest) => { const [id, , value] = val return [estemplate.declaration(id, value), rest] @@ -1268,10 +1143,7 @@ const fnDeclParser = (input) => )(input), (val, rest) => { const [funcID, paramsArr, , body] = val - return [ - estemplate.funcDeclaration(funcID, paramsArr, body), - rest - ] + return [estemplate.funcDeclaration(funcID, paramsArr, body), rest] } ) diff --git a/lib/parserObject.js b/lib/parserObject.js index 21b80cd..506eedf 100644 --- a/lib/parserObject.js +++ b/lib/parserObject.js @@ -1,78 +1,74 @@ -const utils = require("./utilityFunctions"); +const utils = require('./utilityFunctions') /* Utility Functions */ -const { isUndefined, maybe, returnRest } = utils; +const { isUndefined, maybe, returnRest } = utils -/** - * Parser factory. Used to create parsers - * parser.regex - creates parser for given regex - * parser.bind - applies monadic bind on parsers - * parser.all - All parsers supplied MUST match - * parser.any - ANY ONE of the parsers need match - */ +/* + Parser factory. Used to create parsers + parser.regex - creates parser for given regex + parser.bind - applies monadic bind on parsers + parser.all - All parsers supplied MUST match + parser.any - ANY ONE of the parsers need match +*/ -const parser = { unParsed: { line: 1, column: 0, regex: [] } }; +const parser = { unParsed: { line: 1, column: 0, regex: [] } } // To keep track of how much of the input has been parsed const updateParsed = (val, name) => { - const maxLine = parser.unParsed.line < val.line; // if existing parsed line is less than newly parsed line + const maxLine = parser.unParsed.line < val.line // if existing parsed line is less than newly parsed line const maxColumn = - parser.unParsed.line === val.line && - parser.unParsed.column < val.column; // if lines match then compare column - const currentExpr = val.str.split("\n")[0]; + parser.unParsed.line === val.line && parser.unParsed.column < val.column // if lines match then compare column + const currentExpr = val.str.split('\n')[0] if (maxLine) { - [ + ;[ parser.unParsed.str, parser.unParsed.line, parser.unParsed.column, - parser.unParsed.regex, - ] = [currentExpr, val.line, val.column, []]; + parser.unParsed.regex + ] = [currentExpr, val.line, val.column, []] } if (maxColumn) { - if (isUndefined(parser.unParsed.str)) - parser.unParsed.str = currentExpr; - if (name !== "spaceRegex" && name !== "equalSignRegex") { - parser.unParsed.regex.push(name); - } - parser.unParsed.column = val.column; + if (isUndefined(parser.unParsed.str)) parser.unParsed.str = currentExpr + if (name !== 'spaceRegex' && name !== 'equalSignRegex') { parser.unParsed.regex.push(name) } + parser.unParsed.column = val.column } -}; +} parser.regex = (regex) => (src) => maybe(regex().exec(src.str), (m, val, rest) => { const result = returnRest(val, src, rest, { - name: "column", - value: val.length, - }); - updateParsed(result[1], regex.name); - return result; - }); + name: 'column', + value: val.length + }) + updateParsed(result[1], regex.name) + return result + }) parser.bind = (mv, mf) => (input) => - maybe(mv(input), (val, rest) => mf(val)(rest)); + maybe(mv(input), (val, rest) => mf(val)(rest)) parser.all = (...parsers) => - (src) => { - let rest = src; - const values = []; - for (const parser of parsers) { - const result = parser(rest); - if (result === null) return null; - values.push(result[0]); - rest = result[1]; + (src) => { + let rest = src + const values = [] + for (const parser of parsers) { + const result = parser(rest) + if (result === null) return null + values.push(result[0]) + rest = result[1] + } + return [values, rest] } - return [values, rest]; - }; parser.any = (...parsers) => - (...src) => { - for (const parser of parsers) { - const result = parser(...src); - if (result !== null) return result; + (...src) => { + for (const parser of parsers) { + const result = parser(...src) + if (result !== null) return result + } + return null } - return null; - }; /* Module exports the parser object along with all its methods */ -module.exports = parser; +module.exports = parser diff --git a/lib/typeInference.js b/lib/typeInference.js index 11b98c6..b3d2609 100644 --- a/lib/typeInference.js +++ b/lib/typeInference.js @@ -1,198 +1,173 @@ -/** - * Type inference and type checker for the AST. - * IO blocks are termed as type 'IO' and whenever the type could not be inferred, - * it is set to 'needsInference' globalTypesObj keeps track of all identifiers - * and their types, function declarations and their accepted and return types. - */ - -const inbuiltPropSpec = require("./inbuiltMethods").inbuiltProps; -const inbuiltObjects = require("./inbuiltMethods").inbuiltObjects; -const jsFunctions = require("./jsFunctions"); -const isEmptyObj = require("./utilityFunctions").isEmptyObj; -const globalTypesObj = {}; +/* + Type inference and type checker for the AST + IO blocks are termed as type 'IO' and whenever the type could not be inferred it is set to 'needsInference' + globalTypesObj keeps track of all identifiers and their types, function declarations and their accepted and return types +*/ +const inbuiltPropSpec = require('./inbuiltMethods').inbuiltProps +const inbuiltObjects = require('./inbuiltMethods').inbuiltObjects +const jsFunctions = require('./jsFunctions') +const isEmptyObj = require('./utilityFunctions').isEmptyObj +const globalTypesObj = {} const isFunction = (id, typeObj) => typeObj[id] !== undefined && typeObj[id] !== null && - typeObj[id].type === "function"; + typeObj[id].type === 'function' const getParamReturnTypes = (id, typeObj) => [ typeObj[id.name].paramTypes, - typeObj[id.name].returnType, -]; + typeObj[id.name].returnType +] -const isEmpty = (arr) => arr.toString() === ""; +const isEmpty = (arr) => arr.toString() === '' const returnIdentifierType = (id, typeObj) => { - if (isFunction(id.name, typeObj)) - return getParamReturnTypes(id, typeObj); - return typeObj[id.name]; -}; + if (isFunction(id.name, typeObj)) return getParamReturnTypes(id, typeObj) + return typeObj[id.name] +} const identifierType = (id, localTypeObj) => { - if (localTypeObj[id.name] !== undefined) { - return returnIdentifierType(id, localTypeObj); - } - if (globalTypesObj[id.name] !== undefined) { - return returnIdentifierType(id, globalTypesObj); - } - return null; -}; + if (localTypeObj[id.name] !== undefined) { return returnIdentifierType(id, localTypeObj) } + if (globalTypesObj[id.name] !== undefined) { return returnIdentifierType(id, globalTypesObj) } + return null +} -const literalType = (literal) => literal.sType; +const literalType = (literal) => literal.sType const unaryExprType = (expr) => { - if (expr.operator === "typeof") return "string"; - if (expr.operator === "!" && exprType(expr.argument) === "bool") - return "bool"; - if (expr.operator === "-" && exprType(expr.argument) === "number") { - return "number"; - } - return null; -}; + if (expr.operator === 'typeof') return 'string' + if (expr.operator === '!' && exprType(expr.argument) === 'bool') return 'bool' + if (expr.operator === '-' && exprType(expr.argument) === 'number') { return 'number' } + return null +} const getType = (expr, expectedType, localTypeObj, id) => { if (expr !== undefined) { - const type = exprType(expr, localTypeObj, id); - return type === expectedType || expectedType === "bool" + const type = exprType(expr, localTypeObj, id) + return type === expectedType || expectedType === 'bool' ? type - : type === "needsInference" - ? type - : null; + : type === 'needsInference' + ? type + : null } -}; +} const checkTypes = (expr, expectedType, localTypeObj, id) => { - let typeLeft = getType(expr.left, expectedType, localTypeObj, id); - let typeRight = getType(expr.right, expectedType, localTypeObj, id); - if (typeLeft === "needsInference" && typeRight !== "needsInference") { - assignTypeToUninferredIdentifier(expr, typeRight, localTypeObj); - typeLeft = typeRight; - } - if (typeLeft !== "needsInference" && typeRight === "needsInference") { - assignTypeToUninferredIdentifier(expr, typeLeft, localTypeObj); - typeRight = typeLeft; + let typeLeft = getType(expr.left, expectedType, localTypeObj, id) + let typeRight = getType(expr.right, expectedType, localTypeObj, id) + if (typeLeft === 'needsInference' && typeRight !== 'needsInference') { + assignTypeToUninferredIdentifier(expr, typeRight, localTypeObj) + typeLeft = typeRight } - if (typeLeft === "needsInference" && typeRight === "needsInference") { - return expectedType; + if (typeLeft !== 'needsInference' && typeRight === 'needsInference') { + assignTypeToUninferredIdentifier(expr, typeLeft, localTypeObj) + typeRight = typeLeft } + if (typeLeft === 'needsInference' && typeRight === 'needsInference') { return expectedType } return typeLeft === typeRight && - (typeLeft === expectedType || expectedType === "bool") + (typeLeft === expectedType || expectedType === 'bool') ? expectedType - : null; -}; + : null +} -const assignTypeToUninferredIdentifier = ( - expr, - inferredType, - localTypeObj -) => { - if (isEmptyObj(localTypeObj)) return localTypeObj; - const [left, right] = [expr.left.name, expr.right.name]; - if (left !== undefined && localTypeObj[left] === "needsInference") { - localTypeObj[left] = inferredType; - } - if (right !== undefined && localTypeObj[right] === "needsInference") { - localTypeObj[right] = inferredType; - } -}; +const assignTypeToUninferredIdentifier = (expr, inferredType, localTypeObj) => { + if (isEmptyObj(localTypeObj)) return localTypeObj + const [left, right] = [expr.left.name, expr.right.name] + if (left !== undefined && localTypeObj[left] === 'needsInference') { localTypeObj[left] = inferredType } + if (right !== undefined && localTypeObj[right] === 'needsInference') { localTypeObj[right] = inferredType } +} const binaryExprType = (expr, localTypeObj, id) => { - const assumedType = expr.sType; - if (assumedType !== "bool") { - assignTypeToUninferredIdentifier(expr, assumedType, localTypeObj); - } - return checkTypes(expr, assumedType, localTypeObj, id); -}; + const assumedType = expr.sType + if (assumedType !== 'bool') { assignTypeToUninferredIdentifier(expr, assumedType, localTypeObj) } + return checkTypes(expr, assumedType, localTypeObj, id) +} const compareArrayProps = (array1, array2) => { const flag = array1.isHomogeneous === array2.isHomogeneous && - array1.commonType === array2.commonType; + array1.commonType === array2.commonType return flag ? { - type: "array", + type: 'array', elemTypes: {}, commonType: array1.commonType, - isHomogeneous: array1.isHomogeneous, + isHomogeneous: array1.isHomogeneous } - : null; -}; + : null +} const conditionalExprType = (expr, localTypeObj, id) => { - if (exprType(expr.test, localTypeObj, id) !== "bool") return null; + if (exprType(expr.test, localTypeObj, id) !== 'bool') return null let [consequentType, alternateType] = [ exprType(expr.consequent, localTypeObj, id), - exprType(expr.alternate, localTypeObj, id), - ]; + exprType(expr.alternate, localTypeObj, id) + ] if ( - consequentType === "needsInference" && - alternateType !== "needsInference" && + consequentType === 'needsInference' && + alternateType !== 'needsInference' && alternateType !== null ) { - consequentType = alternateType; - localTypeObj[expr.consequent.name] = alternateType; + consequentType = alternateType + localTypeObj[expr.consequent.name] = alternateType } if ( - consequentType !== "needsInference" && - alternateType === "needsInference" && + consequentType !== 'needsInference' && + alternateType === 'needsInference' && consequentType !== null ) { - alternateType = consequentType; - localTypeObj[expr.alternate.name] = consequentType; + alternateType = consequentType + localTypeObj[expr.alternate.name] = consequentType } - if (consequentType === null || alternateType === null) return null; - if ( - consequentType.type !== undefined && - alternateType.type !== undefined - ) { - const match = consequentType.type === alternateType.type; + if (consequentType === null || alternateType === null) return null + if (consequentType.type !== undefined && alternateType.type !== undefined) { + const match = consequentType.type === alternateType.type if (match) { - return consequentType.type === "array" + return consequentType.type === 'array' ? compareArrayProps(consequentType, alternateType) - : consequentType.type === "object" - ? { type: "object", propTypes: {} } - : null; + : consequentType.type === 'object' + ? { type: 'object', propTypes: {} } + : null } - return null; + return null } - return consequentType === alternateType ? consequentType : null; -}; + return consequentType === alternateType ? consequentType : null +} const mapArgTypeToParams = (params, args, localTypeObj, id) => { return params.map((param, index) => args[index].sType === undefined ? exprType(args[index], localTypeObj, id) : args[index].sType - ); -}; + ) +} const makeParamTypeArray = (localTypeObj) => { - const paramTypes = []; + const paramTypes = [] for (const identifier in localTypeObj) { if (localTypeObj[identifier].type === undefined) { - paramTypes.push(localTypeObj[identifier]); + paramTypes.push(localTypeObj[identifier]) } else { - paramTypes.push(localTypeObj[identifier].type); + paramTypes.push(localTypeObj[identifier].type) } } - return paramTypes; -}; + return paramTypes +} const arrowFunctionExprType = (expr, localTypeObj, id) => { - const [params, body] = [expr.params, expr.body]; + const [params, body] = [expr.params, expr.body] params.forEach((param) => { - localTypeObj[param.name] = "needsInference"; - }); - const returnType = exprType(body, localTypeObj, id); + localTypeObj[param.name] = 'needsInference' + }) + const returnType = exprType(body, localTypeObj, id) return returnType === null ? null : { - type: "function", + type: 'function', paramTypes: makeParamTypeArray(localTypeObj), - returnType, - }; -}; + returnType + } +} const matchArgTypesToAcceptedTypes = ( args, @@ -201,395 +176,339 @@ const matchArgTypesToAcceptedTypes = ( id ) => { const _args = args.map((arg, index) => { - let type = exprType(arg, localTypeObj, id); - if (type !== null && type.type !== undefined) type = type.type; + let type = exprType(arg, localTypeObj, id) + if (type !== null && type.type !== undefined) type = type.type if ( - type === "needsInference" && - acceptedTypes[index] !== "needsInference" + type === 'needsInference' && + acceptedTypes[index] !== 'needsInference' ) { - type = acceptedTypes[index]; - if (arg.type === "Identifier") localTypeObj[arg.name] = type; + type = acceptedTypes[index] + if (arg.type === 'Identifier') localTypeObj[arg.name] = type } return ( - type === "needsInference" || + type === 'needsInference' || type === acceptedTypes[index] || - (type !== null && acceptedTypes[index] === "needsInference") - ); - }); - return isEmpty(_args) - ? true - : _args.reduce((type1, type2) => type1 === type2); -}; + (type !== null && acceptedTypes[index] === 'needsInference') + ) + }) + return isEmpty(_args) ? true : _args.reduce((type1, type2) => type1 === type2) +} const checkForRecursion = (callee, id, localTypeObj, args) => { if (callee === id) { /* recursive call */ - args = args.map((e) => exprType(e, localTypeObj, id)); + args = args.map((e) => exprType(e, localTypeObj, id)) if ( globalTypesObj[id] !== undefined && - globalTypesObj[id].type === "function" && - globalTypesObj[id].returnType !== "needsInference" - ) { - return { flag: false }; - } - args = args.map((arg) => (arg.type !== undefined ? arg.type : arg)); + globalTypesObj[id].type === 'function' && + globalTypesObj[id].returnType !== 'needsInference' + ) { return { flag: false } } + args = args.map((arg) => (arg.type !== undefined ? arg.type : arg)) globalTypesObj[id] = { - type: "function", + type: 'function', paramTypes: args, - returnType: "needsInference", - }; - return { flag: true, paramTypes: args }; + returnType: 'needsInference' + } + return { flag: true, paramTypes: args } } - return { flag: false }; -}; + return { flag: false } +} -const getFunctionType = (calleeName) => jsFunctions[calleeName]; +const getFunctionType = (calleeName) => jsFunctions[calleeName] const callExprType = (expr, localTypeObj = {}, id) => { if ( - expr.callee.type === "Identifier" && + expr.callee.type === 'Identifier' && globalTypesObj[expr.callee.name] === undefined ) { - const calleeName = expr.callee.name; - globalTypesObj[calleeName] = getFunctionType(calleeName); + const calleeName = expr.callee.name + globalTypesObj[calleeName] = getFunctionType(calleeName) } const [params, body, args] = [ expr.callee.params, expr.callee.body, - expr.arguments, - ]; - if (expr.sType !== undefined) return expr.sType; // if call has type already set + expr.arguments + ] + if (expr.sType !== undefined) return expr.sType // if call has type already set if ( params !== undefined && body !== undefined && (!isEmptyObj(localTypeObj) || expr.callee.id === null) ) { - const typesOfParams = mapArgTypeToParams( - params, - args, - localTypeObj, - id - ); - args.map((arg) => exprType(arg, localTypeObj, id)); + const typesOfParams = mapArgTypeToParams(params, args, localTypeObj, id) + args.map((arg) => exprType(arg, localTypeObj, id)) params.map((param, index) => { - localTypeObj[param.name] = typesOfParams[index]; - return param; - }); - return exprType(body, localTypeObj, id); - } - const isRecursive = checkForRecursion( - expr.callee.name, - id, - localTypeObj, - args - ); - let result = exprType(expr.callee, localTypeObj, id); - if (result === null) return null; - if (expr.callee.id === null) - result = [result.paramTypes, result.returnType]; - let [acceptedTypes, returnType] = result; - if (isRecursive.flag) acceptedTypes = isRecursive.paramTypes; + localTypeObj[param.name] = typesOfParams[index] + return param + }) + return exprType(body, localTypeObj, id) + } + const isRecursive = checkForRecursion(expr.callee.name, id, localTypeObj, args) + let result = exprType(expr.callee, localTypeObj, id) + if (result === null) return null + if (expr.callee.id === null) result = [result.paramTypes, result.returnType] + let [acceptedTypes, returnType] = result + if (isRecursive.flag) acceptedTypes = isRecursive.paramTypes const match = matchArgTypesToAcceptedTypes( args, acceptedTypes, localTypeObj, id - ); - return match ? returnType : null; -}; + ) + return match ? returnType : null +} const reduceTypes = (typesArr, localTypeObj, id) => { const reducedType = typesArr .map((e) => { - if (e.type !== undefined && e.type === "Identifier") { - return { id: e.name, type: exprType(e, localTypeObj, id) }; - } - return { id: null, type: exprType(e, localTypeObj, id) }; + if (e.type !== undefined && e.type === 'Identifier') { return { id: e.name, type: exprType(e, localTypeObj, id) } } + return { id: null, type: exprType(e, localTypeObj, id) } }) .reduce((exp1, exp2) => { if ( - exp1.type === "needsInference" && - exp2.type !== "needsInference" && + exp1.type === 'needsInference' && + exp2.type !== 'needsInference' && exp2.type !== null ) { - localTypeObj[exp1.id] = exp2.type; - exp1.type = exp2.type; + localTypeObj[exp1.id] = exp2.type + exp1.type = exp2.type } - if ( - exp2.type === "needsInference" && - exp1.type !== "needsInference" - ) { - exp2.type = exp1.type; - localTypeObj[exp2.id] = exp1.type; + if (exp2.type === 'needsInference' && exp1.type !== 'needsInference') { + exp2.type = exp1.type + localTypeObj[exp2.id] = exp1.type } - if ( - typeof exp1.type === "object" && - typeof exp2.type === "object" - ) { - return exp1.type.type === exp2.type.type ? exp1.type : false; + if (typeof exp1.type === 'object' && typeof exp2.type === 'object') { + return exp1.type.type === exp2.type.type ? exp1.type : false } - return exp1.type === exp2.type ? exp1 : false; - }); - return reducedType !== false ? reducedType.type : false; -}; + return exp1.type === exp2.type ? exp1 : false + }) + return reducedType !== false ? reducedType.type : false +} const switchStatementType = (body, localTypeObj, id) => { - const cases = body.cases; - const [initialPattern] = cases; + const cases = body.cases + const [initialPattern] = cases let [returnType, acceptedType] = [ initialPattern.consequent[0].argument, - initialPattern.test, - ].map((exp) => exprType(exp, localTypeObj, id)); - const paramId = body.discriminant.name; - localTypeObj[paramId] = acceptedType; + initialPattern.test + ].map((exp) => exprType(exp, localTypeObj, id)) + const paramId = body.discriminant.name + localTypeObj[paramId] = acceptedType const [caseArgArray, caseTestArray] = [ cases.map((c) => c.consequent[0].argument), cases.map((c) => c.test === null - ? { type: "Identifier", name: paramId, sType: acceptedType } + ? { type: 'Identifier', name: paramId, sType: acceptedType } : c.test - ), - ]; - const checkTestType = reduceTypes(caseTestArray, localTypeObj, id); - const checkArgsType = reduceTypes(caseArgArray, localTypeObj, id); - if (returnType === "needsInference") returnType = checkArgsType; + ) + ] + const checkTestType = reduceTypes(caseTestArray, localTypeObj, id) + const checkArgsType = reduceTypes(caseArgArray, localTypeObj, id) + if (returnType === 'needsInference') returnType = checkArgsType globalTypesObj[id] = { - type: "function", + type: 'function', paramTypes: makeParamTypeArray(localTypeObj, id), - returnType, - }; - return checkArgsType === false || checkTestType === false - ? null - : returnType; -}; + returnType + } + return checkArgsType === false || checkTestType === false ? null : returnType +} const arrayExprType = (expr, localTypeObj, id) => { - const elementTypeObj = {}; + const elementTypeObj = {} if (isEmpty(expr.elements)) { return { - type: "array", + type: 'array', elemTypes: {}, - commonType: "needsInference", - isHomogeneous: true, - }; + commonType: 'needsInference', + isHomogeneous: true + } } const deducedtype = expr.elements .map((e, index) => { - const elemType = exprType(e, localTypeObj, id); - elementTypeObj[index] = elemType; - return elemType; + const elemType = exprType(e, localTypeObj, id) + elementTypeObj[index] = elemType + return elemType }) - .reduce((type1, type2) => - type1 === type2 ? type1 : "needsInference" - ); + .reduce((type1, type2) => (type1 === type2 ? type1 : 'needsInference')) const arrayType = { - type: "array", + type: 'array', elemTypes: elementTypeObj, commonType: deducedtype.type !== undefined && - (deducedtype.type === "object" || deducedtype.type === "array") + (deducedtype.type === 'object' || deducedtype.type === 'array') ? deducedtype.type : deducedtype, - isHomogeneous: true, - }; - if (deducedtype === "needsInference") { - arrayType.isHomogeneous = false; + isHomogeneous: true } - return arrayType; -}; + if (deducedtype === 'needsInference') { + arrayType.isHomogeneous = false + } + return arrayType +} const objectExprType = (expr, localTypeObj, id) => { - const propertyTypeObj = {}; + const propertyTypeObj = {} expr.properties.forEach((prop) => { if (prop.key.value === undefined) { - propertyTypeObj[prop.key.name] = exprType( - prop.value, - localTypeObj - ); + propertyTypeObj[prop.key.name] = exprType(prop.value, localTypeObj) } else { - propertyTypeObj[prop.key.value] = exprType( - prop.value, - localTypeObj - ); + propertyTypeObj[prop.key.value] = exprType(prop.value, localTypeObj) } - }); - return { type: "object", propTypes: propertyTypeObj }; -}; + }) + return { type: 'object', propTypes: propertyTypeObj } +} const getParentTypes = (propSpec, propName, parentId, localTypeObj) => { - const supportedTypes = []; + const supportedTypes = [] for (const type in propSpec) { - if (propSpec[type][propName] !== undefined) - supportedTypes.push(type); + if (propSpec[type][propName] !== undefined) supportedTypes.push(type) } if (supportedTypes.length === 1) { - localTypeObj[parentId.name] = supportedTypes[0]; + localTypeObj[parentId.name] = supportedTypes[0] } - return localTypeObj[parentId.name]; -}; + return localTypeObj[parentId.name] +} const getPropName = (prop) => - prop.type === "Identifier" + prop.type === 'Identifier' ? prop.name - : prop.type === "Literal" - ? prop.raw - : null; + : prop.type === 'Literal' + ? prop.raw + : null const getPropReturnType = (propSpec, propName) => { - if (propSpec === undefined) return { type: false, id: propName }; // allow - if (propSpec.isMutative) return { type: null, id: propName }; // block + if (propSpec === undefined) return { type: false, id: propName } // allow + if (propSpec.isMutative) return { type: null, id: propName } // block if (propSpec.isMethod) { return { - type: "function", + type: 'function', paramTypes: propSpec.paramTypes, returnType: propSpec.returnType, - id: propName, - }; + id: propName + } } // handle no params - if (propSpec.isProp) - return { type: propSpec.returnType, id: propName }; -}; - -const checkForInbuiltProp = ( - parentType, - prop, - parentId, - localTypeObj -) => { - const propName = getPropName(prop); - if (propName === null) - return { type: "needsInference", id: propName }; - if (parentType === "needsInference") { - const propSpec = inbuiltPropSpec[parentType][propName]; - if (propSpec === undefined) - return { type: "needsInference", id: propName }; - localTypeObj[parentId.name] = propSpec.parentType; - return getPropReturnType(propSpec.spec, propName); - } - const propSpec = inbuiltPropSpec[parentType][propName]; - return getPropReturnType(propSpec, propName); -}; - -const getTypeOfChild = ( - parentObj, - propsArray, - parentId, - localTypeObj, - id -) => { - if (isEmpty(propsArray)) return parentObj; - const [prop] = propsArray; + if (propSpec.isProp) return { type: propSpec.returnType, id: propName } +} + +const checkForInbuiltProp = (parentType, prop, parentId, localTypeObj) => { + const propName = getPropName(prop) + if (propName === null) return { type: 'needsInference', id: propName } + if (parentType === 'needsInference') { + const propSpec = inbuiltPropSpec[parentType][propName] + if (propSpec === undefined) return { type: 'needsInference', id: propName } + localTypeObj[parentId.name] = propSpec.parentType + return getPropReturnType(propSpec.spec, propName) + } + const propSpec = inbuiltPropSpec[parentType][propName] + return getPropReturnType(propSpec, propName) +} + +const getTypeOfChild = (parentObj, propsArray, parentId, localTypeObj, id) => { + if (isEmpty(propsArray)) return parentObj + const [prop] = propsArray const propSpec = checkForInbuiltProp( parentObj.type, prop, parentId, localTypeObj - ); - const propId = propSpec.id; + ) + const propId = propSpec.id switch (propSpec.type) { - case "needsInference": { + case 'needsInference': { const type = getParentTypes( inbuiltPropSpec, prop.name, parentId, localTypeObj - ); - if (type === "needsInference") return "needsInference"; - if (typeof type === "string") { - localTypeObj[parentId] = type; + ) + if (type === 'needsInference') return 'needsInference' + if (typeof type === 'string') { + localTypeObj[parentId] = type return getTypeOfChild( { type: type }, propsArray, parentId, localTypeObj, id - ); + ) } - return "needsInference"; + return 'needsInference' } case null: - return null; // block mutative methods + return null // block mutative methods case false: { - if (parentObj.type === "object") { - if (prop.type !== "Literal" && prop.isSubscript) { - const expType = exprType(prop, localTypeObj, id); - return expType !== "string" && expType !== undefined + if (parentObj.type === 'object') { + if (prop.type !== 'Literal' && prop.isSubscript) { + const expType = exprType(prop, localTypeObj, id) + return expType !== 'string' && expType !== undefined ? null - : "needsInference"; + : 'needsInference' } - if (prop.sType !== undefined && prop.sType !== "string") - return null; - if (parentObj.propTypes === "needsInference") - return "needsInference"; + if (prop.sType !== undefined && prop.sType !== 'string') return null + if (parentObj.propTypes === 'needsInference') return 'needsInference' return getTypeOfChild( parentObj.propTypes[propId], propsArray.slice(1), propsArray[0], localTypeObj, id - ); + ) } - if (parentObj.type === "array") { - if (prop.type !== "Literal") { + if (parentObj.type === 'array') { + if (prop.type !== 'Literal') { return propsArray.length === 1 ? parentObj.commonType - : "needsInference"; + : 'needsInference' } - if (prop.sType === "number") { + if (prop.sType === 'number') { // check prop is string for string in subscripts // let index = Number(propId) - if (isEmptyObj(parentObj.elemTypes)) - return parentObj.commonType; + if (isEmptyObj(parentObj.elemTypes)) return parentObj.commonType return getTypeOfChild( parentObj.elemTypes[propId], propsArray.slice(1), propsArray[0], localTypeObj, id - ); + ) } - return null; // return type error : subscript value must be a number for array + return null // return type error : subscript value must be a number for array } - return null; // return on such property for strings, numbers, and bool + return null // return on such property for strings, numbers, and bool } - case "function": { + case 'function': { if ( - parentObj.type === "array" && + parentObj.type === 'array' && parentObj.isHomogeneous && - propSpec.returnType.type === "array" + propSpec.returnType.type === 'array' ) { - propSpec.returnType.isHomogeneous = propId !== "concat"; + propSpec.returnType.isHomogeneous = propId !== 'concat' } - return [propSpec.paramTypes, propSpec.returnType]; + return [propSpec.paramTypes, propSpec.returnType] } default: - return propSpec.type; + return propSpec.type } -}; +} const getPathToProp = (obj, path = []) => { - if (obj.type !== undefined && obj.type !== "MemberExpression") { - path.unshift(obj); - return path; - } - if ( - obj.property.type === "Identifier" || - obj.property.type === "Literal" - ) { - path.unshift(obj.property); + if (obj.type !== undefined && obj.type !== 'MemberExpression') { + path.unshift(obj) + return path } + if (obj.property.type === 'Identifier' || obj.property.type === 'Literal') { path.unshift(obj.property) } // Handle binary and function calls inside member expressions - return getPathToProp(obj.object, path); -}; + return getPathToProp(obj.object, path) +} const memberExprType = (expr, localTypeObj, id) => { - const object = expr.object; - const property = expr.property; - const pathToProp = getPathToProp(object); - pathToProp.push(property); - const [parentId] = pathToProp; - const parentType = exprType(parentId, localTypeObj, id); // Handle cases other than object and arrays and strings - if (parentType === null) return "needsInference"; + const object = expr.object + const property = expr.property + const pathToProp = getPathToProp(object) + pathToProp.push(property) + const [parentId] = pathToProp + const parentType = exprType(parentId, localTypeObj, id) // Handle cases other than object and arrays and strings + if (parentType === null) return 'needsInference' if (parentType !== undefined) { return parentType.type === undefined ? getTypeOfChild( @@ -600,102 +519,96 @@ const memberExprType = (expr, localTypeObj, id) => { id ) : getTypeOfChild( - parentType, - pathToProp.slice(1), - pathToProp[0], - localTypeObj, - id - ); + parentType, + pathToProp.slice(1), + pathToProp[0], + localTypeObj, + id + ) } - return null; // accessing parentType undefined -}; + return null // accessing parentType undefined +} const blockStatementType = (stmnt, localTypeObj, id) => { - const [expr] = stmnt.body; - return exprType(expr, localTypeObj, id); -}; + const [expr] = stmnt.body + return exprType(expr, localTypeObj, id) +} const exprType = (expr, localTypeObj = {}, id = null) => { - if ( - expr !== null && - expr.sType !== undefined && - expr.sType === "IO" - ) { - return "IO"; - } - if (expr === null) return "needsInference"; - if (expr.type === "ExpressionStatement") expr = expr.expression; - const type = expr.type; + if (expr !== null && expr.sType !== undefined && expr.sType === 'IO') { return 'IO' } + if (expr === null) return 'needsInference' + if (expr.type === 'ExpressionStatement') expr = expr.expression + const type = expr.type switch (type) { - case "Literal": - return literalType(expr); - case "Identifier": - return identifierType(expr, localTypeObj); - case "UnaryExpression": - return unaryExprType(expr); - case "BinaryExpression": - return binaryExprType(expr, localTypeObj, id); - case "CallExpression": - return callExprType(expr, localTypeObj, id); - case "ConditionalExpression": - return conditionalExprType(expr, localTypeObj, id); - case "ArrowFunctionExpression": - return arrowFunctionExprType(expr, localTypeObj, id); - case "BlockStatement": - return blockStatementType(expr, localTypeObj, id); - case "SwitchStatement": - return switchStatementType(expr, localTypeObj, id); - case "ArrayExpression": - return arrayExprType(expr, localTypeObj, id); - case "ObjectExpression": - return objectExprType(expr, localTypeObj, id); - case "MemberExpression": - return memberExprType(expr, localTypeObj, id); + case 'Literal': + return literalType(expr) + case 'Identifier': + return identifierType(expr, localTypeObj) + case 'UnaryExpression': + return unaryExprType(expr) + case 'BinaryExpression': + return binaryExprType(expr, localTypeObj, id) + case 'CallExpression': + return callExprType(expr, localTypeObj, id) + case 'ConditionalExpression': + return conditionalExprType(expr, localTypeObj, id) + case 'ArrowFunctionExpression': + return arrowFunctionExprType(expr, localTypeObj, id) + case 'BlockStatement': + return blockStatementType(expr, localTypeObj, id) + case 'SwitchStatement': + return switchStatementType(expr, localTypeObj, id) + case 'ArrayExpression': + return arrayExprType(expr, localTypeObj, id) + case 'ObjectExpression': + return objectExprType(expr, localTypeObj, id) + case 'MemberExpression': + return memberExprType(expr, localTypeObj, id) default: - return expr; + return expr } -}; +} const declTypeExtract = (stmnt) => { - const [decl] = stmnt.declarations; - const [id, exp] = [decl.id.name, decl.init]; - if ((exp.sType !== undefined && exp.sType === "IO") || id === "IO") { - globalTypesObj[id] = "IO"; + const [decl] = stmnt.declarations + const [id, exp] = [decl.id.name, decl.init] + if ((exp.sType !== undefined && exp.sType === 'IO') || id === 'IO') { + globalTypesObj[id] = 'IO' } else { - const type = exprType(exp, {}, id); - globalTypesObj[id] = type; + const type = exprType(exp, {}, id) + globalTypesObj[id] = type } -}; +} const loadInbuiltObjects = () => { for (const obj in inbuiltObjects) { - globalTypesObj[obj] = inbuiltObjects[obj]; + globalTypesObj[obj] = inbuiltObjects[obj] } -}; +} const delObj = (obj) => { for (const member in obj) { - delete obj[member]; + delete obj[member] } -}; +} const types = (body) => { - loadInbuiltObjects(); + loadInbuiltObjects() body.forEach((expr) => { - const type = expr.type; - if (type === "VariableDeclaration") declTypeExtract(expr); - }); - const errorObj = { error: false }; + const type = expr.type + if (type === 'VariableDeclaration') declTypeExtract(expr) + }) + const errorObj = { error: false } for (const decl in globalTypesObj) { if (globalTypesObj[decl] === null) { - errorObj.error = true; - errorObj.id = decl; - break; + errorObj.error = true + errorObj.id = decl + break } } - delObj(globalTypesObj); - return errorObj.error ? errorObj : body; -}; + delObj(globalTypesObj) + return errorObj.error ? errorObj : body +} /* Module Exports types */ -module.exports = types; +module.exports = types