@@ -12,7 +12,8 @@ const WASM_PAGE_SIZE = 64 * 1024;
1212const DEBUG = process . env . OHM_DEBUG === '1' ;
1313const FAST_SAVE_BINDINGS = true ;
1414const FAST_RESTORE_BINDINGS = true ;
15- const IMPLICIT_SPACE_SKIPPING = false ;
15+
16+ const IMPLICIT_SPACE_SKIPPING = true ;
1617
1718// When specializing rules, should we emit a generalized version that
1819// handles the specific cases? If false, code size will be larger.
@@ -63,7 +64,10 @@ function uniqueName(names, str) {
6364 return name ;
6465}
6566
66- const isSyntactic = ruleName => ruleName [ 0 ] === ruleName [ 0 ] . toUpperCase ( ) ;
67+ function isSyntacticRule ( ruleName ) {
68+ assert ( ruleName [ 0 ] !== '$' , ruleName ) ;
69+ return ruleName [ 0 ] === ruleName [ 0 ] . toUpperCase ( ) ;
70+ }
6771
6872class IndexedSet {
6973 constructor ( ) {
@@ -617,11 +621,11 @@ export class Compiler {
617621 return idx ;
618622 }
619623
620- inLexifiedContext ( ) {
621- return this . _lexContextStack . at ( - 1 ) ;
624+ inLexicalContext ( ) {
625+ return checkNotNull ( this . _lexContextStack . at ( - 1 ) ) ;
622626 }
623627
624- liftPExpr ( exp ) {
628+ liftPExpr ( exp , isSyntactic ) {
625629 assert ( ! ( exp instanceof pexprs . Terminal ) ) ;
626630
627631 // Note: the same expression might appear in more than one place, and
@@ -656,7 +660,7 @@ export class Compiler {
656660 formals = newParams . filter ( isNonNull ) . map ( p => `__${ p . index } ` ) ;
657661 }
658662 const actuals = freeVars . filter ( isNonNull ) ;
659- const ruleInfo = { body, formals, source : exp . source } ;
663+ const ruleInfo = { body, formals, isSyntactic , source : exp . source } ;
660664 return [ name , ruleInfo , actuals ] ;
661665 }
662666
@@ -733,13 +737,26 @@ export class Compiler {
733737 const { grammar} = this ;
734738
735739 const lookUpRule = name => {
736- if ( name in grammar . rules ) return grammar . rules [ name ] ;
737- if ( grammar . superGrammar ) return lookUpRule ( name , grammar . superGrammar ) ;
740+ const isSyntactic = isSyntacticRule ( name ) ;
741+ if ( name in grammar . rules ) {
742+ return { ...grammar . rules [ name ] , isSyntactic} ;
743+ }
744+ if ( grammar . superGrammar ) {
745+ return lookUpRule ( name , grammar . superGrammar ) ;
746+ }
738747 } ;
739748
740749 // Begin with all the rules in the grammar + spaces.
741- const rules = Object . entries ( this . grammar . rules ) ;
742- rules . push ( [ 'spaces' , lookUpRule ( 'spaces' ) ] ) ;
750+ const rules = Object . entries ( this . grammar . rules ) . map ( ( [ name , info ] ) => {
751+ const isSyntactic = isSyntacticRule ( name ) ;
752+ return [ name , { ...info , isSyntactic} ] ;
753+ } ) ;
754+ rules . push ( [
755+ 'spaces' ,
756+ {
757+ ...lookUpRule ( 'spaces' ) ,
758+ } ,
759+ ] ) ;
743760
744761 const liftedTerminals = new IndexedSet ( ) ;
745762
@@ -751,25 +768,25 @@ export class Compiler {
751768
752769 // If `exp` is not an Apply or Param, lift it into its own rule and return
753770 // a new application of that rule.
754- const simplifyArg = exp => {
771+ const simplifyArg = ( exp , isSyntactic ) => {
755772 if ( isApplyLike ( exp ) ) {
756- return simplify ( exp ) ;
773+ return simplify ( exp , isSyntactic ) ;
757774 }
758775 if ( exp instanceof pexprs . Terminal ) {
759776 return liftTerminal ( exp ) ;
760777 }
761778
762- const [ name , info , env ] = this . liftPExpr ( exp ) ;
779+ const [ name , info , env ] = this . liftPExpr ( exp , isSyntactic ) ;
763780 const args = env . map ( p => {
764781 assert ( p instanceof pexprs . Param , 'Expected Param' ) ;
765782 return ir . param ( p . index ) ;
766783 } ) ;
767784 rules . push ( [ name , info ] ) ;
768785 return ir . apply ( name , args ) ;
769786 } ;
770- const simplify = exp => {
787+ const simplify = ( exp , isSyntactic ) => {
771788 if ( exp instanceof pexprs . Alt ) {
772- return ir . alt ( exp . terms . map ( e => simplify ( e ) ) ) ;
789+ return ir . alt ( exp . terms . map ( e => simplify ( e , isSyntactic ) ) ) ;
773790 }
774791 if ( exp === pexprs . any ) return ir . any ( ) ;
775792 if ( exp === pexprs . end ) return ir . end ( ) ;
@@ -778,24 +795,24 @@ export class Compiler {
778795 rules . push ( [ exp . ruleName , checkNotNull ( lookUpRule ( exp . ruleName ) ) ] ) ;
779796 return ir . apply (
780797 exp . ruleName ,
781- exp . args . map ( arg => simplifyArg ( arg ) ) ,
798+ exp . args . map ( arg => simplifyArg ( arg , isSyntactic ) ) ,
782799 ) ;
783800 case pexprs . CaseInsensitive :
784801 return ir . caseInsensitive ( exp . obj ) ;
785802 case pexprs . Lex :
786- return ir . lex ( simplify ( exp . expr ) ) ;
803+ return ir . lex ( simplify ( exp . expr , true ) ) ;
787804 case pexprs . Lookahead :
788- return ir . lookahead ( simplify ( exp . expr ) ) ;
805+ return ir . lookahead ( simplify ( exp . expr , isSyntactic ) ) ;
789806 case pexprs . Not :
790- return ir . not ( simplify ( exp . expr ) ) ;
807+ return ir . not ( simplify ( exp . expr , isSyntactic ) ) ;
791808 case pexprs . Opt :
792- return ir . opt ( simplify ( exp . expr ) ) ;
809+ return ir . opt ( simplify ( exp . expr , isSyntactic ) ) ;
793810 case pexprs . Plus :
794- return ir . plus ( simplify ( exp . expr ) ) ;
811+ return ir . plus ( simplify ( exp . expr , isSyntactic ) ) ;
795812 case pexprs . Seq :
796- return ir . seq ( exp . factors . map ( e => simplify ( e ) ) ) ;
813+ return ir . seq ( exp . factors . map ( e => simplify ( e , isSyntactic ) ) ) ;
797814 case pexprs . Star :
798- return ir . star ( simplify ( exp . expr ) ) ;
815+ return ir . star ( simplify ( exp . expr , isSyntactic ) ) ;
799816 case pexprs . Param :
800817 return ir . param ( exp . index ) ;
801818 case pexprs . Range :
@@ -818,7 +835,7 @@ export class Compiler {
818835 if ( ! newRules . has ( name ) ) {
819836 newRules . set ( name , {
820837 ...info ,
821- body : simplify ( info . body ) ,
838+ body : simplify ( info . body , info . isSyntactic ) ,
822839 } ) ;
823840 }
824841 }
@@ -828,10 +845,10 @@ export class Compiler {
828845
829846 compileTerminalRule ( name ) {
830847 const { asm} = this ;
848+ this . beginLexContext ( true ) ;
831849 asm . addFunction ( `$${ name } ` , [ w . valtype . i32 ] , [ w . valtype . i32 ] , ( ) => {
832850 asm . addLocal ( 'ret' , w . valtype . i32 ) ;
833851 asm . addLocal ( 'tmp' , w . valtype . i32 ) ;
834-
835852 asm . switch (
836853 w . blocktype . empty ,
837854 ( ) => asm . localGet ( '__arg0' ) ,
@@ -842,18 +859,28 @@ export class Compiler {
842859 ) ;
843860 asm . localGet ( 'ret' ) ;
844861 } ) ;
862+ this . endLexContext ( ) ;
845863 return this . asm . _functionDecls . at ( - 1 ) ;
846864 }
847865
866+ beginLexContext ( initialVal ) {
867+ assert ( this . _lexContextStack . length === 0 ) ;
868+ this . _lexContextStack . push ( initialVal ) ;
869+ }
870+
871+ endLexContext ( ) {
872+ this . _lexContextStack . pop ( ) ;
873+ assert ( this . _lexContextStack . length === 0 ) ;
874+ }
875+
848876 compileRule ( name ) {
849877 const { asm} = this ;
850878 const ruleInfo = getNotNull ( this . rules , name ) ;
851879 let paramTypes = [ ] ;
852880 if ( ruleInfo . patterns ) {
853881 paramTypes = [ w . valtype . i32 ] ;
854882 }
855- assert ( this . _lexContextStack . length === 0 ) ;
856- this . _lexContextStack . push ( ! isSyntactic ( name ) ) ;
883+ this . beginLexContext ( ! ruleInfo . isSyntactic ) ;
857884 asm . addFunction ( `$${ name } ` , paramTypes , [ w . valtype . i32 ] , ( ) => {
858885 asm . addLocal ( 'ret' , w . valtype . i32 ) ;
859886 asm . addLocal ( 'tmp' , w . valtype . i32 ) ;
@@ -862,8 +889,7 @@ export class Compiler {
862889 asm . emit ( `END eval:${ name } ` ) ;
863890 asm . localGet ( 'ret' ) ;
864891 } ) ;
865- this . _lexContextStack . pop ( ) ;
866- assert ( this . _lexContextStack . length === 0 ) ;
892+ this . endLexContext ( ) ;
867893 return this . asm . _functionDecls . at ( - 1 ) ;
868894 }
869895
@@ -1204,6 +1230,7 @@ export class Compiler {
12041230
12051231 emitApplyTerm ( { terminalId} ) {
12061232 const { asm} = this ;
1233+ this . maybeEmitSpaceSkipping ( ) ;
12071234 asm . i32Const ( terminalId ) ;
12081235 asm . emit ( w . instr . call , this . ruleEvalFuncIdx ( '$term' ) ) ;
12091236 asm . localSet ( 'ret' ) ;
@@ -1223,7 +1250,7 @@ export class Compiler {
12231250 assert ( exp . children . length === 0 ) ;
12241251
12251252 if ( exp !== this . _applySpaces ) {
1226- this . maybeEmitSpaceSkipping ( ) ;
1253+ this . maybeEmitSpaceSkipping ( ) ; // Avoid infinite recursion.
12271254 }
12281255
12291256 const { asm} = this ;
@@ -1340,7 +1367,7 @@ export class Compiler {
13401367 }
13411368
13421369 maybeEmitSpaceSkipping ( ) {
1343- if ( IMPLICIT_SPACE_SKIPPING && ! this . inLexifiedContext ( ) ) {
1370+ if ( IMPLICIT_SPACE_SKIPPING && ! this . inLexicalContext ( ) ) {
13441371 this . asm . emit ( 'BEGIN space skipping' ) ;
13451372 this . emitApply ( this . _applySpaces ) ;
13461373 this . asm . emit ( 'END space skipping' ) ;
0 commit comments