Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modularized parser #304

Merged
merged 2 commits into from
Apr 28, 2020
Merged

Modularized parser #304

merged 2 commits into from
Apr 28, 2020

Conversation

Razican
Copy link
Member

@Razican Razican commented Apr 10, 2020

This is still work in progress, but tests pass, and even though I need to divide the code further, we now have multiple different structures. I also need to document a bunch of stuff.

I also modified the parser so that it would better respect the specification. So for example, an initializer expects to first read a = symbol, as in the spec.

I added more tests for break throw and continue parsing, that I think they were failing with automatic semicolon insertion.

About this last part, it gets done at the Cursor level. I think I changed all semicolon expects for the new expect_semicolon() function. This will automatically insert semicolons in all the situations where the spec says so. The only exception is the semicolon after the do while statement, so this should fail:

var i = 0;
do {console.log("hello");} while(i++ < 10) console.log("end");

In any case, do-while parsing is not done, so this doesn't affect us. It's now detected with a panic, though.

In any case, this is advanced enough so that you can give it a look and let me know what you think.

@github-actions
Copy link

Benchmark for 40ed44e

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 407.1±13.55µs 382.5±26.29µs 106%
Expression (Parser) 2.8±0.21µs 2.8±0.15µs 99%
Hello World (Execution) 406.9±19.36µs 379.6±22.13µs 107%
Hello World (Lexer) 1069.9±81.25ns 1075.2±63.69ns 100%
Hello World (Parser) 1297.9±95.10ns 1173.4±70.72ns 111.00000000000001%
Symbol Creation 411.7±24.10µs 432.4±24.55µs 95%
fibonacci (Execution) 4.4±0.16ms 4.3±0.18ms 101%
undefined undefined 100%

Copy link
Member

@HalidOdat HalidOdat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! The parser code is much easier to reason with!

boa/src/syntax/parser/expression/mod.rs Outdated Show resolved Hide resolved
}

let mut lhs = ConditionalExpression::parse(cursor)?;
// let mut lhs = self.read_block()?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// let mut lhs = self.read_block()?;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check what's happening here :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this is that I'm not 100% sure on how is this done. An AssignmentExpression can be one of these:

  • ConditionalExpression
  • YieldExpression
  • ArrowFunction
  • AsyncArrowFunction
  • LeftHandSideExpression = AssignmentExpression
  • LeftHandSideExpression AssignmentOperator AssignmentExpression

The thing is that we do test for ArrowFunction at the beginning, and then, we directly parse a ConditionalExpression, but I don't understand why. Can this be explained a bit more, @jasonwilliams? maybe I can add some comments once I understand it properly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not sure i understand what the question is here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just that the read_block() call is commented out, not sure why, and more generally, how does this parsing work? It seems to only check the conditional expression, but it should check more things, right?

/// - The `$lower` identifier will contain the parser for lower level expressions.
///
/// Those exressions are divided by the punctuators passed as the third (and following) parameters.
macro_rules! expression { ( $name:ident, $lower:ident, $( $op:path ),* ) => {
Copy link
Member

@HalidOdat HalidOdat Apr 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you remove [...] form expression macro?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this made it easier to understand. What do you think? It's pretty easy to put it back, but I wanted to try how it looked like this.

Copy link
Member

@HalidOdat HalidOdat Apr 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I think separating the parameters of the expression macro is better. So its not a continuous line of parameters.
I would changed even more to be:

macro_rules! expression {
	(
	  name: $name:ident,
	  call: $lower:ident,
	  [$( $op:path ),*]
	)
	...
}

expression!(
	name: update_expression,
	call: some_other_expression,
	[...]
);

This way it is clear to see that the name of the expression, what it will call and what it matches against.
What do you think? @Razican
Am I overdoing it a bit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm the thing is that the name would be a struct or an enum to implement TokenParser in, so maybe a better name would suit. I will implement it this way for now, though, to see how it goes.

@HalidOdat
Copy link
Member

The tests are failing because you need to import MethodDefinitionKind, PropertyDefinition, AssignOp, BinOp, NumOp and UnaryOp in test.rs

@HalidOdat
Copy link
Member

It might be a good idea to refactor the AST too, to reflect the changes.
So we don't have one node type Node, but a Statement, Declaration and Expression node type. Just like V8 AST.

Any thoughts @Razican and @jasonwilliams? 🤔

@Razican
Copy link
Member Author

Razican commented Apr 11, 2020

It might be a good idea to refactor the AST too, to reflect the changes.
So we don't have one node type Node, but a Statement, Declaration and Expression node type. Just like V8 AST.

Any thoughts @Razican and @jasonwilliams? 🤔

When working on iterative statements, I did notice that we were not following the spec 100%, as we directly parse them instead of using an intermediate parser for iterative statements.

It can be a good idea to match the V8 engine in AST node types.

@jasonwilliams
Copy link
Member

It might be a good idea to refactor the AST too, to reflect the changes.
So we don't have one node type Node, but a Statement, Declaration and Expression node type. Just like V8 AST.
Any thoughts @Razican and @jasonwilliams? 🤔

When working on iterative statements, I did notice that we were not following the spec 100%, as we directly parse them instead of using an intermediate parser for iterative statements.

It can be a good idea to match the V8 engine in AST node types.

Yeah i agree with this.
I think what we had was good for getting us to this point, we didn't have any sort of pre-parser or intermediate parser so i think it was just easier to parse as we saw it. Obviously the end game would to be more closer to how V8 deals with it.

@Razican
Copy link
Member Author

Razican commented Apr 11, 2020

I will review that. I'm not sure if it would make sense for the TokenParser trait to be a method instead of a member function (and therefore accept &self.

This would allow not having dangling functions and all parsers would implement TokenParser. Then an extra thing that we could add here would be to be able to return a Result<dyn Executable, ParseError>, where Executable would be a trait that gets passed an executor and executes the node. So we can implement it for AST nodes and also for things like Vec<Node> or so.

BTW, I added a try_parse() method for TokenParser that just tries to parse something, and then goes back to where it was if there was an error parsing it. Currently done by arrow function parsing in expressions, if I'm not mistaken.

Then, there is another thing to be considered: The fact that the lexer doesn't take into account goal symbols (#294). This could be solved by passing the Lexer as a parameter to the Cursor constructor, and adding a method in the Cursor to set the current goal.

This would mean that we no longer can benchmark lexing and parsing separately, as they would happen at the same time, but I think it makes sense.

What do you think?

@github-actions
Copy link

Benchmark for 661469a

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 355.1±19.35µs 350.6±18.24µs 101%
Expression (Parser) 2.6±0.14µs 2.7±0.24µs 95%
Hello World (Execution) 377.4±22.69µs 387.4±23.82µs 97%
Hello World (Lexer) 972.2±57.95ns 1017.7±82.53ns 95%
Hello World (Parser) 1200.6±79.85ns 1151.9±82.38ns 104%
Symbol Creation 395.0±30.93µs 397.0±27.02µs 100%
fibonacci (Execution) 4.1±0.17ms 4.1±0.17ms 100%
undefined undefined 100%

@jasonwilliams jasonwilliams added this to the v0.8.0 milestone Apr 12, 2020
@jasonwilliams
Copy link
Member

jasonwilliams commented Apr 13, 2020

I will review that. I'm not sure if it would make sense for the TokenParser trait to be a method instead of a member function (and therefore accept &self.

I don't mind too much what you have now, but i'd like to see this alternative you mention (even if its just for 1 function) to get an idea of what you mean.

This would allow not having dangling functions and all parsers would implement TokenParser. Then an extra thing that we could add here would be to be able to return a Result<dyn Executable, ParseError>, where Executable would be a trait that gets passed an executor and executes the node. So we can implement it for AST nodes and also for things like Vec<Node> or so.

BTW, I added a try_parse() method for TokenParser that just tries to parse something, and then goes back to where it was if there was an error parsing it. Currently done by arrow function parsing in expressions, if I'm not mistaken.

Looks good!

Then, there is another thing to be considered: The fact that the lexer doesn't take into account goal symbols (#294). This could be solved by passing the Lexer as a parameter to the Cursor constructor, and adding a method in the Cursor to set the current goal.

Does the specification discus much about goal symbols?
Edit: just seen https://tc39.es/ecma262/#sec-ecmascript-language-lexical-grammar

Would we send the lexer the current state we're in? Then the lexer has context of what we're looking for.

This would mean that we no longer can benchmark lexing and parsing separately, as they would happen at the same time, but I think it makes sense.

What do you think?

Yeah if there's no solution i'm fine with changing the benchmarks

@Razican
Copy link
Member Author

Razican commented Apr 13, 2020

I will review that. I'm not sure if it would make sense for the TokenParser trait to be a method instead of a member function (and therefore accept &self.

I don't mind too much what you have now, but i'd like to see this alternative you mention (even if its just for 1 function) to get an idea of what you mean.

The idea is that we would change how the parsers are called now:

let expr = ExpressionParser::parse(cursor)?;

To something like this:

let expr = ExpressionParser(cursor).parse()?;

But this would allow having functions that require some extra information, such as read_binding_list() to actually be a TokenParser:

let binding_list = BindingList(cursor, is_const).parse()?;

where BindingList would be defined like this:

struct BindingList<'b>(&'b Cursor<'_>, bool);

Would we send the lexer the current state we're in? Then the lexer has context of what we're looking for.

Yes, I think that the lexer's next() function should be a function that receives the goal_symbol as a parameter, and it should be one of the symbols declared in the spec. I'm not so sure yet how to find out the current symbol in the parser.

Also, I think the cursor should always skip line terminators, and have the expect_semicolon() function insert the actual semicolon if we are in a case of automatic semicolon insertion. This is mostly done, except for the line terminator skipping part. I think it would make the parser easier to understand without sacrificing the lexer.

The only special case where this might be a bit difficult would be the ) token after the while condition in a do-while statement. This is pretty difficult to know from the lexer/cursor directly, so I would suggest adding a bool as a parameter to that function, to make sure it checks if the previous token is a ) in the case of a do-while.

@Razican
Copy link
Member Author

Razican commented Apr 14, 2020

The idea is that we would change how the parsers are called now:

The only thing I'm worried about is if this will make the code less performant, having to create an object first and calling its methods, instead of calling a static function with some arguments. I can try it as soon as I finish documenting this first iteration.

@HalidOdat HalidOdat added enhancement New feature or request parser Issues surrounding the parser labels Apr 14, 2020
@github-actions
Copy link

Benchmark for abbca39

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 400.1±17.08µs 399.5±17.99µs 100%
Expression (Parser) 3.0±0.08µs 3.1±0.34µs 97%
Hello World (Execution) 411.7±11.95µs 418.4±19.23µs 98%
Hello World (Lexer) 940.5±35.23ns 958.5±29.09ns 98%
Hello World (Parser) 1211.8±52.30ns 1119.8±35.58ns 108%
Symbol Creation 498.5±22.07µs 498.4±20.67µs 100%
fibonacci (Execution) 4.7±0.06ms 4.8±0.10ms 99%
undefined undefined 100%

@github-actions
Copy link

Benchmark for 0d40842

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 406.2±25.97µs 408.5±20.08µs 99%
Expression (Parser) 3.0±0.09µs 3.3±0.23µs 89.99999999999999%
Hello World (Execution) 413.1±13.57µs 418.8±18.68µs 99%
Hello World (Lexer) 963.6±23.64ns 899.4±57.08ns 107%
Hello World (Parser) 1183.2±26.51ns 1234.6±65.99ns 96%
Symbol Creation 496.9±11.44µs 500.3±18.87µs 99%
fibonacci (Execution) 4.7±0.10ms 4.9±0.24ms 96%
undefined undefined 100%

@Razican
Copy link
Member Author

Razican commented Apr 14, 2020

I added some nice methods (WIP) to easily create AST nodes. This will help make tests more clear, and should also help with the parser implementation. So you can now create a local node like this:

Node::local("a")

instead of:

Node::Local(String::from("a"));

and you can create a Break node like this:

Node::break_node("label");

instead of:

Node::Break(Some(String::from("label")));

Also no more need to add Box::new() everywhere, so it should make things cleaner.

@github-actions
Copy link

Benchmark for 0862dd4

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 454.0±49.20µs 446.2±28.42µs 102%
Expression (Parser) 3.3±0.37µs 3.6±0.24µs 90.99999999999999%
Hello World (Execution) 437.1±30.50µs 456.8±39.20µs 95%
Hello World (Lexer) 1010.6±62.83ns 1082.0±81.14ns 93%
Hello World (Parser) 1350.4±68.83ns 1280.4±70.12ns 105%
Symbol Creation 553.5±52.24µs 517.4±39.38µs 107%
fibonacci (Execution) 5.3±0.22ms 5.1±0.28ms 104%
undefined undefined 100%

@Razican Razican mentioned this pull request Apr 16, 2020
10 tasks
@github-actions
Copy link

Benchmark for d98538e

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 459.0±66.13µs 448.0±16.43µs 102%
Expression (Parser) 3.4±0.06µs 3.5±0.13µs 98%
Hello World (Execution) 461.8±9.85µs 462.0±14.89µs 100%
Hello World (Lexer) 1010.1±38.30ns 1099.7±37.48ns 90.99999999999999%
Hello World (Parser) 1311.1±22.16ns 1297.6±24.96ns 101%
Symbol Creation 565.1±20.72µs 556.9±20.76µs 101%
fibonacci (Execution) 5.3±0.10ms 5.4±0.07ms 99%
undefined undefined 100%

@Razican
Copy link
Member Author

Razican commented Apr 16, 2020

I implemented automatic semicolon insertion after do-while statements. This means we have less things left for this to be mergeable:

  • Add proper documentation to all parsers.
  • Make parsers return something Executable.
  • Make the executor be able to execute anything Executable.
  • Divide parser in smaller submodules.

@github-actions
Copy link

Benchmark for f3bf8b0

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 391.4±19.95µs 366.9±38.70µs 107%
Expression (Lexer) 1878.0±135.28ns 1753.5±139.52ns 107%
Expression (Parser) 3.8±0.28µs 4.0±0.40µs 93%
Fibonacci (Execution) 4.3±0.21ms 4.1±0.21ms 105%
For loop (Execution) 464.1±29.82µs 453.9±42.74µs 102%
For loop (Lexer) 4.4±0.34µs 4.3±0.34µs 102%
For loop (Parser) 13.2±1.39µs 12.1±1.08µs 109.00000000000001%
Hello World (Lexer) 820.2±72.03ns 770.6±61.35ns 106%
Hello World (Parser) 1758.6±139.26ns 1726.7±117.69ns 102%
Symbols (Execution) 477.7±44.57µs 457.0±43.63µs 105%
undefined undefined 100%

@github-actions
Copy link

Benchmark for c212135

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 398.1±18.87µs 389.5±8.65µs 102%
Expression (Lexer) 1891.0±30.39ns 1936.1±28.86ns 98%
Expression (Parser) 4.4±0.10µs 4.5±0.54µs 97%
Fibonacci (Execution) 4.3±0.06ms 4.3±0.05ms 100%
For loop (Execution) 478.8±6.99µs 481.2±12.43µs 100%
For loop (Lexer) 5.2±0.15µs 5.4±0.12µs 95%
For loop (Parser) 13.8±0.26µs 13.4±0.28µs 103%
Hello World (Lexer) 948.8±12.94ns 944.3±38.96ns 100%
Hello World (Parser) 2.0±0.03µs 1972.6±58.62ns 102%
Symbols (Execution) 492.2±7.97µs 491.5±6.22µs 100%
undefined undefined 100%

@github-actions
Copy link

Benchmark for 2d8eb20

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 365.5±24.20µs 365.2±18.40µs 100%
Expression (Lexer) 1688.3±78.57ns 1731.2±92.08ns 97%
Expression (Parser) 4.1±0.33µs 3.9±0.27µs 103%
Fibonacci (Execution) 4.1±0.19ms 4.4±0.20ms 94%
For loop (Execution) 462.2±26.56µs 450.6±26.71µs 103%
For loop (Lexer) 4.7±0.29µs 4.6±0.27µs 102%
For loop (Parser) 13.9±0.62µs 12.7±1.12µs 110.00000000000001%
Hello World (Lexer) 902.5±41.07ns 810.2±52.67ns 111.00000000000001%
Hello World (Parser) 1819.6±92.58ns 1733.3±75.75ns 105%
Symbols (Execution) 476.9±25.86µs 464.2±31.30µs 103%
undefined undefined 100%

@github-actions
Copy link

Benchmark for 6eb0431

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 425.2±13.70µs 424.9±16.51µs 100%
Expression (Lexer) 2.0±0.07µs 2.0±0.07µs 99%
Expression (Parser) 4.5±0.22µs 4.6±0.20µs 98%
Fibonacci (Execution) 4.8±0.13ms 4.9±0.10ms 97%
For loop (Execution) 516.8±22.54µs 521.1±20.41µs 99%
For loop (Lexer) 5.2±0.20µs 5.3±0.30µs 97%
For loop (Parser) 14.9±0.72µs 15.0±0.49µs 99%
Hello World (Lexer) 921.8±35.15ns 955.1±38.42ns 96%
Hello World (Parser) 2.2±0.08µs 2.1±0.10µs 101%
Symbols (Execution) 530.8±25.24µs 528.7±26.28µs 100%
undefined undefined 100%

@Razican
Copy link
Member Author

Razican commented Apr 18, 2020

Something I see from the benchmarks is that more than 99% of the time is spent on execution. I think we should improve our interpreter :)

@github-actions
Copy link

Benchmark for 06c0c6b

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 292.6±19.90µs 289.3±20.46µs 101%
Expression (Lexer) 1799.4±105.00ns 1734.8±133.73ns 104%
Expression (Parser) 3.7±0.19µs 3.9±0.31µs 95%
Fibonacci (Execution) 3.2±0.14ms 3.3±0.16ms 98%
For loop (Execution) 300.4±18.35µs 332.3±22.57µs 88.99999999999999%
For loop (Lexer) 4.4±0.29µs 4.3±0.32µs 103%
For loop (Parser) 10.6±0.88µs 10.3±0.66µs 103%
Hello World (Lexer) 730.0±32.59ns 789.3±58.65ns 92%
Hello World (Parser) 1670.4±127.38ns 1663.0±94.58ns 100%
Symbols (Execution) 300.9±18.26µs 300.1±17.04µs 100%
undefined undefined 100%

@Razican
Copy link
Member Author

Razican commented Apr 25, 2020

I did al the requested changes, @HalidOdat, I will rebase today. Still, the expression module is a bit strange, since it has a tree of expressions.

@HalidOdat
Copy link
Member

HalidOdat commented Apr 25, 2020

Still, the expression module is a bit strange, since it has a tree of expressions.

Well I think that's good, the parser in a way should reflect what it generates. (not exactly).
For example with lexer the functions that lex the source code should be like tokens, small and only deal with that type of token.
And it's easier now to look at the spec productions and reason were something is supposed to go or be.

In the future we should refactor the AST too.
Edit: The lexer probably needs a refactor too.

Copy link
Member

@HalidOdat HalidOdat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks perfect to me!

@Razican
Copy link
Member Author

Razican commented Apr 25, 2020

Edit: The lexer probably needs a refactor too.

Yes, I'm working a bit on that in a couple of places, with string interning and trying to parse source code byte by byte.

@Razican
Copy link
Member Author

Razican commented Apr 25, 2020

Rebased and ready for a merge, @HalidOdat, @jasonwilliams :D

@github-actions
Copy link

Benchmark for bca05a0

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 404.5±26.07µs 422.8±35.78µs 95%
Expression (Lexer) 2.3±0.19µs 2.2±0.13µs 104%
Expression (Parser) 5.3±0.44µs 5.1±0.36µs 103%
Fibonacci (Execution) 4.2±0.22ms 3.9±0.25ms 110.00000000000001%
For loop (Execution) 432.1±37.53µs 402.6±30.43µs 107%
For loop (Lexer) 5.6±0.49µs 6.0±0.44µs 93%
For loop (Parser) 15.3±0.86µs 14.0±0.78µs 110.00000000000001%
Hello World (Lexer) 997.8±62.58ns 1064.7±103.53ns 93%
Hello World (Parser) 2.5±0.21µs 2.3±0.21µs 108%
Symbols (Execution) 415.4±22.98µs 441.4±37.90µs 94%
undefined undefined 100%

@github-actions
Copy link

Benchmark for 8781a01

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 398.2±34.01µs 415.4±30.02µs 96%
Expression (Lexer) 2.1±0.17µs 2.1±0.19µs 96%
Expression (Parser) 4.8±0.37µs 5.1±0.47µs 94%
Fibonacci (Execution) 4.0±0.27ms 3.9±0.31ms 100%
For loop (Execution) 425.2±33.83µs 380.2±34.01µs 112.00000000000001%
For loop (Lexer) 5.7±0.54µs 5.6±0.39µs 102%
For loop (Parser) 14.4±1.57µs 15.3±0.76µs 94%
Hello World (Lexer) 987.5±95.76ns 1030.0±125.89ns 96%
Hello World (Parser) 2.5±0.10µs 2.2±0.23µs 112.99999999999999%
Symbols (Execution) 413.9±41.17µs 444.0±26.82µs 93%
undefined undefined 100%

@github-actions
Copy link

Benchmark for 4f14555

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 368.7±5.14µs 370.1±9.37µs 100%
Expression (Lexer) 2.1±0.10µs 2.1±0.11µs 99%
Expression (Parser) 5.1±0.08µs 4.9±0.06µs 104%
Fibonacci (Execution) 3.6±0.04ms 3.6±0.07ms 100%
For loop (Execution) 382.6±5.98µs 378.7±7.25µs 101%
For loop (Lexer) 5.2±0.16µs 5.3±0.28µs 98%
For loop (Parser) 13.9±0.23µs 12.8±0.54µs 109.00000000000001%
Hello World (Lexer) 895.5±17.61ns 941.7±65.16ns 95%
Hello World (Parser) 2.2±0.07µs 2.1±0.02µs 103%
Symbols (Execution) 390.7±6.13µs 381.1±9.36µs 103%
undefined undefined 100%

@Razican Razican force-pushed the parser_modularization branch 2 times, most recently from cc43f06 to bc2e924 Compare April 27, 2020 10:28
@github-actions
Copy link

Benchmark for 959685e

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 513.7±95.03µs 512.2±95.83µs 100%
Expression (Lexer) 3.0±0.44µs 2.6±0.36µs 114.99999999999999%
Expression (Parser) 6.6±0.80µs 6.2±0.95µs 106%
Fibonacci (Execution) 5.4±0.63ms 5.2±0.64ms 104%
For loop (Execution) 537.8±117.75µs 514.7±85.00µs 104%
For loop (Lexer) 6.7±0.97µs 7.1±1.04µs 94%
For loop (Parser) 19.7±3.48µs 17.6±3.39µs 112.00000000000001%
Hello World (Lexer) 1159.8±167.29ns 1165.8±168.78ns 99%
Hello World (Parser) 3.1±0.54µs 2.9±0.39µs 106%
Symbols (Execution) 543.7±91.01µs 546.7±96.95µs 99%
undefined undefined 100%

@Razican
Copy link
Member Author

Razican commented Apr 27, 2020

Rebased and ready :)

@github-actions
Copy link

Benchmark for 6305aa0

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 342.4±15.01µs 341.3±12.95µs 100%
Expression (Lexer) 1932.5±68.66ns 1945.0±52.07ns 99%
Expression (Parser) 4.5±0.15µs 4.4±0.25µs 103%
Fibonacci (Execution) 3.5±0.23ms 3.4±0.08ms 102%
For loop (Execution) 352.3±15.49µs 352.8±8.98µs 100%
For loop (Lexer) 4.7±0.13µs 4.9±0.19µs 98%
For loop (Parser) 13.1±0.63µs 12.7±0.90µs 104%
Hello World (Lexer) 849.7±35.06ns 861.0±18.37ns 99%
Hello World (Parser) 2.1±0.07µs 1993.7±61.78ns 105%
Symbols (Execution) 364.0±14.74µs 364.7±15.92µs 100%
undefined undefined 100%

Copy link
Member

@jasonwilliams jasonwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks awesome, very clean too!

Comment on lines +52 to +53
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come into() is needed here? (just for me to understand)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not realy needed, but I used generics in the function signature: I: Into<AllowIn> and so on. This allows us to create a parser with booleans too: ArrowFunction(true, false, true).

We could just remove the generics from the new() functions and pass the wrapping structures, which would improve compile times, and is probably just as clear / developer friendly.

@github-actions
Copy link

Benchmark for 893a647

Click to view benchmark
Test PR Benchmark Master Benchmark %
Create Realm 388.6±7.90µs 385.8±5.51µs 101%
Expression (Lexer) 2.2±0.06µs 2.2±0.05µs 102%
Expression (Parser) 5.3±0.13µs 5.1±0.15µs 104%
Fibonacci (Execution) 3.8±0.03ms 3.7±0.05ms 101%
For loop (Execution) 394.9±5.30µs 399.5±9.07µs 99%
For loop (Lexer) 5.4±0.11µs 5.4±0.10µs 99%
For loop (Parser) 14.7±0.44µs 13.5±0.25µs 109.00000000000001%
Hello World (Lexer) 940.6±37.47ns 966.4±12.46ns 97%
Hello World (Parser) 2.3±0.04µs 2.2±0.04µs 105%
Symbols (Execution) 416.6±11.91µs 409.6±6.15µs 102%
undefined undefined 100%

@Razican Razican merged commit bc63b28 into master Apr 28, 2020
@Razican Razican deleted the parser_modularization branch April 28, 2020 18:17
@HalidOdat HalidOdat mentioned this pull request May 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request parser Issues surrounding the parser
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants