UNPKG

@specs-feup/lara

Version:

A js port of the popular framework for building source-to-source compilers

384 lines 11.4 kB
import { LaraJoinPoint } from "../../LaraJoinPoint.js"; import JoinPoints from "../../weaver/JoinPoints.js"; import { isJoinPoint } from "../core/LaraCore.js"; /** * Logger object, for inserting code that prints/saves information to files. * * @param isGlobal - Not implemented, please ignore * @param filename - If set, instead of printing, will insert code for writing output to this file * */ export default class LoggerBase { isGlobal; filename; currentElements = []; functionMap = {}; afterJp = undefined; Type = new Map(); constructor(isGlobal = false, filename) { if (isGlobal) { console.log("[Logger-warning] global Logger is not implemented yet, reverting to local Logger"); isGlobal = false; } this.isGlobal = isGlobal; this.filename = filename; this.Type.set("NORMAL", 1); this.Type.set("INT", 2); this.Type.set("DOUBLE", 3); this.Type.set("STRING", 4); this.Type.set("CHAR", 5); this.Type.set("HEX", 6); this.Type.set("OCTAL", 7); this.Type.set("LITERAL", 8); this.Type.set("LONG", 9); } /** * Used for both C and Java printf functions */ printfFormat = { 1: undefined, 2: "%d", 3: "%f", 4: "%s", 5: "%c", 6: "%x", 7: "%o", 8: undefined, 9: "%ld", }; isGlobalFn() { console.log("Is Global Fn:", this.isGlobal); } /** * The 'last' join point after .log() is called. * */ getAfterJp() { return this.afterJp; } clear() { this.currentElements = []; } /** * Helper method which call 'log' with 'insertBefore' set to true * */ logBefore($jp) { this.log($jp, true); } /** * Verifies that the given $jp is inside a function. * * Requires global attribute 'ancestor'. * * @returns true if $jp is inside a function, false otherwise */ // TODO: This function should receive LaraJoinPoints but they do not have the getAncestor method _validateJp($jp, functionJpName = "function") { const $function = $jp.getAncestor(functionJpName); if ($function === undefined) { console.log("Logger: tried to insert log around joinpoint " + $jp.joinPointType + ", but is not inside a function"); this.clear(); return false; } return true; } _insert($jp, insertBefore, code) { this._insertCode($jp, insertBefore, code); // Clear internal state this.clear(); } /** * Inserts the given code before/after the given join point. * * Override this method if you need to specialize the insertion. */ // TODO: This function should receive LaraJoinPoints but they do not have the insertAfter method _insertCode($jp, insertBefore, code) { const insertBeforeString = insertBefore ? "before" : "after"; if (insertBefore) { $jp.insert(insertBeforeString, code); this.afterJp = $jp; } else { this.afterJp = $jp.insertAfter(code); } } /** * Appends the given string to the current buffer. * * @param text - The text to append * @returns The current logger instance */ append(text) { return this._append_private(text, this.Type.get("NORMAL")); } /** * The same as 'append'. * * @param text - the text to append * @returns The current logger instance */ text(text) { return this.append(text); } /** * The same as 'append', but adds a new line at the end of the buffer. * * @param text - the text to append * @returns The current logger instance */ appendln(text) { return this.append(text).ln(); } /** * Appends a new line to the buffer. * * @returns The current logger instance */ ln() { return this._append_private("\\n", this.Type.get("NORMAL")); } /** * Appends a tab to the buffer. * * @returns The current logger instance */ tab() { return this.append("\\t"); } /** * Appends an expression that represents a double. * * @param expr - The expression to append * @returns The current logger instance */ appendDouble(expr) { return this._append_private(expr, this.Type.get("DOUBLE")); } /** * The same as 'appendDouble'. * * @param expr - The expression to append * @returns The current logger instance */ double(expr) { return this.appendDouble(expr); } /** * Appends an expression that represents a int. * * @param expr - The expression to append * @returns The current logger instance */ appendInt(expr) { return this._append_private(expr, this.Type.get("INT")); } /** * The same as 'appendInt'. * * @param expr - The expression to append * @returns The current logger instance */ int(expr) { return this.appendInt(expr); } /** * Appends an expression that represents a long. * * @param expr - The expression to append * @returns The current logger instance */ appendLong(expr) { return this._append_private(expr, this.Type.get("LONG")); } /** * The same as 'appendLong'. * * @param expr - The expression to append * @returns The current logger instance */ long(expr) { return this.appendLong(expr); } /** * Appends an expression that represents a string. * * @param expr - The expression to append * @returns The current logger instance */ appendString(expr) { return this._append_private(expr, this.Type.get("STRING")); } /** * The same as 'appendString'. * * @param expr - The expression to append * @returns The current logger instance */ string(expr) { return this.appendString(expr); } /** * Appends an expression that represents a char. * * @param expr - The expression to append * @returns The current logger instance */ appendChar(expr) { return this._append_private(expr, this.Type.get("CHAR")); } /** * The same as 'appendChar'. * * @param expr - The expression to append * @returns The current logger instance */ char(expr) { return this.appendChar(expr); } /** * Appends an expression that represents a hex number. * * @param expr - The expression to append * @returns The current logger instance */ appendHex(expr) { return this._append_private(expr, this.Type.get("HEX")); } /** * The same as 'appendHex'. * * @param expr - The expression to append * @returns The current logger instance */ hex(expr) { return this.appendHex(expr); } /** * Appends an expression that represents an octal. * * @param expr - The expression to append * @returns The current logger instance */ appendOctal(expr) { return this._append_private(expr, this.Type.get("OCTAL")); } /** * The same as 'appendOctal'. * * @param expr - The expression to append * @returns The current logger instance */ octal(expr) { return this.appendOctal(expr); } /**** PRIVATE METHODS ****/ _append_private(message, type) { // If message is a join point, convert to code first if (isJoinPoint(message) || message instanceof LaraJoinPoint) { message = JoinPoints.getCode(message); } // Do not push message if empty if (message === "" || type === undefined) { return this; } this.currentElements.push({ content: message, type: type }); return this; } _warn(message) { console.log("[Logger Warning]", message); } _info(message) { console.log("[Logger]", message); } // Receives an element{content, type} and returns the content with or without quotation marks, accordingly _getPrintableContent(element) { const enumType = this.Type; let content = element.content; if (element.type === enumType.get("LITERAL")) { return String(content); } if (element.type === enumType.get("NORMAL") || element.type === enumType.get("STRING")) { return '"' + content + '"'; } if (element.type === enumType.get("CHAR")) { return "'" + content + "'"; } // Test if it has a decimal point if (element.type === enumType.get("DOUBLE")) { if (typeof content !== "number") { return content; } const indexOfDecimal = String(content).indexOf("."); if (indexOfDecimal === -1) { content = String(content) + ".0"; } return String(content); } return String(content); } /** * Generates printf like code for c and java * * @param printFunctionName - The name of the function to use (printf for C, System.out.println for Java) */ _printfFormat(printFunctionName, prefix = "(", suffix = ");", delimiter = '"') { // Create code from elements let code = printFunctionName + prefix + delimiter + this.currentElements .map((element) => { const enumType = this.Type; if (element.type === enumType.get("NORMAL")) { return element.content; } return this.printfFormat[element.type]; }) .join("") + delimiter; const valuesCode = this.currentElements // Filter only non-NORMAL types .filter((element) => { const enumType = this.Type; return element.type !== enumType.get("NORMAL"); }) .map((element) => { // Even though _getPrintableContent tests an always unmet condition (type === NORMAL) it represents a reusable piece of code for both C and C++ return this._getPrintableContent(element); }) .join(", "); if (valuesCode.length > 0) { code = code + ", " + valuesCode; } code = code + suffix; return code; } /** * * * @param $function - Function where name will be declared * @param nameGenerator - Function that receives no arguments and generates a new name */ _declareName(functionId, nameGenerator) { let name = this.functionMap[functionId]; let alreadyDeclared = false; if (name !== undefined) { alreadyDeclared = true; } else { name = nameGenerator(); this.functionMap[functionId] = name; alreadyDeclared = false; } return { name: name, alreadyDeclared: alreadyDeclared, }; } } //# sourceMappingURL=LoggerBase.js.map