/**
* @license
* Copyright 2020 Roberto Luiz Souza Monteiro,
* Renata Souza Barreto,
* Hernane Borges de Barros Pereira.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* MaiaScript virtual machine.
* @class
*/
function MaiaVM() {
init();
/**
* Creates the attributes of the class.
*/
function init() {
// Class attributes goes here.
compiledCode = {
'xml': '',
'mil': '',
'js': ''
}
}
/**
* Compiles MaiaScript code, contained in <script> tags for JavaScript
* and inserts the compiled code in a new <script> tag in the <body> tag
* of the document.
*
* MaiaScript codes must be in <script> tags of type 'text/maiascript',
* as in the following example:
*
* <script type='text/maiascript'> ... </script>
*
* This method must be called from the onLoad event of the document's
* <body> tag, as in the following example:
*
* <body onload='maiavm.compile()'> ... </body>
*/
this.compile = function() {
var scripts = document.querySelectorAll('script[type="text/maiascript"]');
for (index in scripts) {
if (typeof scripts[index].getAttribute != 'undefined') {
var fileName = scripts[index].getAttribute('src');
if (typeof fileName != 'undefined') {
if (fileName) {
compiledCode.maia = '';
fetch(fileName)
.then(response => response.text())
.then(data => {
var code = data;
if (typeof code != 'undefined') {
if (typeof code == 'string') {
compiledCode.xml = '';
function getXml(data) {
compiledCode.xml += data;
}
var s = new MaiaScript.XmlSerializer(getXml, true);
var maiaScriptParser = new MaiaScript(code, s);
try {
maiaScriptParser.parse_maiascript();
} catch (pe) {
if (!(pe instanceof maiaScriptParser.ParseException)) {
throw pe;
} else {
var parserError = maiaScriptParser.getErrorMessage(pe);
system.log(parserError);
throw parserError;
}
}
var parser = new DOMParser();
var xml = parser.parseFromString(compiledCode.xml, 'text/xml');
var compiler = new MaiaCompiler();
compiledCode.js = compiler.compile(xml);
try {
var script = document.createElement('script');
script.type = 'text/javascript';
script.text = compiledCode.js;
document.body.appendChild(script);
} catch (se) {
var scriptError = se.message;
system.log(scriptError);
throw scriptError;
}
}
}
});
}
}
}
var code = scripts[index].innerHTML;
if (typeof code != 'undefined') {
if (typeof code == 'string') {
compiledCode.xml = '';
function getXml(data) {
compiledCode.xml += data;
}
var s = new MaiaScript.XmlSerializer(getXml, true);
var maiaScriptParser = new MaiaScript(code, s);
try {
maiaScriptParser.parse_maiascript();
} catch (pe) {
if (!(pe instanceof maiaScriptParser.ParseException)) {
throw pe;
} else {
var parserError = maiaScriptParser.getErrorMessage(pe);
system.log(parserError);
throw parserError;
}
}
var parser = new DOMParser();
var xml = parser.parseFromString(compiledCode.xml, 'text/xml');
var compiler = new MaiaCompiler();
compiledCode.js = compiler.compile(xml);
try {
var script = document.createElement('script');
script.type = 'text/javascript';
script.text = compiledCode.js;
document.body.appendChild(script);
} catch (se) {
var scriptError = se.message;
system.log(scriptError);
throw scriptError;
}
}
}
}
}
/**
* Compiles the MaiaScript code passed as a command line argument
* and executes the code in the JavaScript interpreter from which
* this method was invoked.
*/
this.run = function() {
// Supports only the Node.js interpreter.
if (typeof process !== 'undefined') {
var command = 'node';
var argv = process.argv.slice();
compiledCode.xml = '';
var fs = require('fs');
var readTextFile = fs.readFileSync;
function getXml(data) {
compiledCode.xml += data;
}
function read(input) {
if (/^{.*}$/.test(input)) {
return input.substring(1, input.length - 1);
} else {
var content = readTextFile(input, 'utf-8');
return content.length > 0 && content.charCodeAt(0) == 0xFEFF ? content.substring(1) : content;
}
}
system.argv = argv.slice();
system.argc = argv.length;
var justCompile = false;
var inputFile;
var outputFile;
var outputFileType = 'js';
var outputContents = '';
if (argv.length > 2) {
var i = 2;
while (i < argv.length) {
if (argv[i] == '-c') {
justCompile = true;
outputFileType = 'js';
} else if (argv[i] == '-m') {
justCompile = true;
outputFileType = 'mil';
} else if (argv[i] == '-x') {
justCompile = true;
outputFileType = 'xml';
} else if ((argv[i] == '-h') || (argv[i] == '--help')) {
system.log('MaiaScript Command Line Interface (CLI)');
system.log('Usage: maiascript [options] [script.maia] [--] [arguments]');
system.log('Options:');
system.log('-c Just compile to JS, don\'t run the script;');
system.log('-m Just compile to MIL, don\'t run the script;');
system.log('-x Just compile to XML, don\'t run the script;');
system.log('-h --help Displays this help message;');
system.log('-o <script.js> Output file name;');
system.log(' -- End of compiler options.\n');
} else if (argv[i] == '-o') {
i++;
outputFile = argv[i];
} else if (argv[i] == '--') {
break;
} else {
inputFile = argv[i];
break;
}
i++;
}
system.argv = argv.slice(i);
system.argc = system.argv.length;
if (typeof inputFile != 'undefined') {
var code = read(String(inputFile));
var s = new MaiaScript.XmlSerializer(getXml, false);
var maiaScriptParser = new MaiaScript(code, s);
try {
maiaScriptParser.parse_maiascript();
} catch (pe) {
if (!(pe instanceof maiaScriptParser.ParseException)) {
throw pe;
} else {
var parserError = maiaScriptParser.getErrorMessage(pe);
system.log(parserError);
throw parserError;
}
}
var parser = new DOMParser();
var xml = parser.parseFromString(compiledCode.xml, 'text/xml');
var compiler = new MaiaCompiler();
compiledCode.mil = compiler.xmlToMil(xml);
compiledCode.js = compiler.compile(xml);
if (justCompile) {
if (typeof outputFile == 'undefined') {
var fileName = inputFile.split('.').shift();
if (outputFileType == 'js') {
outputFile = fileName + '.js';
outputContents = compiledCode.js;
} else if (outputFileType == 'mil') {
outputFile = fileName + '.mil';
outputContents = JSON.stringify(compiledCode.mil);
} else if (outputFileType == 'xml') {
outputFile = fileName + '.xml';
outputContents = compiledCode.xml;
} else {
outputFile = fileName + '.js';
outputContents = compiledCode.js;
}
} else {
outputContents = compiledCode.js;
}
fs.writeFile(outputFile, outputContents, function(err) {
if (err) {
throw err;
}
});
} else {
try {
const vm = require('vm');
const script = new vm.Script(compiledCode.js);
script.runInThisContext();
} catch (e) {
var evalError = e.message;
system.log(evalError);
}
}
} else {
system.log('MaiaScript Command Line Interface (CLI)');
system.log('Usage: maiascript [options] [script.maia] [--] [arguments]');
}
} else {
var options = {
input: process.stdin,
output: process.stdout
}
// Command prompt.
const readline = require('readline');
const rl = readline.createInterface(options);
rl.setPrompt(': ');
rl.prompt();
function runCommand(commandLine) {
var res;
if (commandLine.trim() == 'exit') {
process.exit(0);
}
try {
res = core.eval(commandLine);
} catch (e) {
var evalError = e.message;
system.log(evalError);
system.showMessageDialog(evalError);
}
if (typeof res != 'undefined') {
system.log(res);
}
rl.prompt();
}
rl.on('line', runCommand);
}
}
}
}
maiavm = new MaiaVM();
/*
* Run MaiaScript code if this script has been invoked
* from the command line.
*/
if (typeof process !== 'undefined') {
// Emulate DOM.
const jsdom = require("jsdom");
const {JSDOM} = jsdom;
var doc = new JSDOM();
var DOMParser = doc.window.DOMParser;
// Emulate Web SQL.
try {
const openDatabase = require('websql');
} catch (e) {
console.error(e.message);
}
var alert = system.log;
maiavm.run();
}