Get basic compiler working
This commit is contained in:
		
							parent
							
								
									3414aaee9b
								
							
						
					
					
						commit
						b0a4f9dc7e
					
				
							
								
								
									
										183
									
								
								src/compiler.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/compiler.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | |||||||
|  | use std::collections::HashMap; | ||||||
|  | 
 | ||||||
|  | use super::errors::CompilerError; | ||||||
|  | use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement}; | ||||||
|  | 
 | ||||||
|  | type Variable = (VariableID, VariableType); | ||||||
|  | type VariableID = u32; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum Command { | ||||||
|  |     InitializeVariable(VariableID, VariableType), | ||||||
|  |     BeginScope, | ||||||
|  |     EndScope, | ||||||
|  |     Pop(u32),                        // Pop into registery u32
 | ||||||
|  |     Push(u32),                       // Push out of registery 32
 | ||||||
|  |     AssignVariable(VariableID, u32), // Assign variable from registery u32
 | ||||||
|  |     VarToReg(VariableID, u32),       // Bring Variable to registery u32
 | ||||||
|  |     StringLit(String),               // Bring String Literal to Heap
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | pub enum VariableType { | ||||||
|  |     TypeString, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Compiler { | ||||||
|  |     parsed: ParsedReid, | ||||||
|  |     root_scope: Scope, | ||||||
|  |     list: Vec<Command>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct CompiledReid { | ||||||
|  |     pub list: Vec<Command>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Compiler { | ||||||
|  |     pub fn from(parsed: ParsedReid) -> Compiler { | ||||||
|  |         Compiler { | ||||||
|  |             parsed, | ||||||
|  |             root_scope: Scope::default(), | ||||||
|  |             list: Vec::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn compile(mut self) -> Result<CompiledReid, CompilerError> { | ||||||
|  |         self.handle_expression(self.parsed.0.clone())?; | ||||||
|  |         Ok(CompiledReid { list: self.list }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn handle_expression( | ||||||
|  |         &mut self, | ||||||
|  |         exp: Expression, | ||||||
|  |     ) -> Result<Option<VariableType>, CompilerError> { | ||||||
|  |         match exp { | ||||||
|  |             Expression::BlockExpr(pos, list) => { | ||||||
|  |                 self.list.push(Command::BeginScope); | ||||||
|  |                 self.root_scope.begin_scope(); | ||||||
|  | 
 | ||||||
|  |                 for statement in list { | ||||||
|  |                     self.handle_statement(statement)?; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 self.root_scope.end_scope(pos)?; | ||||||
|  |                 self.list.push(Command::EndScope); | ||||||
|  |                 Ok(None) | ||||||
|  |             } | ||||||
|  |             Expression::ValueRef(_, val) => match val { | ||||||
|  |                 Pattern::IdentPattern(pos, ident) => { | ||||||
|  |                     if let Some(var) = self.root_scope.get(ident.clone()) { | ||||||
|  |                         self.list.push(Command::VarToReg(var.0, 0)); | ||||||
|  |                         self.list.push(Command::Push(0)); | ||||||
|  |                         Ok(Some(var.1)) | ||||||
|  |                     } else { | ||||||
|  |                         Err(CompilerError::VariableNotExists(pos, ident)) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 Pattern::LiteralPattern(_, literal) => { | ||||||
|  |                     let vtype = self.handle_literal(literal)?; | ||||||
|  |                     Ok(Some(vtype)) | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn handle_statement( | ||||||
|  |         &mut self, | ||||||
|  |         statement: Statement, | ||||||
|  |     ) -> Result<Option<VariableType>, CompilerError> { | ||||||
|  |         match statement { | ||||||
|  |             Statement::LetStatement(pos, ident, val) => { | ||||||
|  |                 let res = self.handle_expression(*val); | ||||||
|  |                 match res { | ||||||
|  |                     Ok(vtype) => { | ||||||
|  |                         if let Some(vtype) = vtype { | ||||||
|  |                             self.root_scope.add_var(pos, ident.clone(), vtype)?; | ||||||
|  |                             let var = self.root_scope.get(ident).unwrap(); | ||||||
|  |                             self.list.push(Command::InitializeVariable(var.0, var.1)); | ||||||
|  |                             self.list.push(Command::Pop(0)); | ||||||
|  |                             self.list.push(Command::AssignVariable(var.0, 0)); | ||||||
|  |                             Ok(None) | ||||||
|  |                         } else { | ||||||
|  |                             Err(CompilerError::LetFailed( | ||||||
|  |                                 pos, | ||||||
|  |                                 Box::new(CompilerError::CanNotAssignVoidType), | ||||||
|  |                             )) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     Err(err) => Err(CompilerError::LetFailed(pos, Box::new(err))), | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Statement::ExprStatement(pos, expr) => self.handle_expression(expr), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn handle_literal(&mut self, pattern: LiteralPattern) -> Result<VariableType, CompilerError> { | ||||||
|  |         match pattern { | ||||||
|  |             LiteralPattern::StringLit(string) => self.list.push(Command::StringLit(string)), | ||||||
|  |         } | ||||||
|  |         Ok(VariableType::TypeString) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Default)] | ||||||
|  | pub struct Scope { | ||||||
|  |     counter: VariableID, | ||||||
|  |     variables: HashMap<String, Variable>, | ||||||
|  |     innerScope: Option<Box<Scope>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Scope { | ||||||
|  |     fn get(&self, variable: String) -> Option<Variable> { | ||||||
|  |         if let Some(val) = self.variables.get(&variable) { | ||||||
|  |             Some(*val) | ||||||
|  |         } else if let Some(inner) = &self.innerScope { | ||||||
|  |             if let Some(val) = inner.get(variable) { | ||||||
|  |                 Some((val.0 + self.counter, val.1)) | ||||||
|  |             } else { | ||||||
|  |                 None | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn add_var( | ||||||
|  |         &mut self, | ||||||
|  |         pos: Position, | ||||||
|  |         variable: String, | ||||||
|  |         vtype: VariableType, | ||||||
|  |     ) -> Result<(), CompilerError> { | ||||||
|  |         if self.variables.contains_key(&variable) { | ||||||
|  |             Err(CompilerError::VariableExists(pos, variable)) | ||||||
|  |         } else if let Some(inner) = &mut self.innerScope { | ||||||
|  |             inner.add_var(pos, variable, vtype) | ||||||
|  |         } else { | ||||||
|  |             self.variables.insert(variable, (self.counter, vtype)); | ||||||
|  |             self.counter += 1; | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn begin_scope(&mut self) { | ||||||
|  |         if let Some(inner) = &mut self.innerScope { | ||||||
|  |             inner.begin_scope(); | ||||||
|  |         } else { | ||||||
|  |             self.innerScope = Some(Box::default()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn end_scope(&mut self, pos: Position) -> Result<(), CompilerError> { | ||||||
|  |         if let Some(inner) = &mut self.innerScope { | ||||||
|  |             if inner.innerScope.is_some() { | ||||||
|  |                 inner.end_scope(pos)?; | ||||||
|  |             } else { | ||||||
|  |                 self.innerScope = None; | ||||||
|  |             } | ||||||
|  |             Ok(()) | ||||||
|  |         } else { | ||||||
|  |             Err(CompilerError::InvalidScopeExit(pos)) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -15,17 +15,17 @@ impl From<io::Error> for GenericError { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum CompilerError { | pub enum SyntaxError { | ||||||
|     Fatal, |     Fatal, | ||||||
|     ExpectedToken(Position, char), |     ExpectedToken(Position, char), | ||||||
|     ExpectedExpression(Position, Option<Box<CompilerError>>), |     ExpectedExpression(Position, Option<Box<SyntaxError>>), | ||||||
|     ExpectedIdent(Position), |     ExpectedIdent(Position), | ||||||
|     ExpectedStatement(Position, Option<Box<CompilerError>>), |     ExpectedStatement(Position, Option<Box<SyntaxError>>), | ||||||
|     ExpectedPattern(Position), |     ExpectedPattern(Position), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl CompilerError { | impl SyntaxError { | ||||||
|     fn from_opt(from: &Option<Box<CompilerError>>) -> String { |     fn from_opt(from: &Option<Box<SyntaxError>>) -> String { | ||||||
|         if let Some(err) = from { |         if let Some(err) = from { | ||||||
|             format!("\n  {}", err) |             format!("\n  {}", err) | ||||||
|         } else { |         } else { | ||||||
| @ -34,24 +34,44 @@ impl CompilerError { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Display for CompilerError { | impl Display for SyntaxError { | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         let text = match self { |         let text = match self { | ||||||
|             CompilerError::Fatal => "Fatal error".to_string(), |             SyntaxError::Fatal => "Fatal error".to_string(), | ||||||
|             CompilerError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos), |             SyntaxError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos), | ||||||
|             CompilerError::ExpectedExpression(pos, err) => format!( |             SyntaxError::ExpectedExpression(pos, err) => format!( | ||||||
|                 "Expected expression at {}{}", |                 "Expected expression at {}{}", | ||||||
|                 pos, |                 pos, | ||||||
|                 CompilerError::from_opt(err) |                 SyntaxError::from_opt(err) | ||||||
|             ), |             ), | ||||||
|             CompilerError::ExpectedIdent(pos) => format!("Expected ident at {}", pos), |             SyntaxError::ExpectedIdent(pos) => format!("Expected ident at {}", pos), | ||||||
|             CompilerError::ExpectedStatement(pos, err) => format!( |             SyntaxError::ExpectedStatement(pos, err) => format!( | ||||||
|                 "Expected statement at {}{}", |                 "Expected statement at {}{}", | ||||||
|                 pos, |                 pos, | ||||||
|                 CompilerError::from_opt(err) |                 SyntaxError::from_opt(err) | ||||||
|             ), |             ), | ||||||
|             CompilerError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos), |             SyntaxError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos), | ||||||
|         }; |         }; | ||||||
|         write!(f, "{}", text) |         write!(f, "{}", text) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum CompilerError { | ||||||
|  |     Fatal, | ||||||
|  |     VariableExists(Position, String), | ||||||
|  |     VariableNotExists(Position, String), | ||||||
|  |     InvalidScopeExit(Position), | ||||||
|  |     LetFailed(Position, Box<CompilerError>), | ||||||
|  |     CanNotAssignVoidType, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl CompilerError { | ||||||
|  |     fn from_opt(from: &Option<Box<SyntaxError>>) -> String { | ||||||
|  |         if let Some(err) = from { | ||||||
|  |             format!("\n  {}", err) | ||||||
|  |         } else { | ||||||
|  |             String::new() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -1,17 +1,29 @@ | |||||||
|  | mod compiler; | ||||||
| mod errors; | mod errors; | ||||||
| mod file_io; | mod file_io; | ||||||
| mod parser; | mod parser; | ||||||
| 
 | 
 | ||||||
|  | use compiler::Compiler; | ||||||
| use file_io::open_file; | use file_io::open_file; | ||||||
| use parser::Parser; | use parser::Parser; | ||||||
| use std::path::Path; | use std::path::Path; | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     let path = Path::new("reid_src/test.reid"); |     let path = Path::new("reid_src/test.reid"); | ||||||
|     let reid = Parser::from(open_file(&path).ok().unwrap()).parse(); |     let parsed = Parser::from(open_file(&path).ok().unwrap()).parse(); | ||||||
|     if let Err(error) = reid { |     match parsed { | ||||||
|         eprintln!("Syntax error: {}", error); |         Err(error) => { | ||||||
|         std::process::exit(1); |             eprintln!("Syntax error: {}", error); | ||||||
|  |             std::process::exit(1); | ||||||
|  |         } | ||||||
|  |         Ok(parsed) => { | ||||||
|  |             dbg!(&parsed); | ||||||
|  |             let compiled = Compiler::from(parsed).compile(); | ||||||
|  |             if let Err(error) = compiled { | ||||||
|  |                 eprintln!("Compilation error: {:#?}", error); | ||||||
|  |                 std::process::exit(1); | ||||||
|  |             } | ||||||
|  |             dbg!(compiled); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     dbg!(reid); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| mod parsed_reid; | mod parsed_reid; | ||||||
| 
 | 
 | ||||||
| use super::errors::CompilerError; | use super::errors::SyntaxError; | ||||||
| use parsed_reid::{Expression, ParsedReid, Statement}; | pub use parsed_reid::*; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::fmt::Display; | use std::fmt::Display; | ||||||
| 
 | 
 | ||||||
| @ -31,7 +31,7 @@ impl Parser { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn parse(mut self) -> Result<ParsedReid, CompilerError> { |     pub fn parse(mut self) -> Result<ParsedReid, SyntaxError> { | ||||||
|         let mut statement_list = Vec::new(); |         let mut statement_list = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let mut error = None; |         let mut error = None; | ||||||
| @ -211,7 +211,7 @@ impl Expect<'_> { | |||||||
|         } |         } | ||||||
|         self.text |         self.text | ||||||
|     } |     } | ||||||
|     pub fn get_or(self, error: CompilerError) -> Result<String, CompilerError> { |     pub fn get_or(self, error: SyntaxError) -> Result<String, SyntaxError> { | ||||||
|         match self.get() { |         match self.get() { | ||||||
|             Some(text) => Ok(text), |             Some(text) => Ok(text), | ||||||
|             None => Err(error), |             None => Err(error), | ||||||
|  | |||||||
| @ -1,35 +1,35 @@ | |||||||
| use super::{CompilerError, Parser, Position}; | use super::{Parser, Position, SyntaxError}; | ||||||
| 
 | 
 | ||||||
| type Ident = String; | type Ident = String; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub struct ParsedReid(pub Expression); | pub struct ParsedReid(pub Expression); | ||||||
| #[derive(Debug)] |  | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
| pub enum Statement { | pub enum Statement { | ||||||
|     LetStatement(Position, Ident, Box<Expression>), |     LetStatement(Position, Ident, Box<Expression>), | ||||||
|     ExprStatement(Position, Expression), |     ExprStatement(Position, Expression), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Statement { | impl Statement { | ||||||
|     pub fn parse(parser: &mut Parser) -> Result<Statement, CompilerError> { |     pub fn parse(parser: &mut Parser) -> Result<Statement, SyntaxError> { | ||||||
|         let pos = parser.pos(); |         let pos = parser.pos(); | ||||||
| 
 | 
 | ||||||
|         if let Some(_) = parser.expect("let").get() { |         if let Some(_) = parser.expect("let").get() { | ||||||
|             let ident = parser |             let ident = parser | ||||||
|                 .expect_ident() |                 .expect_ident() | ||||||
|                 .get_or(CompilerError::ExpectedIdent(pos))?; |                 .get_or(SyntaxError::ExpectedIdent(pos))?; | ||||||
|             parser |             parser | ||||||
|                 .expect("=") |                 .expect("=") | ||||||
|                 .get_or(CompilerError::ExpectedToken(pos, '='))?; |                 .get_or(SyntaxError::ExpectedToken(pos, '='))?; | ||||||
|             match Expression::parse(parser) { |             match Expression::parse(parser) { | ||||||
|                 Ok(expr) => { |                 Ok(expr) => { | ||||||
|                     parser |                     parser | ||||||
|                         .expect(";") |                         .expect(";") | ||||||
|                         .get_or(CompilerError::ExpectedToken(pos, ';'))?; |                         .get_or(SyntaxError::ExpectedToken(pos, ';'))?; | ||||||
|                     Ok(Statement::LetStatement(pos, ident, Box::new(expr))) |                     Ok(Statement::LetStatement(pos, ident, Box::new(expr))) | ||||||
|                 } |                 } | ||||||
|                 Err(err) => Err(CompilerError::ExpectedExpression(pos, Some(Box::new(err)))), |                 Err(err) => Err(SyntaxError::ExpectedExpression(pos, Some(Box::new(err)))), | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             match Expression::parse(parser) { |             match Expression::parse(parser) { | ||||||
| @ -37,23 +37,23 @@ impl Statement { | |||||||
|                     let statement = Statement::ExprStatement(pos, expr); |                     let statement = Statement::ExprStatement(pos, expr); | ||||||
|                     parser |                     parser | ||||||
|                         .expect(";") |                         .expect(";") | ||||||
|                         .get_or(CompilerError::ExpectedToken(pos, ';'))?; |                         .get_or(SyntaxError::ExpectedToken(pos, ';'))?; | ||||||
|                     Ok(statement) |                     Ok(statement) | ||||||
|                 } |                 } | ||||||
|                 Err(err) => Err(CompilerError::ExpectedStatement(pos, Some(Box::new(err)))), |                 Err(err) => Err(SyntaxError::ExpectedStatement(pos, Some(Box::new(err)))), | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub enum Expression { | pub enum Expression { | ||||||
|     BlockExpr(Position, Vec<Statement>), |     BlockExpr(Position, Vec<Statement>), | ||||||
|     ValueRef(Position, Pattern), |     ValueRef(Position, Pattern), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Expression { | impl Expression { | ||||||
|     pub fn parse(parser: &mut Parser) -> Result<Expression, CompilerError> { |     pub fn parse(parser: &mut Parser) -> Result<Expression, SyntaxError> { | ||||||
|         let begin_pos = parser.pos(); |         let begin_pos = parser.pos(); | ||||||
| 
 | 
 | ||||||
|         let expect = parser.expect("{"); |         let expect = parser.expect("{"); | ||||||
| @ -71,24 +71,24 @@ impl Expression { | |||||||
|             if let Some(_) = parser.expect("}").get() { |             if let Some(_) = parser.expect("}").get() { | ||||||
|                 Ok(Expression::BlockExpr(begin_pos, statement_list)) |                 Ok(Expression::BlockExpr(begin_pos, statement_list)) | ||||||
|             } else { |             } else { | ||||||
|                 Err(CompilerError::ExpectedToken(parser.pos(), '}')) |                 Err(SyntaxError::ExpectedToken(parser.pos(), '}')) | ||||||
|             } |             } | ||||||
|         } else if let Ok(pattern) = Pattern::parse(parser) { |         } else if let Ok(pattern) = Pattern::parse(parser) { | ||||||
|             Ok(Expression::ValueRef(begin_pos, pattern)) |             Ok(Expression::ValueRef(begin_pos, pattern)) | ||||||
|         } else { |         } else { | ||||||
|             Err(CompilerError::ExpectedExpression(begin_pos, None)) |             Err(SyntaxError::ExpectedExpression(begin_pos, None)) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub enum Pattern { | pub enum Pattern { | ||||||
|     IdentPattern(Position, Ident), |     IdentPattern(Position, Ident), | ||||||
|     LiteralPattern(Position, LiteralPattern), |     LiteralPattern(Position, LiteralPattern), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Pattern { | impl Pattern { | ||||||
|     fn parse(parser: &mut Parser) -> Result<Pattern, CompilerError> { |     fn parse(parser: &mut Parser) -> Result<Pattern, SyntaxError> { | ||||||
|         let pos = parser.pos(); |         let pos = parser.pos(); | ||||||
|         if let Some(string) = parser.expect_string_lit().get() { |         if let Some(string) = parser.expect_string_lit().get() { | ||||||
|             Ok(Pattern::LiteralPattern( |             Ok(Pattern::LiteralPattern( | ||||||
| @ -98,12 +98,12 @@ impl Pattern { | |||||||
|         } else if let Some(ident) = parser.expect_ident().get() { |         } else if let Some(ident) = parser.expect_ident().get() { | ||||||
|             Ok(Pattern::IdentPattern(pos, ident)) |             Ok(Pattern::IdentPattern(pos, ident)) | ||||||
|         } else { |         } else { | ||||||
|             Err(CompilerError::ExpectedPattern(pos)) |             Err(SyntaxError::ExpectedPattern(pos)) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub enum LiteralPattern { | pub enum LiteralPattern { | ||||||
|     StringLit(String), |     StringLit(String), | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user