44
55use ariadne:: { Color , Label , Report , ReportKind , Source } ;
66use chumsky:: {
7- input:: { Stream , ValueInput } ,
7+ input:: { SliceInput , Stream , ValueInput } ,
88 prelude:: * ,
99} ;
1010use logos:: Logos ;
@@ -31,33 +31,38 @@ enum Token<'a> {
3131 #[ token( ")" ) ]
3232 RParen ,
3333
34+ #[ regex( "[A-Za-z_]+" ) ]
35+ Ident ,
36+
3437 #[ regex( r"[ \t\f\n]+" , logos:: skip) ]
3538 Whitespace ,
3639}
3740
3841impl < ' a > fmt:: Display for Token < ' a > {
3942 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
4043 match self {
41- Self :: Float ( s) => write ! ( f, "{}" , s ) ,
44+ Self :: Float ( s) => write ! ( f, "{s}" ) ,
4245 Self :: Add => write ! ( f, "+" ) ,
4346 Self :: Sub => write ! ( f, "-" ) ,
4447 Self :: Mul => write ! ( f, "*" ) ,
4548 Self :: Div => write ! ( f, "/" ) ,
4649 Self :: LParen => write ! ( f, "(" ) ,
4750 Self :: RParen => write ! ( f, ")" ) ,
4851 Self :: Whitespace => write ! ( f, "<whitespace>" ) ,
52+ Self :: Ident => write ! ( f, "<ident>" ) ,
4953 Self :: Error => write ! ( f, "<error>" ) ,
5054 }
5155 }
5256}
5357
5458#[ derive( Debug ) ]
55- enum SExpr {
59+ enum SExpr < ' a > {
5660 Float ( f64 ) ,
5761 Add ,
5862 Sub ,
5963 Mul ,
6064 Div ,
65+ Ident ( & ' a str ) ,
6166 List ( Vec < Self > ) ,
6267}
6368
@@ -71,9 +76,9 @@ enum SExpr {
7176// - Has an input type of type `I`, the one we declared as a type parameter
7277// - Produces an `SExpr` as its output
7378// - Uses `Rich`, a built-in error type provided by chumsky, for error generation
74- fn parser < ' a , I > ( ) -> impl Parser < ' a , I , SExpr , extra:: Err < Rich < ' a , Token < ' a > > > >
79+ fn parser < ' a , I > ( ) -> impl Parser < ' a , I , SExpr < ' a > , extra:: Err < Rich < ' a , Token < ' a > > > >
7580where
76- I : ValueInput < ' a , Token = Token < ' a > , Span = SimpleSpan > ,
81+ I : ValueInput < ' a , Token = Token < ' a > , Span = SimpleSpan > + SliceInput < ' a , Slice = & ' a str > ,
7782{
7883 recursive ( |sexpr| {
7984 let atom = select ! {
@@ -84,17 +89,19 @@ where
8489 Token :: Div => SExpr :: Div ,
8590 } ;
8691
92+ let ident = just ( Token :: Ident ) . slice ( ) . map ( SExpr :: Ident ) ;
93+
8794 let list = sexpr
8895 . repeated ( )
8996 . collect ( )
9097 . map ( SExpr :: List )
9198 . delimited_by ( just ( Token :: LParen ) , just ( Token :: RParen ) ) ;
9299
93- atom. or ( list)
100+ atom. or ( ident ) . or ( list)
94101 } )
95102}
96103
97- impl SExpr {
104+ impl < ' a > SExpr < ' a > {
98105 // Recursively evaluate an s-expression
99106 fn eval ( & self ) -> Result < f64 , & ' static str > {
100107 match self {
@@ -103,6 +110,7 @@ impl SExpr {
103110 Self :: Sub => Err ( "Cannot evaluate operator '-'" ) ,
104111 Self :: Mul => Err ( "Cannot evaluate operator '*'" ) ,
105112 Self :: Div => Err ( "Cannot evaluate operator '/'" ) ,
113+ Self :: Ident ( _) => Err ( "Identifiers not supported" ) ,
106114 Self :: List ( list) => match & list[ ..] {
107115 [ Self :: Add , tail @ ..] => tail. iter ( ) . map ( SExpr :: eval) . sum ( ) ,
108116 [ Self :: Mul , tail @ ..] => tail. iter ( ) . map ( SExpr :: eval) . product ( ) ,
@@ -142,7 +150,8 @@ fn main() {
142150 let token_stream = Stream :: from_iter ( token_iter)
143151 // Tell chumsky to split the (Token, SimpleSpan) stream into its parts so that it can handle the spans for us
144152 // This involves giving chumsky an 'end of input' span: we just use a zero-width span at the end of the string
145- . spanned ( ( SRC . len ( ) ..SRC . len ( ) ) . into ( ) ) ;
153+ . spanned ( ( SRC . len ( ) ..SRC . len ( ) ) . into ( ) )
154+ . with_slice ( SRC ) ;
146155
147156 // Parse the token stream with our chumsky parser
148157 match parser ( ) . parse ( token_stream) . into_result ( ) {
0 commit comments