Commit graph

113 commits

Author SHA1 Message Date
Andreas Kling
9ebd066ac8 LibJS: Add support for "continue" inside "for" statements :^) 2020-04-05 00:22:42 +02:00
Andreas Kling
5e40aa182b LibJS: Support VariableDeclaration with multiple declarators
This patch adds support in the parser and interpreter for this:

    var a = 1, b = 2, c = a + b;

VariableDeclaration is now a sequence of VariableDeclarators. :^)
2020-04-04 21:47:12 +02:00
Andreas Kling
9691286cf0 LibJS: Add Declaration class to the AST
This is just here to make the AST class hierarchy more spec-like.
2020-04-04 21:32:10 +02:00
Andreas Kling
f8393b80e3 LibJS: Add support for do..while statements 2020-04-04 21:29:23 +02:00
Andreas Kling
da0715aba9 LibJS: Rename WhileStatement::predicate() => body()
This name matches other parsers.
2020-04-04 21:22:03 +02:00
Andreas Kling
644ff1bbfd LibJS: Add basic support for modulo (%) in binary expressions 2020-04-04 21:17:34 +02:00
Andreas Kling
0622181d1f LibJS: Implement ConditionalExpression (ternary "?:" operator) 2020-04-03 12:15:14 +02:00
Linus Groh
2636cac6e4 LibJS: Remove UndefinedLiteral, add undefined to global object
There is no such thing as a "undefined literal" in JS - undefined is
just a property on the global object with a value of undefined.
This is pretty similar to NaN.

var undefined = "foo"; is a perfectly fine AssignmentExpression :^)
2020-04-03 00:10:52 +02:00
Linus Groh
a62230770b LibJS: Implement unary plus / minus 2020-04-02 19:55:45 +02:00
Andreas Kling
cd9379dca9 LibJS: Reorganize computing of |this| for CallExpressions
This avoids executing the LHS of the object expression twice when doing
a call on the result of an object expression.
2020-04-01 18:57:00 +02:00
Andreas Kling
2285f84596 LibJS: Implement basic execution of "switch" statements
The "break" keyword now unwinds to the nearest ScopeType::Breakable.
There's no support for break labels yet, but we'll get there too.
2020-03-29 15:03:58 +02:00
Andreas Kling
1923051c5b LibJS: Lexer and parser support for "switch" statements 2020-03-29 15:03:58 +02:00
Andreas Kling
a3d92b1210 LibJS: Implement the "instanceof" operator
This operator walks the prototype chain of the RHS value and looks for
a "prototype" property with the same value as the prototype of the LHS.

This is pretty cool. :^)
2020-03-28 16:56:54 +01:00
Andreas Kling
0593ce406b LibJS: Implement basic support for the "new" keyword
NewExpression mostly piggybacks on the existing CallExpression. The big
difference is that "new" creates a new Object and passes it as |this|
to the callee.
2020-03-28 16:33:52 +01:00
Andreas Kling
faddf3a1db LibJS: Implement "throw"
You can now throw an expression to the nearest catcher! :^)

To support throwing arbitrary values, I added an Exception class that
sits as a wrapper around whatever is thrown. In the future it will be
a logical place to store a call stack.
2020-03-24 22:21:58 +01:00
Andreas Kling
c33d4aefc3 LibJS: Parse "try", "catch" and "finally"
This is the first step towards support exceptions. :^)
2020-03-24 16:14:10 +01:00
Andreas Kling
df524203b2 LibJS: Consume semicolon at the end of a statement
A bunch of code was relying on this not happenind, in particular the
parsing of "for" statements. Reorganized things so they work again.
2020-03-23 19:10:18 +01:00
Andreas Kling
fbb9e1b715 LibJS: Implement "else" parsing
We can now handle scripts with if/else in LibJS. Most of the changes
are about fixing IfStatement to store the consequent and alternate node
as Statements.

Interpreter now also runs Statements, rather than running ScopeNodes.
2020-03-23 16:52:58 +01:00
Andreas Kling
cccbe43056 LibJS: Use FlyString for identifiers
This makes variable and property lookups a lot faster since comparing
two FlyStrings is O(1).
2020-03-22 13:03:43 +01:00
Andreas Kling
7c48c3c8e1 LibJS: Parse "if" statements
This patch implements basic parsing of "if" statements. We don't yet
support parsing "else", so I added a FIXME about that.
2020-03-21 18:40:17 +01:00
Andreas Kling
00feef8642 LibJS: Some optimizations for ObjectExpression
- move() the property map when constructing ObjectExpression instead of
  making a copy.
- Use key+value iterators to traverse the property map in the execute()
  and dump() functions.
2020-03-21 13:11:51 +01:00
0xtechnobabble
bc002f807a LibJS: Parse object expressions 2020-03-21 10:08:58 +01:00
Andreas Kling
a3d2e07446 LibJS: Parse computed MemberExpressions
MemberExpression comes in two flavors:

    computed: a[b]
non-computed: a.b

We can now parse both of the types. :^)
2020-03-20 21:56:40 +01:00
Andreas Kling
a82f64d3d6 LibJS: Parse ArrayExpression and start implementing Array objects
Note that property lookup is not functional yet.
2020-03-20 21:56:40 +01:00
Andreas Kling
1a10470c1d LibJS: Implement basic object property assignment
This is pretty naive, we just walk up the prototype chain and call any
NativeProperty setter that we find. If we don't find one, we put/set
the value as an own property of the object itself.
2020-03-19 17:44:06 +01:00
Andreas Kling
07679e347c LibJS: Parse FunctionExpressions
FunctionExpression is mostly like FunctionDeclaration, except the name
is optional. Share the parsing logic in parse_function_node<NodeType>.

This allows us to do nice things like:

    document.addEventListener("DOMContentLoaded", function() {
        alert("Hello friends!");
    });
2020-03-19 11:54:11 +01:00
Andreas Kling
b1b4c9844e LibJS: Add FunctionExpression AST node
Most of the code is shared with FunctionDeclaration, so the shared bits
are moved up into a common base called FunctionNode.
2020-03-19 11:12:08 +01:00
Andreas Kling
f0b49ae04b LibJS: Fix reference leak in ASTNode::append()
Using make<T> like this would create an unadopted object whose refcount
would never reach zero.
2020-03-19 11:02:20 +01:00
Andreas Kling
ddd69e3660 LibJS: Make the AST reference-counted
This allows function objects to outlive the original parsed program
without their ScopeNode disappearing.
2020-03-18 11:23:53 +01:00
Conrad Pankoff
46a897b59b LibJS: Implement typeof operator 2020-03-17 21:28:02 +01:00
Andreas Kling
19452230cd LibJS: Add "Heap" and "Runtime" subdirectories
Let's try to keep LibJS tidy as it expands. :^)
2020-03-16 14:37:19 +01:00
0xtechnobabble
dfbaa8e543 LibJS: Implement abstract equality and inequality 2020-03-16 13:42:13 +01:00
0xtechnobabble
94088640f1 LibJS: Specify overridden functions with 'override' 2020-03-16 13:42:13 +01:00
0xtechnobabble
cfd710eb31 LibJS: Implement null and undefined literals 2020-03-16 13:42:13 +01:00
Andreas Kling
f7c15d00c9 LibJS: Add basic prototype support
Object will now traverse up the prototype chain when doing a get().
When a function is called on an object, that object will now also be
the "this" value inside the function. This stuff is probably not very
correct, but we will improve things as we go! :^)
2020-03-15 15:01:10 +01:00
0xtechnobabble
db64f364f0 LibJS/AST: Implement prefixed update expressions 2020-03-14 20:02:53 +01:00
0xtechnobabble
20a0fc5576 LibJS: Rename BitNot -> BitwiseNot to match other bitwise operators 2020-03-14 20:02:53 +01:00
0xtechnobabble
644b4f4201 LibJS: Evaluate for statements in their own scope if necessary
We now evaluate for loops in their own scope if their init statement is
a lexical declaration.

Evaluating for loops in their own scope allow us to obtain expected
behaviour, which means for example, that the block-scoped variables
declared in a  for statement will be limited to the scope of the for
loop's body and  statement and not to that of the current scope (i.e the
one where the for statement was made)
2020-03-14 13:58:30 +01:00
Stephan Unverwerth
15d5b2d29e LibJS: Add operator precedence parsing
Obey precedence and associativity rules when parsing expressions
with chained operators.
2020-03-14 00:11:24 +01:00
0xtechnobabble
ee5a49e2fe LibJS: Implement const variable declarations
This also tightens the means of redeclaration of a variable by proxy,
since we now have a way of knowing how a variable was initially
declared, we can check if it was declared using `let` or `const` and
not tolerate redeclaration like we did previously.
2020-03-12 14:58:16 +01:00
0xtechnobabble
8557bc56f7 LibJS: Implement update expressions
Note that currently only the non-prefixed variant is supported (i.e i++
not ++i), this variant returns the value of the argument before the
update.
2020-03-12 14:58:16 +01:00
Andreas Kling
4dc1d6654f LibJS: Tweak AssignmentOp names 2020-03-12 13:54:56 +01:00
Conrad Pankoff
097e1af4e8 LibJS: Implement for statement 2020-03-12 13:42:23 +01:00
Conrad Pankoff
2b36b4f09f LibJS: Implement +=, -=, *=, and /= assignment operators 2020-03-12 13:42:23 +01:00
Conrad Pankoff
0fe87c5fec LibJS: Implement <= and >= binary operators 2020-03-12 13:42:23 +01:00
Conrad Pankoff
fdf7f81ba9 LibJS: Implement multiplication and division operators 2020-03-12 13:42:23 +01:00
howar6hill
01133733dd
LibJS: Allow functions to take arguments (#1405) 2020-03-12 12:22:13 +01:00
Andreas Kling
425fd3ce51 LibJS: Defer Value construction until a Literal is executed
Remove the need to construct a full Value during parsing. This means
we don't have to worry about plumbing the heap into the parser.

The Literal ASTNode now has a bunch of subclasses that synthesize a
Value on demand.
2020-03-12 12:19:11 +01:00
Stephan Unverwerth
f3a9eba987 LibJS: Add Javascript lexer and parser
This adds a basic Javascript lexer and parser. It can parse the
currently existing demo programs. More work needs to be done to
turn it into a complete parser than can parse arbitrary JS Code.

The lexer outputs tokens with preceeding whitespace and comments
in the trivia member. This should allow us to generate the exact
source code by concatenating the generated tokens.

The parser is written in a way that it always returns a complete
syntax tree. Error conditions are represented as nodes in the
tree. This simplifies the code and allows it to be used as an
early stage parser, e.g for parsing JS documents in an IDE while
editing the source code.:
2020-03-12 09:25:49 +01:00
0xtechnobabble
df40c85f80
LibJS: Allow the choice of a scope of declaration for a variable (#1408)
Previously, we were assuming all declared variables were bound to a
block scope, now, with the addition of declaration types, we can bind
a variable to a block scope using `let`, or a function scope (the scope
of the inner-most enclosing function of a `var` declaration) using
`var`.
2020-03-11 20:09:20 +01:00