@ -18,7 +18,7 @@
( define-for-syntax ( rules->token-types rules )
( define-values ( implicit-tokens explicit-tokens ) ( rules-collect-token-types rules ) )
( remove-duplicates ( append ( for/list ( [ it ( in-list implicit-tokens ) ] )
( string->symbol ( syntax-e it ) ) )
( string->symbol ( syntax-e it ) ) )
( map syntax-e explicit-tokens ) ) eq? ) )
( define-syntax ( brag-module-begin rules-stx )
@ -38,7 +38,7 @@
( with-syntax ( [ START-ID ( first rule-ids ) ] ; The first rule, by default, is the start rule.
[ ( ( TOKEN-TYPE . TOKEN-TYPE-CONSTRUCTOR ) ... )
( for/list ( [ tt ( in-list ( rules->token-types rules ) ) ] )
( cons tt ( string->symbol ( format " token-~a " tt ) ) ) ) ]
( cons tt ( string->symbol ( format " token-~a " tt ) ) ) ) ]
;; Flatten rules to use the yacc-style ruleset that br-parser-tools supports
[ GENERATED-RULE-CODES ( map flat-rule->yacc-rule ( flatten-rules rules ) ) ]
;; main exports. Break hygiene so they're also available at top-level / repl
@ -71,41 +71,38 @@
( cons eof token-EOF )
( cons ' TOKEN-TYPE TOKEN-TYPE-CONSTRUCTOR ) ... ) ) )
( define-syntax ( MAKE-RULE-PARSER rule-id-stx )
( syntax-case rule-id-stx ( )
[ ( _ start-rule )
( and ( identifier? #' start-rule )
( member ( syntax-e #' start-rule ) ' RULE-IDS ) )
( define-syntax ( MAKE-RULE-PARSER stx )
( syntax-case stx ( )
[ ( _ START-RULE-ID )
( and ( identifier? #' START-RULE-ID ) ( member ( syntax-e #' START-RULE-ID ) ' RULE-IDS ) )
;; The cfg-parser depends on the start-rule provided in (start ...) to have the same
;; context as the rest of this body. Hence RECOLORED-START-RULE
( with-syntax ( [ RECOLORED-START-RULE ( datum->syntax #' RULES-STX ( syntax-e #' start-rule ) ) ] )
#' ( let ( [ THE-GRAMMAR ( cfg-parser ( tokens enumerated-tokens )
( src-pos )
( start RECOLORED-START-RULE )
( end EOF )
( error THE-ERROR-HANDLER )
( grammar . GENERATED-RULE-CODES ) ) ] )
( procedure-rename
( case-lambda [ ( tokenizer )
( define next-token
( make-permissive-tokenizer tokenizer all-tokens-hash/mutable ) )
;; little post-processor to support cuts on top rule name
( define parse-tree-stx ( THE-GRAMMAR next-token ) )
( define top-rule-name-stx ( syntax-case parse-tree-stx ( )
[ ( TRN . REST ) #' TRN ]
[ _ ( error ' malformed-parse-tree ) ] ) )
( if ( eq? ( syntax-property top-rule-name-stx ' hide-or-splice? ) ' hide )
;; use `remove-rule-name` so we get the same housekeeping
( remove-rule-name parse-tree-stx )
parse-tree-stx ) ]
[ ( source tokenizer )
( parameterize ( [ current-source source ] )
( PARSE tokenizer ) ) ] )
( string->symbol ( format " ~a-rule-parser " ' start-rule ) ) ) ) ) ]
( with-syntax ( [ RECOLORED-START-RULE ( datum->syntax #' RULES-STX ( syntax-e #' START-RULE-ID ) ) ] )
#' ( let ( )
( define ( rule-parser tokenizer )
( define rule-grammar ( cfg-parser ( tokens enumerated-tokens )
( src-pos )
( start RECOLORED-START-RULE )
( end EOF )
( error the-error-handler )
( grammar . GENERATED-RULE-CODES ) ) )
( define next-token ( make-permissive-tokenizer tokenizer all-tokens-hash/mutable ) )
;; here's how we support grammar "cuts" on top rule name
( define parse-tree-stx ( rule-grammar next-token ) )
( syntax-case parse-tree-stx ( )
[ ( TOP-RULE-NAME . _ )
( if ( eq? ( syntax-property #' TOP-RULE-NAME ' hide-or-splice? ) ' hide )
( remove-rule-name parse-tree-stx ) ; use `remove-rule-name` so we get the same housekeeping
parse-tree-stx ) ]
[ _ ( error ' malformed-parse-tree ) ] ) )
( case-lambda [ ( tokenizer ) ( rule-parser tokenizer ) ]
[ ( source tokenizer )
( parameterize ( [ current-source source ] )
( rule-parser tokenizer ) ) ] ) ) ) ]
[ ( _ not-a-rule-id )
( raise-syntax-error #f
( format " Rule ~a is not defined in the grammar " ( syntax-e #' not-a-rule-id ) )
rule-id- stx) ] ) )
stx) ] ) )
;; start-id has to be a value, not an expr, because make-rule-parser is a macro
( define PARSE ( procedure-rename ( MAKE-RULE-PARSER START-ID ) ' PARSE ) )