Website Summary Files Commits Branches @commit @diff @stats
path: root / homework / 45183 / CodeFormatting
diff options
context:
space:
mode:
Commit1384d7ea4e80eaa6b195195af81de974575b2bb0 (patch)
Author
 omalinov <ognyan.m@coherent-labs.com>
2018-10-21 17:36:32 +0300
Committer
 Martin Dobrev <martindobrev0@gmail.com>
2018-10-21 17:36:32 +0300
Files4e73618753e1d42f9cfa60a247a8bcf35c483db7 /homework/45183/CodeFormatting
IPL-1384d7ea4e80eaa6b195195af81de974575b2bb0.tar
IPL-1384d7ea4e80eaa6b195195af81de974575b2bb0.tar.gz
IPL-1384d7ea4e80eaa6b195195af81de974575b2bb0.zip
Parent7509dce0686d9a418975f73b3721ecaa2d534f16 (diff)
Lexer/homework (#15)
* Initial commit * code is formatted * Homework finished * Genie project generation. * Updated code with new constructors
diff --git a/homework/45183/CodeFormatting/README.md b/homework/45183/CodeFormatting/README.md
new file mode 100644
index 0000000..51e8155
--- /dev/null
+++ b/homework/45183/CodeFormatting/README.md
@@ -0,0 +1,16 @@
+# Overview
+The code here takes `.js` files as input and produces color formatted JavaScript code in an `.html` file.
+
+# Prerequisites
+* Windows OS
+* VisualStudio 2015 or 2017
+
+# How to use
+* Download GENie from https://github.com/bkaradzic/GENie
+* Execute `./genie.exe vs2017` to generate a Visual Studio 2017 project.
+* Open the solution to Build and Run.
+* The output files should be created in the same folder as the `.js` files and they should open in your browser.
+
+# Known issues
+* Lexer can't parse RegExp.
+* Lexer can't parse Template literals. \ No newline at end of file
diff --git a/homework/45183/CodeFormatting/genie.lua b/homework/45183/CodeFormatting/genie.lua
new file mode 100644
index 0000000..74b3734
--- /dev/null
+++ b/homework/45183/CodeFormatting/genie.lua
@@ -0,0 +1,25 @@
+PROJ_DIR = path.getabsolute(".")
+
+solution 'CodeFormatting'
+ configurations { 'Debug' }
+ configuration 'Windows'
+ flags {
+ 'FatalWarnings',
+ 'ExtraWarnings',
+ 'Symbols',
+ 'FullSymbols'
+ }
+ startproject 'CodeFormatting'
+
+configuration 'Debug'
+ targetdir(path.join(PROJ_DIR, 'bin', 'debug'))
+ objdir(path.join(PROJ_DIR, 'bin', 'debug'))
+
+project 'CodeFormatting'
+ kind 'ConsoleApp'
+ language 'C++'
+ files {
+ path.join(PROJ_DIR, "main.cpp"),
+ path.join(PROJ_DIR, "..", "..", "..", "JSImpl", "src", "Lexer.h"),
+ path.join(PROJ_DIR, "..", "..", "..", "JSImpl", "src", "Lexer.cpp")
+ } \ No newline at end of file
diff --git a/homework/45183/CodeFormatting/input1.js b/homework/45183/CodeFormatting/input1.js
new file mode 100644
index 0000000..1c241e4
--- /dev/null
+++ b/homework/45183/CodeFormatting/input1.js
@@ -0,0 +1,127 @@
+true;
+false;
+undefined;
+null;
+
+import CoherentUtilities from "../CoherentUtilities";
+import Select from "../components/Select/Select";
+import { SUPPORTED_UNIT_TYPES } from './UnitTypes';
+
+const DEFAULT_OPTION = Object.freeze({
+ value: 'default',
+ displayed: 'Use default units'
+});
+
+const SUPPORTED_UNIT_TYPES_POSITIONS = Object.assign([], SUPPORTED_UNIT_TYPES);
+SUPPORTED_UNIT_TYPES_POSITIONS.push(DEFAULT_OPTION);
+Object.freeze(SUPPORTED_UNIT_TYPES_POSITIONS);
+
+const SUPPORTED_UNITS_TYPE_FONT_SIZE = Object.assign([], SUPPORTED_UNIT_TYPES_POSITIONS);
+for (let i = 0; i < SUPPORTED_UNITS_TYPE_FONT_SIZE.length; ++i) {
+ if (SUPPORTED_UNITS_TYPE_FONT_SIZE[i].value === 'percents') {
+ SUPPORTED_UNITS_TYPE_FONT_SIZE.splice(i, 1);
+ break;
+ }
+}
+Object.freeze(SUPPORTED_UNITS_TYPE_FONT_SIZE);
+
+const AUTO_OPTION = Object.freeze({
+ value: 'auto',
+ displayed: 'auto'
+});
+
+const SUPPORTED_UNITS_TYPE_DIMENSIONS = Object.assign([], SUPPORTED_UNIT_TYPES);
+SUPPORTED_UNITS_TYPE_DIMENSIONS.push(AUTO_OPTION);
+SUPPORTED_UNITS_TYPE_DIMENSIONS.push(DEFAULT_OPTION);
+Object.freeze(SUPPORTED_UNITS_TYPE_DIMENSIONS);
+
+const DEFAULT_UNIT_SELECTION_INDEX = SUPPORTED_UNIT_TYPES_POSITIONS.length - 1;
+const DEFAULT_UNITS_SELECTION_VALUE = SUPPORTED_UNIT_TYPES_POSITIONS[DEFAULT_UNIT_SELECTION_INDEX].value;
+
+const UNITS_SELECT_CONFIGURATIONS = Object.freeze({
+ WIDTH: Object.freeze({
+ sSelector: '#widthUnits',
+ aOptionObj: SUPPORTED_UNITS_TYPE_DIMENSIONS,
+ nSelected: DEFAULT_UNIT_SELECTION_INDEX
+ }),
+ HEIGHT: Object.freeze({
+ sSelector: '#heightUnits',
+ aOptionObj: SUPPORTED_UNITS_TYPE_DIMENSIONS,
+ nSelected: DEFAULT_UNIT_SELECTION_INDEX
+ }),
+ TOP: Object.freeze({
+ sSelector: '#topUnits',
+ aOptionObj: SUPPORTED_UNIT_TYPES_POSITIONS,
+ nSelected: DEFAULT_UNIT_SELECTION_INDEX
+ }),
+ LEFT: Object.freeze({
+ sSelector: '#leftUnits',
+ aOptionObj: SUPPORTED_UNIT_TYPES_POSITIONS,
+ nSelected: DEFAULT_UNIT_SELECTION_INDEX
+ }),
+ FONTSIZE: Object.freeze({
+ sSelector: '#fontSizeUnits',
+ aOptionObj: SUPPORTED_UNITS_TYPE_FONT_SIZE,
+ nSelected: 0
+ })
+});
+
+export default class UnitsTab {
+ constructor() {
+ /**
+ * @type {Object.<string, Select>}
+ */
+ UnitsTab.units = {
+ width: new Select(UNITS_SELECT_CONFIGURATIONS.WIDTH),
+ height: new Select(UNITS_SELECT_CONFIGURATIONS.HEIGHT),
+ top: new Select(UNITS_SELECT_CONFIGURATIONS.TOP),
+ left: new Select(UNITS_SELECT_CONFIGURATIONS.LEFT),
+ fontSize: new Select(UNITS_SELECT_CONFIGURATIONS.FONTSIZE)
+ }
+ UnitsTab.addEventHandlers();
+ }
+
+ /**
+ * Sets all values of the Unit Selects and writes the new values to the current selection.
+ *
+ * @param {Object} metadata - UnitsTab types for some item.
+ * @param {boolean} disable - Whether the units Select should be disabled.
+ */
+ static deserializeUnitsPrefs(metadata, disable) {
+ const toWriteValues = [];
+ const toWriteTypes = [];
+
+ for (let unitsType in UnitsTab.units) {
+ let metaValue = metadata.units[unitsType];
+
+ // Backwards compatability.
+ if (metaValue === '' || metaValue === undefined) {
+ metaValue = DEFAULT_UNITS_SELECTION_VALUE;
+ }
+ if (metaValue === 'px') {
+ metaValue = 'pixels';
+ }
+
+ UnitsTab.units[unitsType].setValue(metaValue, true);
+ UnitsTab.units[unitsType].setDisabled(disable);
+
+ toWriteValues.push(metaValue);
+ toWriteTypes.push(unitsType);
+ }
+ }
+
+ /**
+ * Attaches a change event listener to each UnitsTab Select that writes
+ * the new units type to the current selection.
+ */
+ static addEventHandlers() {
+ for (let unitsType in UnitsTab.units) {
+ UnitsTab.units[unitsType].addEventListener('change', event => {
+ CoherentUtilities.fl_changeDataProperty(
+ unitsType,
+ "units",
+ event.detail.value);
+ });
+ }
+ }
+}
diff --git a/homework/45183/CodeFormatting/input2.js b/homework/45183/CodeFormatting/input2.js
new file mode 100644
index 0000000..c1c377c
--- /dev/null
+++ b/homework/45183/CodeFormatting/input2.js
@@ -0,0 +1,71 @@
+export default class Queue {
+ constructor() {
+ this._firstNode = null;
+ this._lastNode = null;
+ }
+
+ /**
+ * Retrieves the first element in the queue.
+ * It also removes it from the queue.
+ * @returns {*}
+ */
+ dequeue() {
+ if (!this._firstNode) {
+ return this._firstNode;
+ }
+
+ const payload = this._firstNode.payload;
+
+ this._firstNode = this._firstNode.next;
+
+ return payload;
+ }
+
+ /**
+ * Adds an item to the queue
+ * @param {*} item
+ */
+ enqueue(item) {
+ const newNode = {
+ payload: item,
+ next: null
+ };
+
+ if (this._firstNode === null) {
+ this._firstNode = newNode;
+ this._lastNode = newNode;
+
+ } else {
+ this._lastNode.next = newNode;
+ this._lastNode = newNode;
+ }
+ }
+
+ /**
+ * Empties the queue
+ */
+ clear() {
+ this._firstNode = null;
+ this._lastNode = null;
+ }
+
+ /**
+ * Gets the first element of the queue
+ * @returns {*}
+ */
+ top() {
+ if (!this._firstNode) {
+ return this._firstNode;
+ }
+
+ return this._firstNode.payload;
+ }
+
+ /**
+ * Checks whether the queue is empty or not
+ * @returns {boolean}
+ */
+ isEmpty() {
+ return !this._firstNode;
+ }
+} \ No newline at end of file
diff --git a/homework/45183/CodeFormatting/input3.js b/homework/45183/CodeFormatting/input3.js
new file mode 100644
index 0000000..11de05a
--- /dev/null
+++ b/homework/45183/CodeFormatting/input3.js
@@ -0,0 +1,9 @@
+/**
+ * @type {Object.<string, Select>}
+ */
+
+if (1 < 2) {
+ console.log(false);
+}
+
+console.log("<>"); \ No newline at end of file
diff --git a/homework/45183/CodeFormatting/input4.js b/homework/45183/CodeFormatting/input4.js
new file mode 100644
index 0000000..9c342c9
--- /dev/null
+++ b/homework/45183/CodeFormatting/input4.js
@@ -0,0 +1 @@
+/regexp/i \ No newline at end of file
diff --git a/homework/45183/CodeFormatting/main.cpp b/homework/45183/CodeFormatting/main.cpp
new file mode 100644
index 0000000..9498bff
--- /dev/null
+++ b/homework/45183/CodeFormatting/main.cpp
@@ -0,0 +1,405 @@
+#include "../../../JSImpl/src/Lexer.h"
+#include <Windows.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <cassert>
+
+// Theme
+#define IDENTIFIER_COLOR "#e2c071"
+#define SINGLE_KEYWORD_COLOR "#b9b8b9"
+#define KEYWORD_COLOR "#bd6fd6"
+#define OPERATOR_KEYWORD_COLOR "#5faee8"
+#define NUMBER_COLOR "#e2c071"
+#define STRING_COLOR "#8daf56"
+#define BACKGROUND_COLOR "#1e1e1e"
+#define COMMENT_COLOR "#5d6371"
+#define MISC_COLOR "#dd7076"
+#define BOLD "font-weight: bold;"
+
+void FormatCode(const IPLString& in, const IPLString& out);
+
+IPLString GetSolutionDir();
+IPLString GetInputCode(const IPLString& inputName);
+bool DumpFormattedCode(const IPLVector<Token>& tokens, const IPLString& outName);
+void PreviewFormattedCode(const IPLString& outName);
+
+void DumpFileBeginning(std::ofstream& out);
+void DumpTokens(std::ofstream& out, const IPLVector<Token>& tokens);
+void DumpFileEnd(std::ofstream& out);
+
+inline void DumpClassWithValue(std::ofstream& out, const IPLString& cssClass, const IPLString& lexeme);
+inline void DumpClassWithValue(std::ofstream& out, const IPLString& cssClass, double number);
+inline void DumpClassWithFormattedLexeme(std::ofstream& out, const IPLString& cssClass, const IPLString& lexeme);
+void DumpCompatibleHTML(std::ofstream& out, const IPLString& text);
+
+inline void DumpOperatorKeyword(std::ofstream& out, const Token& token);
+inline void DumpSingleKeyword(std::ofstream& out, const Token& token);
+inline void DumpKeyword(std::ofstream& out, const Token& token);
+inline void DumpString(std::ofstream& out, const Token& token);
+inline void DumpMisc(std::ofstream& out, const Token& token);
+inline void DumpNumber(std::ofstream& out, const Token& token);
+inline void DumpIdentifier(std::ofstream& out, const Token& token);
+inline void DumpComment(std::ofstream& out, const Token& token);
+
+int main()
+{
+ const IPLVector<IPLString> inputs = { "input1.js","input2.js", "input3.js", "input4.js"};
+ const IPLString outputFilePrefix = "output";
+
+ for (std::size_t i = 0; i < inputs.size(); ++i)
+ {
+ FormatCode(inputs[i], outputFilePrefix + std::to_string(i + 1) + ".html");
+ }
+
+ return 0;
+}
+
+IPLString GetSolutionDir()
+{
+ TCHAR* buffer = new TCHAR[MAX_PATH];
+ int nSize = GetModuleFileName(NULL, buffer, MAX_PATH);
+
+ if (nSize != 0)
+ {
+ IPLString ret(buffer);
+ delete[] buffer;
+
+ auto dirDelim = ret.rfind("\\bin");
+
+ if (dirDelim != IPLString::npos)
+ {
+ ret.resize(dirDelim + 1);
+ return ret;
+ }
+ }
+
+ return IPLString();
+}
+
+IPLString GetInputCode(const IPLString& inputName)
+{
+ auto dir = GetSolutionDir();
+ if (!dir.empty())
+ {
+ std::ifstream input(dir + inputName);
+ if (input.good())
+ {
+ std::stringstream buffer;
+ buffer << input.rdbuf();
+ input.close();
+ return buffer.str();
+ }
+ }
+
+ std::cerr << "Input file error.\n";
+ return IPLString();
+}
+
+void DumpFileBeginning(std::ofstream& out)
+{
+ out << "<html>\n\n"
+ << "<head>\n"
+ << "\t<style>\n"
+ << "\t\tdiv {\n\t\t\twhite-space: pre-wrap;\n\t\t}\n\n"
+ << "\t\tbody {\n"
+ << "\t\t\tbackground-color: " << BACKGROUND_COLOR << ";\n"
+ << "\t\t\tfont-size: 18px;\n"
+ << "\t\t\tfont-family: 'Consolas';\n"
+ << "\t\t}\n\n"
+ << "\t\t.identifier {\n\t\t\tcolor: " << IDENTIFIER_COLOR << ";\n\t\t}\n\n"
+ << "\t\t.single-keyword {\n\t\t\tcolor: " << SINGLE_KEYWORD_COLOR << ";\n\t\t}\n\n"
+ << "\t\t.keyword {\n \t\t\tcolor: " << KEYWORD_COLOR << ";\n\t\t}\n\n"
+ << "\t\t.operator-keyword {\n\t\t\tcolor: " << OPERATOR_KEYWORD_COLOR << "; " << BOLD << "\n\t\t}\n\n"
+ << "\t\t.number {\n\t\t\tcolor: " << NUMBER_COLOR << ";\n\t\t}\n\n"
+ << "\t\t.string {\n\t\t\tcolor: " << STRING_COLOR << ";\n\t\t}\n\n"
+ << "\t\t.comment {\n\t\t\tcolor: " << COMMENT_COLOR << ";\n\t\t}\n\n"
+ << "\t\t.misc {\n\t\t\tcolor: " << MISC_COLOR << ";\n\t\t}\n"
+ << "\t</style>\n"
+ << "</head>\n\n"
+ << "<body>\n"
+ << "\t<div id='text'></div>\n"
+ << "\t<script>\n"
+ << "\t\tdocument.getElementById('text').innerHTML = '";
+}
+
+void DumpFileEnd(std::ofstream& out)
+{
+ out << "';\n"
+ << "\t</script>\n"
+ << "</body>\n\n"
+ << "</html>";
+}
+
+void DumpCompatibleHTML(std::ofstream& out, const IPLString& text)
+{
+ for (auto& ch : text)
+ {
+ if (ch == '\n')
+ {
+ out << "\\n";
+ }
+ else if (ch == '\t')
+ {
+ out << "\\t";
+ }
+ else if (ch == '<')
+ {
+ out << "&#60;";
+ }
+ else if (ch == '>')
+ {
+ out << "&#62;";
+ }
+ else
+ {
+ out << ch;
+ }
+ }
+}
+
+inline void DumpClassWithValue(std::ofstream& out, const IPLString& cssClass, const IPLString& lexeme)
+{
+ out << "<span class=\"" << cssClass << "\">" << lexeme << "</span>";
+}
+
+inline void DumpClassWithValue(std::ofstream& out, const IPLString& cssClass, double number)
+{
+ out << "<span class=\"" << cssClass << "\">" << number << "</span>";
+}
+
+inline void DumpClassWithFormattedLexeme(std::ofstream& out, const IPLString& cssClass, const IPLString& lexeme)
+{
+ out << "<span class=\"" << cssClass << "\">";
+ DumpCompatibleHTML(out, lexeme);
+ out << "</span>";
+}
+
+inline void DumpComment(std::ofstream& out, const Token& token)
+{
+ DumpClassWithFormattedLexeme(out, "comment", token.Lexeme);
+}
+
+inline void DumpIdentifier(std::ofstream& out, const Token& token)
+{
+ DumpClassWithFormattedLexeme(out, "identifier", token.Lexeme);
+}
+
+inline void DumpNumber(std::ofstream& out, const Token& token)
+{
+ DumpClassWithValue(out, "number", token.Number);
+}
+
+inline void DumpMisc(std::ofstream& out, const Token& token)
+{
+ DumpClassWithValue(out, "misc", token.Lexeme);
+}
+
+inline void DumpString(std::ofstream& out, const Token& token)
+{
+ auto str = token.Lexeme;
+ str.insert(str.begin(), '\\');
+ str.insert(str.end() - 1, '\\');
+ DumpClassWithValue(out, "string", str);
+}
+
+inline void DumpKeyword(std::ofstream& out, const Token& token)
+{
+ DumpClassWithValue(out, "keyword", token.Lexeme);
+}
+
+inline void DumpSingleKeyword(std::ofstream& out, const Token& token)
+{
+ DumpClassWithValue(out, "single-keyword", token.Lexeme);
+}
+
+inline void DumpOperatorKeyword(std::ofstream& out, const Token& token)
+{
+ DumpClassWithFormattedLexeme(out, "operator-keyword", token.Lexeme);
+}
+
+void DumpTokens(std::ofstream& out, const IPLVector<Token>& tokens)
+{
+ for (auto& token : tokens)
+ {
+ assert(token.Type != TokenType::Invalid);
+
+ switch (token.Type)
+ {
+ case TokenType::Comment:
+ DumpComment(out, token);
+ break;
+ case TokenType::Whitespace:
+ DumpCompatibleHTML(out, token.Lexeme);
+ break;
+ case TokenType::Identifier:
+ DumpIdentifier(out, token);
+ break;
+ case TokenType::Null:
+ case TokenType::Undefined:
+ case TokenType::True:
+ case TokenType::False:
+ DumpMisc(out, token);
+ break;
+ case TokenType::Number:
+ DumpNumber(out, token);
+ break;
+ case TokenType::String:
+ DumpString(out, token);
+ break;
+ case TokenType::Break:
+ case TokenType::Case:
+ case TokenType::Catch:
+ case TokenType::Class:
+ case TokenType::Continue:
+ case TokenType::Debugger:
+ case TokenType::Default:
+ case TokenType::Delete:
+ case TokenType::Do:
+ case TokenType::Else:
+ case TokenType::Export:
+ case TokenType::Extends:
+ case TokenType::Finally:
+ case TokenType::For:
+ case TokenType::Function:
+ case TokenType::If:
+ case TokenType::Import:
+ case TokenType::In:
+ case TokenType::Instanceof:
+ case TokenType::New:
+ case TokenType::Return:
+ case TokenType::Super:
+ case TokenType::Switch:
+ case TokenType::This:
+ case TokenType::Throw:
+ case TokenType::Try:
+ case TokenType::Typeof:
+ case TokenType::Void:
+ case TokenType::While:
+ case TokenType::With:
+ case TokenType::Yield:
+ case TokenType::Const:
+ case TokenType::Var:
+ case TokenType::Let:
+ case TokenType::Dot:
+ DumpKeyword(out, token);
+ break;
+ case TokenType::LeftParen:
+ case TokenType::RightParen:
+ case TokenType::LeftBrace:
+ case TokenType::RightBrace:
+ case TokenType::Comma:
+ case TokenType::Semicolon:
+ case TokenType::QuestionMark:
+ case TokenType::Colon:
+ case TokenType::LeftSquareBracket:
+ case TokenType::RightSquareBracket:
+ DumpSingleKeyword(out, token);
+ break;
+ case TokenType::PlusEqual:
+ case TokenType::MinusEqual:
+ case TokenType::Minus:
+ case TokenType::Plus:
+ case TokenType::Star:
+ case TokenType::Division:
+ case TokenType::Modulo:
+ case TokenType::BitwiseNot:
+ case TokenType::BitwiseAnd:
+ case TokenType::BitwiseXor:
+ case TokenType::BitwiseOr:
+ case TokenType::Bang:
+ case TokenType::BangEqual:
+ case TokenType::Equal:
+ case TokenType::EqualEqual:
+ case TokenType::StrictEqual:
+ case TokenType::StrictNotEqual:
+ case TokenType::MinusMinus:
+ case TokenType::PlusPlus:
+ case TokenType::LogicalAnd:
+ case TokenType::LogicalOr:
+ case TokenType::StarEqual:
+ case TokenType::DivideEqual:
+ case TokenType::ModuloEqual:
+ case TokenType::BitwiseAndEqual:
+ case TokenType::BitwiseXorEqual:
+ case TokenType::BitwiseOrEqual:
+ case TokenType::Greater:
+ case TokenType::GreaterEqual:
+ case TokenType::LessEqual:
+ case TokenType::Less:
+ case TokenType::RightShift:
+ case TokenType::LeftShift:
+ case TokenType::LeftShiftEqual:
+ case TokenType::RightShiftEqual:
+ DumpOperatorKeyword(out, token);
+ break;
+ case TokenType::Eof:
+ return;
+ default:
+ DumpMisc(out, token);
+ break;
+ }
+ }
+}
+
+bool DumpFormattedCode(const IPLVector<Token>& tokens, const IPLString& outName)
+{
+ auto dir = GetSolutionDir();
+ if (!dir.empty())
+ {
+ std::ofstream out(dir + outName);
+ if (out.good())
+ {
+ DumpFileBeginning(out);
+ DumpTokens(out, tokens);
+ DumpFileEnd(out);
+ out.close();
+ return true;
+ }
+ }
+
+ std::cerr << "Output file error.\n";
+ return false;
+}
+
+void PreviewFormattedCode(const IPLString& outName)
+{
+ auto dir = GetSolutionDir();
+ if (!dir.empty())
+ {
+ auto res = system((dir + outName).c_str());
+ if (res == -1)
+ {
+ switch (errno)
+ {
+ case ENOENT:
+ case E2BIG:
+ case ENOEXEC:
+ case ENOMEM:
+ std::cerr << "Unable to preview output file.\n";
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void FormatCode(const IPLString& in, const IPLString& out)
+{
+ IPLString code = GetInputCode(in);
+ if (!code.empty())
+ {
+ IPLVector<Token> tokens;
+ const auto& res = Tokenize(code.c_str(), tokens, { true, true });
+ if (!res.IsSuccessful)
+ {
+ std::cerr << "Lexer error at row " << res.Error.Row << " column " << res.Error.Column << ": " << res.Error.What;
+ return;
+ }
+
+ if (DumpFormattedCode(tokens, out))
+ {
+ PreviewFormattedCode(out);
+ }
+ }
+} \ No newline at end of file