@@ -20,6 +20,7 @@ import {
20
20
Parser ,
21
21
sequence ,
22
22
UnexpectedError ,
23
+ UnrecognizedError ,
23
24
withPosition ,
24
25
withSource ,
25
26
} from "../src/parser/parser_lib.ts" ;
@@ -53,7 +54,9 @@ const ignore = allWithCheck(
53
54
function lex < T > ( parser : Parser < T > ) : Parser < T > {
54
55
return parser . skip ( ignore ) ;
55
56
}
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
+ ) ;
57
60
const openParenthesis = lex ( matchString ( "(" , "open parenthesis" ) ) ;
58
61
const closeParenthesis = lex ( matchString ( ")" , "close parenthesis" ) ) ;
59
62
const openBracket = lex ( matchString ( "[" , "open bracket" ) ) ;
@@ -577,7 +580,10 @@ const definition = choiceWithCheck<Definition>(
577
580
twoFormPersonalPronounDefinition ,
578
581
fourFormPersonalPronounDefinition ,
579
582
) ;
580
- const head = sequence ( all ( tokiPonaWord . skip ( comma ) ) , tokiPonaWord )
583
+ const positionedHead = sequence (
584
+ all ( wordWithPosition . skip ( comma ) ) ,
585
+ wordWithPosition ,
586
+ )
581
587
. skip ( colon )
582
588
. map ( ( [ init , last ] ) => [ ...init , last ] ) ;
583
589
const entry = withSource (
@@ -592,11 +598,32 @@ const entry = withSource(
592
598
)
593
599
. map ( ( [ definitions , source ] ) => ( { definitions, source : source . trimEnd ( ) } ) ) ;
594
600
export 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