There was a mistake in some Javascript code where the decimal 0.04 was declared as 0.0.4 like the following:
var x = 0.0.4;
When this was run in Firefox the error given was:
SyntaxError: missing ; before statement
IE stated:
Expected ';'
And Chrome stated:
Uncaught SyntaxError: Unexpected number
I understand that 0.0.4 is not a number or a literal but how is Javascript trying to inerpret the statement? Why exactly does it think there is a missing ; ?
Chrome
Chrome sees the first part of the assignment as a floating point number 0.0, for which you want to access property at key 0, which is not allowed in JavaScript (you cannot use dot notation to reference numeric keys). In other words, you can split the assignment to the following equivalent:
var x = 0.0
x.0 // Throws unexpected number
In comparison, this is valid:
var x = 0.0.toString()
In my opinion, this is the most logical implementation of the parser with an error that makes most sense.
Firefox
Firefox sees the first part of the assignment as the floating point number 0.0, but gets confused about the .0 part - it does not recognise this as a property access and instead thinks you want to start a new statement (.4, which is a shorthand for 0.4) - thus it tells you you missed a semicolon, which is used to terminate statements.
It still correctly interprets the statement when you use a valid property accessor (a string):
var x = 0.0.toString()
Somewhat related is also this SO question which discusses similar behaviour.
Depending on the parser (browser) the way it handles a line of code may be different. My thoughts are that when IE and Firefox see a number they only "expect" a single decimal for a number and then numerical characters after it until either a space or a ';' occurs.
If another character type is encountered the parser would throw an exception that it was looking for the end of the number - hence the Expected ';'.
In the realm of how Chrome handled it, it seems like that it can tell it was supposed to be a number, but it was given in an invalid format.
The messages from IE and Firefox make perfect sense. Parse the number part of the statement as 0.0, perform the assignment x = 0.0, then expect an end of statement. If the character following isn't a semi-colon or newline (implicit end of statement), throw an error saying we expect one.
Chrome's is a little more cryptic, but still makes sense with a little thought. It has performed the assignment as with FF and IE (x = 0.0) but has interpreted the dot as a dot-operator rather than a decimal. (x = 0.0.toString() would be perfectly valid.) Rather than stating what it expected, it's stating what it saw, an "unexpected number", which was the 4.
It's unclear whether IE and FF first parsed the .4 as a number or if the unexpected character was simply a dot.
Related
For example,
1.toFixed(2) // Uncaught SyntaxError: Invalid or unexpected token
(1).toFixed(2) // "1.00"
let num = 1
num.toFixed(2) // "1.00"
At the same time, you don't have to wrap parenthesis around strings to call methods on them
'yo'.repeat(3) // "yoyoyo"
What is the rule at play here and where else does it apply? Guessing it has something to do with the dot being misinterpreted as a decimal for numbers?
Because the interpreter is looking for more digits (decimal values), not keywords or methods.
As others have stated, JavaScript is looking for more numbers after the decimal point. It thinks you are trying to type a float like 1.2 and it doesn't like that t there, it's not a number.
Interestingly, you can do this without parenthesis or making variable by using 2 decimal points. Like this: 1..toFixed(2). I guess you can also do 1.0.toFixed(2) if you want.
When using a variable, Javascript is confident that you're not going to add decimals after the point.
When not using a variable, Javascript thinks that you are going to add decimals after the point.
When you wrap your number with parenthesis, you say that the number is finished, and everything is fine again.
You can also use .. if you don't like parenthesis. The first one for decimals, the second one to call the method.
let num = 1;
console.log(num.toFixed(2));
// console.log(1.toFixed(2)); // ERROR
console.log((1).toFixed(2));
console.log(1..toFixed(2));
The following code throws an error in javascript:
console.log(String(+0n))
But this code runs successfully:
console.log(String(-0n))
Why +0n throws an error but -0n does not?
So that it doesn't break asm.js:
Unary + followed by an expression is always either a Number, or results in throwing. For this reason, unfortunately, + on a BigInt
needs to throw, rather than being symmetrical with + on Number:
Otherwise, previously "type-declared" asm.js code would now be
polymorphic.
As Bergi highlights in the comments, this was the least bad of three options:
+BigInt -> BigInt: breaks asm.js, and anything else that made the assumption "unary plus gives a Number";
+BigInt -> Number: conflicts with the design decision to disallow implicit conversions between Number and BigInt; or
+BigInt -> error.
+0n is treated as +(BigInt(0)), since unary + means "cast to integer", and it can't automatically do that (for some reason)
console.log(+(BigInt(0)));
-0n is treated as BigInt(-0), since negative numbers can be big integers
(You need to check your console for this, since I guess there's a bug in the StackSnippets preventing BigInts from being casted to a string in the console.log call)
console.log(BigInt(-0));
I am trying to make a web-app in JavaScript that converts arithmetic expressions to i486-compatible assembly. You can see it here:
http://flatassembler.000webhostapp.com/compiler.html
I have tried to make it able to deal with expressions that contain the incremental and decremental operators ("--" and "++"). Now it appears to correctly deal with expressions such as:
c++
However, in a response to an expression such as:
c--
the web-app responds with:
Tokenizer error: Unable to assign the type to the operator '-' (whether it's unary or binary).
The error message seems quite self-explanatory. Namely, I made the tokenizer assign to the "-" operator a type (unary or binary) and put the parentheses where they are needed, so that the parser can deal with the expressions such as:
10 * -2
And now, because of that, I am not able to implement the decremental operator. I've been thinking about this for days, and I can't decide what to even try. Do you have any ideas?
Please note that the web-app now correctly deals with the expressions such as:
a - -b
The way that this works in all existing languages (that I know of anyway) that have these operators, is that -- is a single token. So when you see a -, you check whether the very next character is another -. If it is, you generate a -- token (consuming both - characters). If it isn't, you generate a - token (leaving the next character in the buffer).
Then in the parser an l-expression, followed by -- token becomes a postfix decrement expression and -- followed by an l-expression becomes a prefix decrement expression. A -- token in any other position is a syntax error.
This means that spaces between -s matter: --x is a prefix decrement (or a syntax error if the language doesn't allow prefix increment and decrement), - -x is a double negative that cancels out to just x.
I should also note that in languages where postfix increment/decrement is an expression, it evaluates to the original value of the operand, not the incremented value. So if x starts out as 5, the value of x++ should be 5 and afterwards the value of x should be 6. So your current code does not actually correctly implement postfix ++ (or at least not in a way consistent with other languages). Also x++ + y++ currently produces a syntax error, so it doesn't seem like it's really supported at all.
Why the first line below gives error although the second and third lines work fine?
1.toString(); // SyntaxError
(1).toString(); // OK
1['toString'](); // OK
The . presents ambiguity. Is it a decimal, or a property accessor?
The interpreter sees it as a decimal, so you can use .. to allow both the decimal, then the property syntax.
1..toString();
Or use one of the other ways you show to resolve the ambiguity.
The parser is trying to treat 1. as the start of a floating-point literal -- only toString turns it into an invalid number.
Compare with:
1.0.toString()
In (1).toString(), (1) forces it to evaluate before .toString() so it works.
In 1.toString(), 1 is not a valid identifier so it does not work.
In Javascript, using the dot (.) can be interpreted in one of two ways:
As a Property Accessor (e.g., var prop = myObject.prop;).
As part of a Floating-point Literal (e.g. var num = 1.5;).
In the above case, the leading 1. in 1.toString() is interpreted as a floating point number, hence the error:
SyntaxError: identifier starts immediately after numeric literal (learn more)
This is the same error you get if you try and declare a variable that starts with a number: var 1person = 'john';
To prevent the interpreter from seeing the 1. as a decimal and instead see it as accessing a property on our literal 1, there are several ways to accomplish this:
// Via white-space after the numeric literal
1 .toString();
1
.toString();
// Via a grouping-operator, aka, parentheses
// #see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Grouping_operator
(1).toString();
// Via an additional dot. Made clearer with parentheses as `(1.).toString()`
1..toString();
// Via an explicit fractional part (because `1. === 1.0`)
1.0.toString();
// Via bracket notation
1['toString']();
1.['toString']();
1.0['toString']();
I'm using jslint.com to validate some functions and came across the error:
"A leading decimal point can be confused with a dot"
The line which triggered the error is as follows:
if ( myvar = .95 ){
How do I correct it?
Easy, put a zero before the dot. I guess JSLint complains because the dot is also used for object properties so it can be confused. Plus you're missing an equals, but in JS is recommended to use triple equals:
if (myvar === 0.95) { ... }
Now JSLint won't complain anymore.
That's not a real Javascript error. Javascript will work fine without the leading 0. However, to prevent JSLint from showing that error, just add the leading 0:
if ( myvar = 0.95 ){
It's clearer, but not actually necessary.
And are you sure you're not trying to use two equals signs, as in ==? The = operator is for assignment, while the == operator is for comparison.