PEG.js: how to use prompt? - javascript

I'm creating a C++ parser with PEG.js, and I need to be able to use cin. With the after-match JS, when I use prompt(), the (alternate) online version throws an error of 'Parse Error: prompt is not defined'. I am trying to use the initializer to create a function to replicate prompt (probably not optimized, I was just trying it as a solution). However, when I do this, it still gives me the error. I have tried using window.prompt as well, but again, it does not work. Here's an example of what I'm doing:
{
function cin() {
window.prompt("");
}
function changeVar(variable, newValue) {
if(typeof variable === typeof newValue) {
variable = newValue;
} else if(typeof variable === 'undefined') {
alert("You can't assign a value to a variable if the variable isn't declared yet!");
} else {
alert("Bad assignment. In C++, a variable *must* have the same type *all the time*.");
}
}
}
stdin =
whitespace* "std::cin" whitespace* ">>" whitespace* varToBeChanged:[a-zA-Z_]+ ";" whitespace*
{ changeVar(varToBeChanged, cin('')); return varToBeChanged; }
whitespace =
space:[ \t]
{ return space; }
and then in the parser testing field:
std::cin >> variable;
Thank you for looking. I have tried Googling this and SO-searching this but I haven't found any results.
Also, here is the main piece of code, for all the (current) extra information anyone needs. I am having some problems with this as well, but I'll try to figure them out on my own before I post another question.

If you are using http://peg.arcanis.fr/, then the parser code is executed inside of a Web Worker - which has no access to any UI like the window or the DOM. The error "undefined variable" means literally that there is no window or prompt declared.
If you paste your code into http://pegjs.majda.cz/online, it is executed in the web page environment and works flawlessly.

Related

I have an anonymous function without parentheses, how does this work?

New to javascript,but i know that form
<script>(function(){ somecode })();</script>
will immediately run somecode when it be interpreted.But when i was reading a html5 game source code,I encountered some code which form like this:
<script>(function(){})</script>
There is no parentheses attached.So what does it mean?
source code:https://github.com/oxyflour/STGame
and the index.html has code form like below:
<script>(function(){})</script>
Refer the game.js file, they are using it as nodes that don't do anything(#Shilly) and accessing them with id in the script tag. I don't know what is being done with the d object but certainly it is being called somewhere, look how they're using the innerHTML
else if (v.tagName == 'SCRIPT' && $attr(v, 'type') == 'text/html') {
d[v.id] = v.innerHTML;
} else if (v.tagName == 'SCRIPT') {
d[v.id] = eval(v.innerHTML)(_t);
}
An example of what's being done:
eval(document.getElementById('myscript').innerHTML)('test');
<script id="myscript">
(function(a) {
a ? console.log(a) : console.log('some string')
})
</script>
In the game.js source I found this piece of code after a quick scan:
// ... line 702
else if (v.tagName == 'SCRIPT') {
d[v.id] = eval(v.innerHTML)(_t);
}
// ...
So it's getting the innerHTML of the <script/> tag and executing it via eval().
As far as I can tell, this does nothing. It only evaluates and returns, so no call or anything.
The (function(){})() is called an IIFE - Immediately Invoked Function Expression). This, however, is an IIFE without the last parentheses (() at the end), which means it will not be called right after its definition.
Therefore, the purpose of this code might be either to keep for later use or maybe the person writing it forgot to call it or something similar. It's not a pattern that is actually used anywhere that I have seen.

Unable to set property...of undefined or null reference

I inherited a SharePoint site that deploys several apps. Everything had been working fine for a year and out of no where all the apps stopped loading and I used developer tools in IE11 and got the following: "SCRIPT5007: Unable to set property 'relatedNavigationProperty' of undefined or null reference". This is the first time I've used angular so I'm not great with it. The file I'm looking at doesn't even have a 'relatedNavigationProperty' property. I've been scouring the web for hours trying to figure this out to no avail. Any suggestions for what I should be looking for would be greatly appreciated.
Looked through all related scripts for relatedNavigationProperty
Checked Emulation information- Document mode = 11
Verified that this is an issue for all users
function createInternalInjector(cache, factory) {
function getService(serviceName) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
serviceName + ' <- ' + path.join(' <- '));
}
return cache[serviceName];
} else {
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
}
throw err;
} finally {
path.shift();
}
}
}
I expect apps to be loading and working as they previously were but the landing page loads and will not continue on to the apps
Developer tools throws the error at the 'throw err' line...obviously
This error Unable to set propertyrelatedNavigationPropertyof undefined or null reference implies that the property called relatedNavigationProperty is being set on a variable that has a value of undefined or null.
For example:
undefined.myProp = true;
null.myProp = true;
You need to log out the values of cache, factory, and any other variables in that code to see what's happening. relatedNavigationProperty is probably being passed in.

How to change a global var in an if statement and then reuse that change in another if statement?

I'm running a game.js file in a Perlenspiel engine. I have a global variable called
var hasKey;
In the PS.keyDown = function I'm running this
var hasKey;
if(dataAtScout == "key"){
hasKey = true;
PS.audioPlay("fx_jump8");
PS.debug("Scout has picked up an odd key")
}
if(dataAtScout == "exit"){
Scout.x = oldSX;
Scout.y = oldSY;
PS.debug("\nTheres a computer at the door.")
if(hasKey == true){
PS.debug("\nThe door creaks open as Scout runs into a cornfield.")
}
else{
PS.debug("\nError... Error... Error... Error")
}
}
I'm wanting to check if the key has been picked up while the player is at the exit. However, I am not able to do so. I've tried many, many things and this is the last hurdle that is stumping me. I want to change hasKey = true globally so that when dataAtScout = "exit" it will confirm that the variable has changed to true. So, in my dataAtScout = "key", how can I changed the hasKey variable to true, globally, to be confirmed later by another if statement?
I saw another post with a similar question and the conclusion was that a reset(); needed to be called. I tried that but it didn't work.
Any and all help is greatly appreciated!
You stated: "In the PS.keyDown = function I'm running this", and then: var hasKey;, from which I understand that the code you are showing is the body or part of the body of the function aforementioned, therefore your hasKey variable is local to this function.
Remove the var hasKey; (from inside your function) statement to use the global variable.
PS. disclaimer: you should never use global variables.

Why is this function considered to be a constructor by linters?

I've been rewriting various bits of code I've 'inherited' and come across something I don't understand. Both jslint and jshint think the below function is a constructor, and I have no idea why.
function GEReqsDone(failed) {
if (!failed) {
alert('Thank you for your submission! The page will now be reloaded.');
document.location.replace(mwConfig.wgScript + '?title=' + encodeURIComponent(mwConfig.wgPageName) + '&action=purge');
} else {
alert('An error occurred while submitting the edit.');
button.disabled = false;
button.innerHTML = 'Update price';
}
}
This is a callback from query using $.ajax() that queries the mediawiki API to automatically edit to update a price on a page. If the edit succeeds failed is not defined and the page reloads. If it fails, failed is set to true and it resets the button used to trigger the update.
button is simply a button element, the wg* variables are part of the mediaWiki object here used to access the pagename and url prefix (usually /index.php).
Does anyone know why jshint and jslint seem to think this function should be new GEReqsDone() rather than GEReqsDone()?
Constructors are the only functions in JavaScript that should start with a capital letter. JSLint/JSHint will see that it starts with an uppercase G and assume it is a constructor.
This is the only convention we have to make sure people know that the function should be used as a constructor. Some people write defensively to avoid people missing the new keyword:
var SomeConstructor = function () {
if (!(this instanceof SomeConstructor))
return new SomeConstructor();
}

Should I be removing console.log from production code?

I currently have this JS statement everywhere in my code:
window.console && console.log("Foo");
I am wondering if this is costly at all, or has any negative side-effects in production.
Am I free to leave client-side logging in, or should it go?
EDIT: In the end, I suppose the best argument I (and anyone else?) can come up with is that there is a possibly non-negligible amount of extra data transferred between the server and the client by leaving logging messages left in. If production code is to be fully optimized, logging will have to be removed to reduce the size of javascript being sent to the client.
Another way of dealing with this is to 'stub' out the console object when it isn't defined so no errors are thrown in contexts that do not have the console i.e.
if (!window.console) {
var noOp = function(){}; // no-op function
console = {
log: noOp,
warn: noOp,
error: noOp
}
}
you get the idea... there are a lot of functions defined on the various implementations of the console, so you could stub them all or just the ones you use (e.g. if you only ever use console.log and never used console.profile, console.time etc...)
This for me is a better alternative in development than adding conditionals in front of every call, or not using them.
see also: Is it a bad idea to leave "console.log()" calls in your producton JavaScript code?
You should not add development tools to a production page.
To answer the other question: The code cannot have a negative side-effect:
window.console will evaluate to false if console is not defined
console.log("Foo") will print the message to the console when it's defined (provided that the page does not overwrite console.log by a non-function).
UglifyJS2
If you are using this minifier, you can set drop_console option:
Pass true to discard calls to console.* functions
So I would suggest to leave console.log calls as they are for a most trickiest part of the codebase.
If minification is part of your build process, you may use it to strip out debug code, as explained here with Google closure compiler: Exclude debug JavaScript code during minification
if (DEBUG) {
console.log("Won't be logged if compiled with --define='DEBUG=false'")
}
If you compile with advanced optimizations, this code will even be identified as dead and removed entirely
Yes. console.log will throw an exception in browsers that don't have support for it (console object will not be found).
Generally yes, its not a great idea to expose log messages in your production code.
Ideally, you should remove such log messages with a build script before deployment; but many (most) people do not use a build process (including me).
Here's a short snippet of some code I've been using lately to solve this dilemma. It fixes errors caused by an undefined console in old IE, as well as disabling logging if in "development_mode".
// fn to add blank (noOp) function for all console methods
var addConsoleNoOp = function (window) {
var names = ["log", "debug", "info", "warn", "error",
"assert", "dir", "dirxml", "group", "groupEnd", "time",
"timeEnd", "count", "trace", "profile", "profileEnd"],
i, l = names.length,
noOp = function () {};
window.console = {};
for (i = 0; i < l; i = i + 1) {
window.console[names[i]] = noOp;
}
};
// call addConsoleNoOp() if console is undefined or if in production
if (!window.console || !window.development_mode) {
this.addConsoleNoOp(window);
}
I'm pretty sure I took much of the above addConsoleNoOp f'n from another answer on SO, but cannot find right now. I'll add a reference later if I find it.
edit: Not the post I was thinking of, but here's a similar approach: https://github.com/paulmillr/console-polyfill/blob/master/index.js
var AppLogger = (function () {
var debug = false;
var AppLogger = function (isDebug) {
debug = isDebug;
}
AppLogger.conlog = function (data) {
if (window.console && debug) {
console.log(data);
}
}
AppLogger.prototype = {
conlog: function (data) {
if (window.console && debug) {
console.log(data);
}
}
};
return AppLogger;
})();
Usage:
var debugMode=true;
var appLogger = new AppLogger(debugMode);
appLogger.conlog('test');
Don't overcomplicate things! I personally use console.log all the time during development, it's just such a timesaver. For production i just add a single line of code (in the "production profile" in my case) that disable all logs:
window.console.log = () => {};
done ;)
This monkey patches window.console and replace the log function with an empty function, disabling the output.
This is good enough for me in most cases. If you want to go "all the way" and remove console.logs from your code to decrease bundle size, you have to change the way your js is bundled (e.g. drop console.logs with minifier or something)
Also I think you CAN actually make a strong point for leaving them in - even in production. It doesn't change anything for a normal user but can really speed up understanding weird "exotic-browser" problems. It's not like it's backend-logs that may contain critical information. It's all on the frontend anyway, not showing a log message because you are scared to reveal something a user shouldn't know really is only "security by obscurity" and should make you think why this information is even available on the frontend in the first place. Just my opinion.
Yes, its good practice to use console.log for javascript debugging purpose, but it needs to be removed from the production server or if needed can be added on production server with some key points to be taken into consideration:
**var isDebugEnabled="Get boolean value from Configuration file to check whether debug is enabled or not".**
if (window.console && isDebugEnabled) {
console.log("Debug Message");
}
Above code block has to be used everywhere for logging in order to first verify whether the console is supported for the current browser and whether debug is enabled or not.
isDebugEnabled has to be set as true or false based on our
environment.
TL;DR
Idea: Logging objects precludes them from being Garbage Collected.
Details
If you pass objects to console.log then these objects are accessible by reference from console of DevTools. You may check it by logging object, mutating it and finding that old messages reflect later changes of the object.
If logs are too long old messages do get deleted in Chrome.
If logs are short then old messages are not removed, if these messages reference objects then these objects are not Garbage Collected.
It's just an idea: I checked points 1 and 2 but not 3.
Solution
If you want to keep logs for sake of client-side troubleshooting or other needs then:
['log', 'warn', 'error'].forEach( (meth) => {
const _meth = window.console[meth].bind(console);
window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});
If the workflow is done using the right tools such as parcel/webpack then it's no longer a headache, because with the production build console.log is being dropped. Even few years earlier with Gulp/Grunt it could've been automated as well.
Many of the modern frameworks such as Angular, React, Svelte, Vue.js come with that setup out-of-the-box. Basically, you don't have to do anything, as long as you deploy the correct build, i.e. production one, not development which will still have console.log.
I basically overwrite the console.log function with the one what has knowledge of where the code is being run. Thus i can keep using console.log as I do always. It automatically knows that I am in dev/qa mode or in production. There is also a way to force it.
Here is a working fiddle.
http://jsfiddle.net/bsurela/Zneek/
Here is the snippet as stack overflow is intimated by people posting jsfiddle
log:function(obj)
{
if(window.location.hostname === domainName)
{
if(window.myLogger.force === true)
{
window.myLogger.original.apply(this,arguments);
}
}else {
window.myLogger.original.apply(this,arguments);
}
},
I know this is quite an old question and hasn't had much activity in a while. I just wanted to add my solution that I came up with which seems to work quite well for me.
/**
* Logger For Console Logging
*/
Global.loggingEnabled = true;
Global.logMode = 'all';
Global.log = (mode, string) => {
if(Global.loggingEnabled){
switch(mode){
case 'debug':
if(Global.logMode == 'debug' || Global.logMode == 'all'){
console.log('Debug: '+JSON.stringify(string));
}
break;
case 'error':
if(Global.logMode == 'error' || Global.logMode == 'all'){
console.log('Error: '+JSON.stringify(string));
}
break;
case 'info':
if(Global.logMode == 'info' || Global.logMode == 'all'){
console.log('Info: '+JSON.stringify(string));
}
break;
}
}
}
Then I typically create a function in my scripts like this or you could make it available in a global script:
Something.fail = (message_string, data, error_type, function_name, line_number) => {
try{
if(error_type == undefined){
error_type = 'error';
}
Global.showErrorMessage(message_string, true);
Global.spinner(100, false);
Global.log(error_type, function_name);
Global.log(error_type, 'Line: '+line_number);
Global.log(error_type, 'Error: '+data);
}catch(error){
if(is_global){
Global.spinner(100, false);
Global.log('error', 'Error: '+error);
Global.log('error', 'Undefined Error...');
}else{
console.log('Error:'+error);
console.log('Global Not Loaded!');
}
}
}
And then I just use that instead of console.log like this:
try{
// To Do Somehting
Something.fail('Debug Something', data, 'debug', 'myFunc()', new Error().lineNumber);
}catch(error){
Something.fail('Something Failed', error, 'error', 'myFunc()', new Error().lineNumber);
}

Categories