To evaluate how hard it is to extend the current parser, I did the following experiment. I extended the JavaScript grammar to support 2 new forms of statements with the following syntax:
atomic { ... }
future <Expr> ;
These could be used for example for the atomic execution of a block, and for the parallel evaluation of an expression in a newly created thread.
A "git diff" is attached below. It took me about 30 minutes to implement the parser extensions.
To implement these extensions we need 2 new tokens "atomic" and "future". Which require adding a %token line in Grammar.y , and two lines in the file "keywords.scm" (which is used to create a perfect hash table of the keywords). Two lines are added to Grammar.y to specify the new productions rules. The file parser.js has to be modified to add the function Statement_18 and Statement_19 which implement the actions of the new production rules, which create AST nodes specific to those cases (18 and 19 because these production rules are the 18th and 19th in the category "Statement"). Finally, for smooth integration with the AST passes of the compiler, the AST walker for statements has to be extended for these new AST node types (file ast-passes.js). A few more lines would be required in the pretty printer (pp.js).
That makes about 30 to 40 lines of simple code to implement each extension. This is very little when compared to the hundreds of lines of complex code to implement the analysis, optimization, code generation and runtime support for these forms.
It would be really nice if we could simplify the implementation of the complex stuff!
Marc
diff --git a/source/parser/Grammar.y b/source/parser/Grammar.y index f7c3c10..7718157 100644 --- a/source/parser/Grammar.y +++ b/source/parser/Grammar.y @@ -243,6 +243,7 @@ static inline void setExceptionLocation(ThrowableExpressionData* node, unsigned %token SWITCH WITH RESERVED %token THROW TRY CATCH FINALLY %token DEBUGGER +%token ATOMIC FUTURE /********* extensions *********/
/* give an if without an else higher precedence than an else to resolve the ambiguity */ %nonassoc IF_WITHOUT_ELSE @@ -859,6 +860,8 @@ Statement: | ThrowStatement | TryStatement | DebuggerStatement + | ATOMIC Block /********* extensions *********/ + | FUTURE Expr ';' /********* extensions *********/ ;
Block: diff --git a/source/parser/ast-passes.js b/source/parser/ast-passes.js index bd92a39..0dfb36e 100644 --- a/source/parser/ast-passes.js +++ b/source/parser/ast-passes.js @@ -213,7 +213,17 @@ function ast_walk_statement(ast, ctx) { return ast; } - else + else if (ast instanceof AtomicStatement) /********* extensions *********/ + { + ast.statement = ctx.walk_statement(ast.statement); + return ast; + } + else if (ast instanceof FutureStatement) /********* extensions *********/ + { + ast.expr = ctx.walk_expr(ast.expr); + return ast; + } + else { //pp(ast); error("unknown ast in walk_statement"); diff --git a/source/parser/keywords.scm b/source/parser/keywords.scm index 8721b2e..5fba892 100644 --- a/source/parser/keywords.scm +++ b/source/parser/keywords.scm @@ -80,6 +80,8 @@ "void" "while" "with" +"atomic" ;; ********* extensions ********* +"future" ;; ********* extensions *********
;; FutureReservedWord "class" diff --git a/source/parser/parser.js b/source/parser/parser.js index 193223d..c5fc0e0 100644 --- a/source/parser/parser.js +++ b/source/parser/parser.js @@ -1984,6 +1984,30 @@ function Statement_17(p, DebuggerStatement) return DebuggerStatement; }
+function AtomicStatement(loc, statement) +{ + this.loc = loc; + this.statement = statement; +} + +function Statement_18(p, ATOMIC, Block) /********* extensions *********/ +{ + return new AtomicStatement(ATOMIC.loc.join(Block.loc), + Block); +} + +function FutureStatement(loc, expr) +{ + this.loc = loc; + this.expr = expr; +} + +function Statement_19(p, FUTURE, Expr, SEMICOLON) /********* extensions *********/ +{ + return new FutureStatement(FUTURE.loc.join(SEMICOLON.loc), + Expr); +} + function Block_1(p, LBRACE, RBRACE) { return new BlockStatement(LBRACE.loc.join(RBRACE.loc),