@@ -14,6 +14,11 @@ const FAST_SAVE_BINDINGS = true;
1414const FAST_RESTORE_BINDINGS = true ;
1515const IMPLICIT_SPACE_SKIPPING = false ;
1616
17+ // When specializing rules, should we emit a generalized version that
18+ // handles the specific cases? If false, code size will be larger.
19+ // This doesn't seem to make a big performance difference either way.
20+ const EMIT_GENERALIZED_RULES = true ;
21+
1722const { instr} = w ;
1823
1924const isNonNull = x => x != null ;
@@ -99,11 +104,6 @@ class IndexedSet {
99104 }
100105}
101106
102- function getDebugLabel ( exp ) {
103- const loc = exp . source ? exp . source . startIdx : - 1 ;
104- return `${ JSON . stringify ( exp ) } @${ loc } ` ;
105- }
106-
107107function collectParams ( exp , seen = new Set ( ) ) {
108108 switch ( exp . constructor ) {
109109 case pexprs . Param :
@@ -406,8 +406,16 @@ class Assembler {
406406 this . emit ( w . instr . br_table , w . vec ( labels . map ( i => w . labelidx ( i ) ) ) , w . labelidx ( defaultIdx ) ) ;
407407 }
408408
409+ return ( ) {
410+ const what = this . _blockStack [ 0 ] ;
411+ assert ( what === 'block' , 'Invalid return' ) ;
412+ this . emit ( w . instr . return ) ;
413+ }
414+
409415 // Emit a dense jump table (switch-like) using br_table.
410416 switch ( bt , condThunk , caseThunks , defaultThunk ) {
417+ const startStackHeight = this . _blockStack . length ;
418+
411419 // Emit one block per case…
412420 caseThunks . forEach ( _ => this . _blockOnly ( bt ) ) ;
413421
@@ -419,10 +427,12 @@ class Assembler {
419427 this . brTable ( labels , w . labelidx ( labels . length ) ) ;
420428 } ) ;
421429 caseThunks . forEach ( ( fn , i ) => {
422- fn ( ) ;
423- this . break ( labels . length - ( i + 1 ) ) ; // Jump to end.
430+ const depth = labels . length - ( i + 1 ) ;
431+ fn ( depth ) ;
432+ this . break ( depth ) ; // Jump to end.
424433 this . _endBlock ( ) ;
425434 } ) ;
435+ assert ( this . _blockStack . length === startStackHeight ) ;
426436 }
427437
428438 // "Macros" -- codegen helpers specific to Ohm.
@@ -825,7 +835,9 @@ export class Compiler {
825835 asm . switch (
826836 w . blocktype . empty ,
827837 ( ) => asm . localGet ( '__arg0' ) ,
828- this . liftedTerminals . values ( ) . map ( str => ( ) => this . emitTerminal ( ir . terminal ( str ) ) ) ,
838+ this . liftedTerminals
839+ . values ( )
840+ . map ( str => depth => this . emitTerminal ( ir . terminal ( str ) , depth ) ) ,
829841 ( ) => asm . emit ( w . instr . unreachable ) ,
830842 ) ;
831843 asm . localGet ( 'ret' ) ;
@@ -894,10 +906,12 @@ export class Compiler {
894906 const rulePatterns = setdefault ( patternsByRule , ruleName , ( ) => new Map ( ) ) ;
895907 rulePatterns . set ( specializedName , children ) ;
896908
897- // Note that we deliberately *don't* visit this application yet,
898- // so it won't be assigned a rule ID.
899- const caseIdx = rulePatterns . size - 1 ;
900- body = ir . applyGeneralized ( ruleName , caseIdx ) ;
909+ if ( EMIT_GENERALIZED_RULES ) {
910+ // Note that we deliberately *don't* visit this application yet,
911+ // so it won't be assigned a rule ID.
912+ const caseIdx = rulePatterns . size - 1 ;
913+ body = ir . applyGeneralized ( ruleName , caseIdx ) ;
914+ }
901915 }
902916 newRules . set ( specializedName , { ...ruleInfo , body, formals : [ ] } ) ;
903917 }
@@ -909,24 +923,26 @@ export class Compiler {
909923 specialize ( ir . apply ( 'spaces' ) ) ;
910924 this . rules = newRules ;
911925
912- const insertDispatches = ( exp , patterns ) =>
913- ir . rewrite ( exp , {
914- Apply : app => ( app . children . length === 0 ? app : ir . dispatch ( app , patterns ) ) ,
915- Param : p => ir . dispatch ( p , patterns ) ,
916- } ) ;
926+ if ( EMIT_GENERALIZED_RULES ) {
927+ const insertDispatches = ( exp , patterns ) =>
928+ ir . rewrite ( exp , {
929+ Apply : app => ( app . children . length === 0 ? app : ir . dispatch ( app , patterns ) ) ,
930+ Param : p => ir . dispatch ( p , patterns ) ,
931+ } ) ;
917932
918- // Save the observed patterns of the parameterized rules.
919- // All non-parameterized & specialized rules have been discovered and
920- // assigned IDs; any rule IDs assigned here won't be memoized.
921- for ( const [ name , patterns ] of patternsByRule . entries ( ) ) {
922- this . _ensureRuleId ( name , { notMemoized : true } ) ;
923- const ruleInfo = getNotNull ( rules , name ) ;
924- const patternsArr = [ ...patterns . values ( ) ] ;
925- newRules . set ( name , {
926- ...ruleInfo ,
927- body : insertDispatches ( ruleInfo . body , patternsArr ) ,
928- patterns : patternsArr ,
929- } ) ;
933+ // Save the observed patterns of the parameterized rules.
934+ // All non-parameterized & specialized rules have been discovered and
935+ // assigned IDs; any rule IDs assigned here won't be memoized.
936+ for ( const [ name , patterns ] of patternsByRule . entries ( ) ) {
937+ this . _ensureRuleId ( name , { notMemoized : true } ) ;
938+ const ruleInfo = getNotNull ( rules , name ) ;
939+ const patternsArr = [ ...patterns . values ( ) ] ;
940+ newRules . set ( name , {
941+ ...ruleInfo ,
942+ body : insertDispatches ( ruleInfo . body , patternsArr ) ,
943+ patterns : patternsArr ,
944+ } ) ;
945+ }
930946 }
931947 }
932948
@@ -1124,11 +1140,12 @@ export class Compiler {
11241140 return ;
11251141 }
11261142 if ( exp . type === 'ApplyGeneralized' ) {
1143+ assert ( EMIT_GENERALIZED_RULES ) ;
11271144 this . emitApplyGeneralized ( exp ) ;
11281145 return ;
11291146 }
11301147
1131- const debugLabel = getDebugLabel ( exp ) ;
1148+ const debugLabel = ir . toString ( exp ) ;
11321149 asm . emit ( `BEGIN ${ debugLabel } ` ) ;
11331150 asm . pushStackFrame ( ) ;
11341151
@@ -1355,14 +1372,14 @@ export class Compiler {
13551372 asm . localSet ( 'ret' ) ;
13561373 }
13571374
1358- emitTerminal ( { value} ) {
1375+ emitTerminal ( { value} , depth = 0 ) {
13591376 // TODO:
13601377 // - proper UTF-8!
13611378 // - handle longer terminals with a loop
13621379 // - SIMD
13631380
13641381 const { asm} = this ;
1365- asm . emit ( 'Terminal' ) ;
1382+ asm . emit ( JSON . stringify ( value ) ) ;
13661383 this . maybeEmitSpaceSkipping ( ) ;
13671384 for ( const c of [ ...value ] ) {
13681385 // Compare next char
@@ -1371,7 +1388,7 @@ export class Compiler {
13711388 asm . emit ( instr . i32 . ne ) ;
13721389 asm . if ( w . blocktype . empty , ( ) => {
13731390 asm . setRet ( 0 ) ;
1374- asm . break ( 1 ) ;
1391+ asm . break ( depth + 1 ) ;
13751392 } ) ;
13761393 asm . incPos ( ) ;
13771394 }
0 commit comments