Currently I am busy with parsers and tried ANTLR. I understand the grammar so far and now I wanted to implement it in javascript.
Here is a small but important snippet of my code.
if (selected == "Funktionen") {
console.log("You selected functions")
const chars = new antlr4.InputStream(data.stringToLex);
const lexer = new FunktionLexer(chars);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new FunktionParser(tokens);
parser.buildParseTrees = true;
const tree = parser.start();
tree.accept(new Visitor());
}
My visitor looks like this
class Visitor {
visitChildren(ctx) {
if (!ctx) {
return;
}
if (ctx.children) {
return ctx.children.map(child => {
if (child.children && child.children.length != 0) {
return child.accept(this);
} else {
return child.getText();
}
});
}
}
}
I have oriented myself to this tutorial and everything works.
https://github.com/antlr/antlr4/blob/master/doc/javascript-target.md
http://lab.antlr.org/ Just hit on start and u will see what I mean.
The object of my tree I get back from my start() function with a right input looks like this:
The big problem is, I want to get the Tree and output it (at least in console log), like on the official ANTLR lab website.
The big problem is, I want to get the Tree and output it
The object returned by parser.start() is the tree of your parsed input. You don't need a visitor for this.
What you mean by "and output it", I do not know. Just print it to your console? That can be done by doing:
const tree = parser.start();
console.log(tree.toStringTree(parser));
// or if the line above doesn't work, try:
// console.log(tree.toStringTree());
Related
I'm working on a site that takes fairly long to build/deploy. I sometimes need information that is only available server-side for debugging. Using console.log is annoying since adding a console.log in the code and building takes too long.
But I also don't want the site to always log that information to the console.
My plan was to have a wrapper function for console.log, that checks if there is e.g dev_config set in localStorage.
For example to activate certain verbose levels that then show respective logs, or log only in certain sections.
Would this have a significant impact on performance of the site?
For instance something like this:
const devLog = (message) => {
devConfig = JSON.parse(localStorage.getItem('dev_config'))
if (devConfig != null) {
// ...
// other checks (set devMode to true)
// ...
if (devMode === true) {
const now = new Date()
const hours = now.getHours()
const min = (now.getMinutes() + '').padStart(2, '0')
const sec = (now.getSeconds() + '').padStart(2, '0')
console.log(`[${hours}:${min}:${sec}] `, message)
}
}
}
PS: I am aware of the built-in browser dev tools and I am using them in most cases. But since the information in my current problem is server side, I don't think I can get with the dev tools what I need.
You could overwrite console.log but that could annoy you later on. I prefer to have my own logger like your devLog function. It's more explicit.
As #Barmar suggested in the comments you could instead check the localStorage on load instead of on every call. I have something similar to the below in a few projects of mine:
{
let devConfig = JSON.parse(localStorage.getItem('dev_config'));
devLog = (...args) => {
if (devConfig) {
const time = new Date().toLocaleTimeString()
console.log(`[${time}] `, ...args)
}
};
devLog.activate = () => {
devConfig = true;
localStorage.setItem('dev_config', true)
}
devLog.deactivate = () => {
devConfig = false;
localStorage.setItem('dev_config', false)
}
devLog.toggle = () => {
if ( devConfig ) {
devLog.deactivate()
} else {
devLog.activate()
}
}
}
Since when you're reading dev_config from the localStorage for the first time you'll get null it will start off deactivated - which seems like a good default to me.
I've been able to sort out the middle bit (the API seems to be called to just fine) along with the submenu displaying. Originally I thought that just the end part wasn't working but I'm now thinking that the selection part isn't either.
What am I doing wrong with the getSelection() and what do I need to do to insert a link into said selection? (to clarify, not to replace the text with a link, but to insert a link into the text)
//Open trigger to get menu
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Scry', 'serumVisions')
.addToUi();
}
//Installation trigger
function onInstall(e) {
onOpen(e);
}
//I'm not sure if I need to do this but in case; declare var elements first
var elements
// Get selected text (not working)
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var elements = selection.getRangeElements();
Logger.log(elements);
} else {
var elements = "Lack of selection"
Logger.log("Lack of selection");
}
}
//Test run
// insert here
// Search Function
function searchFunction(nameTag) {
// API call + inserted Value
let URL = "https://api.scryfall.com/cards/named?exact=" + nameTag;
// Grabbing response
let response = UrlFetchApp.fetch(URL, {muteHttpExceptions: true});
let json = response.getContentText();
// Translation
let data = JSON.parse(json);
// Jackpot
let link = data.scryfall_uri;
// Output
Logger.log(link);
}
// Test run
searchFunction("Lightning Bolt");
//Let's hope this works how I think it works
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
// Unsure what class I'm supposed to use, this doesn't
const insertLink = DocumentApp.getActiveDocument().getSelection().newRichTextValue()
.setLinkUrl(linkage);
Logger.log(linkage);
}
For the first part, I tried the getSelection() and getCursor() examples from the Google documentation but they don't seem to work, they all just keep returning null.
For the inserting link bit, I read all those classes from the Spreadsheet section of the documentation, at the time I was unaware but now knowing, I haven't been able to find a version of the same task for Google Docs. Maybe it works but I'm writing it wrong as well, idk.
Modification points:
In your script, the functions of getSelectedText() and searchFunction(nameTag) return no values. I think that this might be the reason for your current issue of they all just keep returning null..
elements of var elements = selection.getRangeElements(); is not text data.
DocumentApp.getActiveDocument().getSelection() has no method of newRichTextValue().
In the case of searchFunction("Lightning Bolt");, when the script is run, this function is always run. Please be careful about this.
When these points are reflected in your script, how about the following modification?
Modified script:
Please remove searchFunction("Lightning Bolt");. And, in this case, var elements is not used. Please be careful about this.
From your script, I guessed that in your situation, you might have wanted to run serumVisions(). And also, I thought that you might have wanted to run the individual function. So, I modified your script as follows.
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
var text = "";
if (selection) {
text = selection.getRangeElements()[0].getElement().asText().getText().trim();
Logger.log(text);
} else {
text = "Lack of selection"
Logger.log("Lack of selection");
}
return text;
}
function searchFunction(nameTag) {
let URL = "https://api.scryfall.com/cards/named?exact=" + encodeURIComponent(nameTag);
let response = UrlFetchApp.fetch(URL, { muteHttpExceptions: true });
let json = response.getContentText();
let data = JSON.parse(json);
let link = data.scryfall_uri;
Logger.log(link);
return link;
}
// Please run this function.
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
if (linkage) {
Logger.log(linkage);
DocumentApp.getActiveDocument().getSelection().getRangeElements()[0].getElement().asText().editAsText().setLinkUrl(linkage);
}
}
When you select the text of "Lightning Bolt" in the Google Document and run the function serumVisions(), the text of Lightning Bolt is retrieved, and the URL like https://scryfall.com/card/2x2/117/lightning-bolt?utm_source=api is retrieved. And, this link is set to the selected text of "Lightning Bolt".
Reference:
getSelection()
I have multiple javascript files in a folder and I want to make sure that every file has comment in the beginning (that will explain the summary of file).
/*
This file will......
*/
function test () {
....
}
So is this possible using gulp-contains or something else?
I think this would be enough just to make sure if start of a file is the comment initial characters (/*)
gulp.src('./file.js')
.pipe(map(function(file, callback) {
var startWithComment = file.contents.toString().replace(/\n|\r/g, "").trim().startsWith("/*");
if (startWithComment){
// DO YOUR CHORES
}
}))
Another approach is to split the initial text to make sure if it is a valid multi-line comment.
function startsWithValidMultiLineComment(str){
try{
return str.replace(/\n|\r/g, "").trim().split("/*")[1].split("*/")[1].length > 0
} catch (e){
return false;
}
}
Following this approach str.split("/*")[1].split("*/")[0] would be your comment text
By using the regex provided by #Sajjad in previous answer. I have managed to achieve my goal. I have used gulp-if and gulp-fail instead (I find it more flexible).
Here is how I do that:
var condition = function (file) {
sFile = require('path').parse(file.path).name;
var startWithComment = file.contents.toString().replace(/\n|\r/g, "").trim().startsWith("/*");
return (!startWithComment);
}
gulp.task('taskName',
function() {
gulp.src('files/*.js')
.pipe(gulpIf(condition, fail(function () {
var message = 'Some message';
return message;
})));
});
It's been days since I'm trying several ways to solve this exercice. I give up. What am I doing wrong here ? Why am I getting "write after end" error if the event I'm using is the "end" event and I don't write anything to the pipe ? I'm just changing an object after it's use. Or at least I think so.
var duplexer2 = require("duplexer2");
var through = require('through2');
module.exports = function (counter) {
var countries = {};
var duplex = duplexer2(through.obj(function (obj, encoding, done) {
if (obj.country in countries)
countries[obj.country]++;
else
countries[obj.country] = 1;
done();
}), counter);
duplex.on("finish", function() {
counter.setCounts(countries);
});
counter.pipe(duplex);
return duplex;
};
If I substitute the line counter.setCounts(countries); for console.log(countries) I see that it's populated correctly.
Problem text: http://pastebin.com/vAM4vKZg
I have read this exercice test file and counldn't get any clue from it as it only compares the objects to see if they're correct.
Your solution is almost correct. Just remove the counter.pipe(duplex); line and it works. You do not need to pipe anything to the duplex stream you created, the stream adventure is going to do that to check if it works :).
I want to use the built-in preference system for my xulrunner (Firefox) application. But I can't figure out how to easily drive the user interface based on preferences.
The user can specify a list of home pages, and each home page will show up in a different tab. Because the tabs are in the presentation layer, I'd like to create them using a template in the xul code. Is this possible?
I haven't seen a way to do this with xul templates. Is there an alternative templating system that would allow me to change the UI based on user preferences?
No, templating in XUL is not powerful enough, so you're stuck with writing JavaScript code that reads the preferences and opens the needed tabs.
XML.prototype.function::domNode = function domNode() {
function addPrefix(prefix, name) {
if (typeof(prefix) == "undefined" || prefix == null || prefix == "") {
return name;
} else {
return prefix + ":" + name;
}
}
function recurse(xml) {
var domNode = document.createElementNS(xml.namespace().uri, addPrefix(xml.namespace().prefix, xml.localName()));
for each (let attr in xml.#*::*) {
let attrNode = document.createAttributeNS(attr.namespace().uri, addPrefix(attr.namespace().prefix, attr.localName()));
attrNode.nodeValue = attr;
domNode.setAttributeNode(attrNode);
}
if (xml.hasComplexContent()) {
for each (let node in xml.*) {
domNode.appendChild(recurse(node));
}
} else if (xml.hasSimpleContent()) {
domNode.appendChild(document.createTextNode(xml));
}
return domNode;
}
return recurse(this);
};
var name = "example"
var xml = {name};
document.querySelector("#example-statusbar-panel").appendChild(xml.domNode());
works as a charm, there's some minor glitches with namespaces though.
You could always convert dom back to XML with
var str = serializer.serializeToString( xml.domNode() );