@@ -20,6 +20,7 @@ import {
2020 Parser ,
2121 sequence ,
2222 UnexpectedError ,
23+ UnrecognizedError ,
2324 withPosition ,
2425 withSource ,
2526} from "../src/parser/parser_lib.ts" ;
@@ -53,7 +54,9 @@ const ignore = allWithCheck(
5354function lex < T > ( parser : Parser < T > ) : Parser < T > {
5455 return parser . skip ( ignore ) ;
5556}
56- const tokiPonaWord = lex ( match ( / [ a - z ] [ a - z A - Z ] * / , "word" ) ) ;
57+ const wordWithPosition = lex (
58+ withPosition ( match ( / [ a - z ] [ a - z A - Z ] * / , "Toki Pona word" ) ) ,
59+ ) ;
5760const openParenthesis = lex ( matchString ( "(" , "open parenthesis" ) ) ;
5861const closeParenthesis = lex ( matchString ( ")" , "close parenthesis" ) ) ;
5962const openBracket = lex ( matchString ( "[" , "open bracket" ) ) ;
@@ -577,7 +580,10 @@ const definition = choiceWithCheck<Definition>(
577580 twoFormPersonalPronounDefinition ,
578581 fourFormPersonalPronounDefinition ,
579582) ;
580- const head = sequence ( all ( tokiPonaWord . skip ( comma ) ) , tokiPonaWord )
583+ const positionedHead = sequence (
584+ all ( wordWithPosition . skip ( comma ) ) ,
585+ wordWithPosition ,
586+ )
581587 . skip ( colon )
582588 . map ( ( [ init , last ] ) => [ ...init , last ] ) ;
583589const entry = withSource (
@@ -592,11 +598,32 @@ const entry = withSource(
592598)
593599 . map ( ( [ definitions , source ] ) => ( { definitions, source : source . trimEnd ( ) } ) ) ;
594600export const dictionaryParser = ignore
595- . with ( allWithCheck ( new CheckedParser ( notEnd , sequence ( head , entry ) ) ) )
596- . map ( ( entries ) =>
597- new Map (
598- entries . flatMap ( ( [ words , definition ] ) =>
599- words . map ( ( word ) => [ word , definition ] )
600- ) ,
601- )
602- ) ;
601+ . with (
602+ allWithCheck ( new CheckedParser ( notEnd , sequence ( positionedHead , entry ) ) ) ,
603+ )
604+ . map ( ( allEntries ) => {
605+ const entries = allEntries . flatMap ( ( [ words , definition ] ) =>
606+ words . map ( ( word ) => [ word , definition ] as const )
607+ ) ;
608+ const recorded : Set < string > = new Set ( ) ;
609+ const errors : Array < UnrecognizedError > = [ ] ;
610+ for ( const [ head ] of entries ) {
611+ if ( recorded . has ( head . value ) ) {
612+ errors . push (
613+ new UnrecognizedError (
614+ `duplicate Toki Pona word "${ head . value } "` ,
615+ head ,
616+ ) ,
617+ ) ;
618+ } else {
619+ recorded . add ( head . value ) ;
620+ }
621+ }
622+ if ( errors . length > 0 ) {
623+ throw new AggregateError ( errors ) ;
624+ } else {
625+ return new Map (
626+ entries . map ( ( [ head , definition ] ) => [ head . value , definition ] ) ,
627+ ) ;
628+ }
629+ } ) ;
0 commit comments