Compare commits
	
		
			2 Commits
		
	
	
		
			1263d84802
			...
			aa3f4b3a8b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | aa3f4b3a8b | ||
|   | ae8f89bb4e | 
							
								
								
									
										421
									
								
								src/ast/build.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								src/ast/build.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,421 @@ | |||||||
|  | use crate::ast::{ | ||||||
|  |     BlockStatement, CompilationUnit, Declaration, Fqn, FunctionDeclaration, GenericArgument, | ||||||
|  |     GenericParameter, Identifier, ImplCtor, ImplCtorArg, Parameter, TypeDeclaration, TypeUse, | ||||||
|  | }; | ||||||
|  | use crate::parser::{DeimosParser, Rule}; | ||||||
|  | use crate::vm::source_code_location::SourceCodeLocation; | ||||||
|  | use pest::iterators::Pair; | ||||||
|  | use pest::Parser; | ||||||
|  | 
 | ||||||
|  | fn build_field(field_pair: Pair<Rule>) -> Declaration { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_prop(prop_pair: Pair<Rule>) -> Declaration { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_impl_ctor_arg(impl_ctor_arg_pair: Pair<Rule>) -> ImplCtorArg { | ||||||
|  |     let mut is_field = false; | ||||||
|  |     let mut identifier: Option<Identifier> = None; | ||||||
|  |     let mut r#type: Option<TypeUse> = None; | ||||||
|  | 
 | ||||||
|  |     for pair in impl_ctor_arg_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::fld => { | ||||||
|  |                 is_field = true; | ||||||
|  |             } | ||||||
|  |             Rule::identifier => { | ||||||
|  |                 identifier = Some(build_identifier(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::type_use => { | ||||||
|  |                 r#type = Some(build_type_use(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Unexpected rule: {}", pair), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ImplCtorArg { | ||||||
|  |         is_field, | ||||||
|  |         identifier: identifier.unwrap(), | ||||||
|  |         r#type, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_impl_ctor(impl_ctor_pair: Pair<Rule>) -> ImplCtor { | ||||||
|  |     let impl_ctor_args_pair = impl_ctor_pair.into_inner().next().unwrap(); | ||||||
|  |     let mut args: Vec<ImplCtorArg> = vec![]; | ||||||
|  | 
 | ||||||
|  |     for pair in impl_ctor_args_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::impl_ctor_arg => { | ||||||
|  |                 args.push(build_impl_ctor_arg(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Unexpected rule: {}", pair), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ImplCtor { args } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_generic_argument(generic_argument_pair: Pair<Rule>) -> GenericArgument { | ||||||
|  |     let fqn_pair = generic_argument_pair.into_inner().next().unwrap(); | ||||||
|  |     GenericArgument { | ||||||
|  |         fqn: build_fqn(fqn_pair), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_generic_arguments_declaration( | ||||||
|  |     generic_arguments_declaration_pair: Pair<Rule>, | ||||||
|  | ) -> Vec<GenericArgument> { | ||||||
|  |     let mut generic_arguments: Vec<GenericArgument> = vec![]; | ||||||
|  |     for pair in generic_arguments_declaration_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::generic_argument => { | ||||||
|  |                 generic_arguments.push(build_generic_argument(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Expected only generic_argument rules. Found: {}", pair), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     generic_arguments | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_generic_parameter(generic_parameter_pair: Pair<Rule>) -> GenericParameter { | ||||||
|  |     let identifier_pair = generic_parameter_pair.into_inner().next().unwrap(); | ||||||
|  |     GenericParameter { | ||||||
|  |         identifier: build_identifier(identifier_pair), | ||||||
|  |         bound: None, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_type_use(type_pair: Pair<Rule>) -> TypeUse { | ||||||
|  |     let mut fqn: Option<Fqn> = None; | ||||||
|  |     let mut generic_arguments_declaration: Option<Vec<GenericArgument>> = None; | ||||||
|  | 
 | ||||||
|  |     for pair in type_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::fqn => { | ||||||
|  |                 fqn = Some(build_fqn(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::generic_arguments_declaration => { | ||||||
|  |                 generic_arguments_declaration = Some(build_generic_arguments_declaration(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!( | ||||||
|  |                 "Expected only fqn or generic_arguments_declaration rules. Found: {}", | ||||||
|  |                 pair | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     TypeUse { | ||||||
|  |         fqn: fqn.unwrap(), | ||||||
|  |         generics: generic_arguments_declaration.unwrap_or(vec![]), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_generic_parameters_declaration( | ||||||
|  |     generic_parameters_declaration_pair: Pair<Rule>, | ||||||
|  | ) -> Vec<GenericParameter> { | ||||||
|  |     let mut parameters: Vec<GenericParameter> = vec![]; | ||||||
|  |     for pair in generic_parameters_declaration_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::generic_parameter => { | ||||||
|  |                 parameters.push(build_generic_parameter(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Expected only generic_parameter rule. Found: {}", pair), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     parameters | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_extends_list(extends_list_pair: Pair<Rule>) -> Vec<TypeUse> { | ||||||
|  |     let mut extensions: Vec<TypeUse> = vec![]; | ||||||
|  | 
 | ||||||
|  |     for pair in extends_list_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::type_use => { | ||||||
|  |                 extensions.push(build_type_use(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Expected only type rule. Found: {}", pair), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     extensions | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_interface(is_extern: bool, is_public: bool, interface_pair: Pair<Rule>) -> Declaration { | ||||||
|  |     let mut identifier: Option<Identifier> = None; | ||||||
|  |     let mut generic_parameters: Option<Vec<GenericParameter>> = None; | ||||||
|  |     let mut extends: Option<Vec<TypeUse>> = None; | ||||||
|  |     let mut declarations: Vec<Declaration> = vec![]; | ||||||
|  | 
 | ||||||
|  |     for pair in interface_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::identifier => { | ||||||
|  |                 identifier = Some(build_identifier(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::generic_parameters_declaration => { | ||||||
|  |                 generic_parameters = Some(build_generic_parameters_declaration(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::extends_list => { | ||||||
|  |                 extends = Some(build_extends_list(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::declaration => { | ||||||
|  |                 declarations.push(build_declaration(pair)); | ||||||
|  |             }, | ||||||
|  |             _ => panic!( | ||||||
|  |                 "Expected only identifier, generics_declaration, extends_list, or declaration rules. Found: {}", | ||||||
|  |                 pair | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Declaration::Interface { | ||||||
|  |         identifier: identifier.unwrap(), | ||||||
|  |         is_extern, | ||||||
|  |         is_public, | ||||||
|  |         type_declaration: TypeDeclaration::new( | ||||||
|  |             generic_parameters.unwrap_or(vec![]), | ||||||
|  |             extends.unwrap_or(vec![]), | ||||||
|  |             declarations, | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_implementation( | ||||||
|  |     is_extern: bool, | ||||||
|  |     is_public: bool, | ||||||
|  |     implementation_pair: Pair<Rule>, | ||||||
|  | ) -> Declaration { | ||||||
|  |     let mut identifier: Option<Identifier> = None; | ||||||
|  |     let mut generic_parameters: Option<Vec<GenericParameter>> = None; | ||||||
|  |     let mut impl_ctor: Option<ImplCtor> = None; | ||||||
|  |     let mut extends: Option<Vec<TypeUse>> = None; | ||||||
|  |     let mut declarations: Vec<Declaration> = vec![]; | ||||||
|  | 
 | ||||||
|  |     for pair in implementation_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::identifier => { | ||||||
|  |                 identifier = Some(build_identifier(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::generic_parameters_declaration => { | ||||||
|  |                 generic_parameters = Some(build_generic_parameters_declaration(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::impl_ctor => { | ||||||
|  |                 impl_ctor = Some(build_impl_ctor(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::extends_list => { | ||||||
|  |                 extends = Some(build_extends_list(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::declaration => { | ||||||
|  |                 declarations.push(build_declaration(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Unexpected rule: {}", pair), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Declaration::Implementation { | ||||||
|  |         identifier: identifier.unwrap(), | ||||||
|  |         is_extern, | ||||||
|  |         is_public, | ||||||
|  |         type_declaration: TypeDeclaration::new( | ||||||
|  |             generic_parameters.unwrap_or(vec![]), | ||||||
|  |             extends.unwrap_or(vec![]), | ||||||
|  |             declarations, | ||||||
|  |         ), | ||||||
|  |         impl_ctor, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_module(is_extern: bool, is_public: bool, pair: Pair<Rule>) -> Declaration { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_parameter(pair: Pair<Rule>) -> Parameter { | ||||||
|  |     let mut identifier: Option<Identifier> = None; | ||||||
|  |     let mut declared_type: Option<TypeUse> = None; | ||||||
|  |     for pair in pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::identifier => { | ||||||
|  |                 identifier = Some(build_identifier(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::type_use => { | ||||||
|  |                 declared_type = Some(build_type_use(pair)); | ||||||
|  |             } | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Parameter { | ||||||
|  |         identifier: identifier.unwrap(), | ||||||
|  |         declared_type, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_parameters_list(pair: Pair<Rule>) -> Vec<Parameter> { | ||||||
|  |     let mut parameters: Vec<Parameter> = vec![]; | ||||||
|  |     for pair in pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::parameter => { | ||||||
|  |                 parameters.push(build_parameter(pair)); | ||||||
|  |             } | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     parameters | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_function_body(pair: Pair<Rule>) -> BlockStatement { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_function_equals_body(pair: Pair<Rule>) -> BlockStatement { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_function(is_extern: bool, is_public: bool, pair: Pair<Rule>) -> Declaration { | ||||||
|  |     let mut generic_parameters: Option<Vec<GenericParameter>> = None; | ||||||
|  |     let mut identifier: Option<Identifier> = None; | ||||||
|  |     let mut parameters: Option<Vec<Parameter>> = None; | ||||||
|  |     let mut return_type: Option<TypeUse> = None; | ||||||
|  |     let mut statement: Option<BlockStatement> = None; | ||||||
|  | 
 | ||||||
|  |     let (line, col) = pair.line_col(); | ||||||
|  | 
 | ||||||
|  |     for pair in pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::generic_parameters_declaration => { | ||||||
|  |                 generic_parameters = Some(build_generic_parameters_declaration(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::identifier => { | ||||||
|  |                 identifier = Some(build_identifier(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::parameters_list => { | ||||||
|  |                 parameters = Some(build_parameters_list(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::type_use => { | ||||||
|  |                 return_type = Some(build_type_use(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::function_body => { | ||||||
|  |                 statement = Some(build_function_body(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::function_equals_body => { | ||||||
|  |                 statement = Some(build_function_equals_body(pair)); | ||||||
|  |             } | ||||||
|  |             _ => unreachable!(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Declaration::Function(FunctionDeclaration { | ||||||
|  |         is_extern, | ||||||
|  |         is_public, | ||||||
|  |         identifier: identifier.unwrap(), | ||||||
|  |         parameters: parameters.unwrap(), | ||||||
|  |         declared_type: return_type, | ||||||
|  |         block_statement: statement.unwrap(), | ||||||
|  |         source_code_location: SourceCodeLocation { | ||||||
|  |             source_file_name: "TODO".to_string(), | ||||||
|  |             line, | ||||||
|  |             col, | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_declaration(declaration_pair: Pair<Rule>) -> Declaration { | ||||||
|  |     let mut is_extern = false; | ||||||
|  |     let mut is_public = false; | ||||||
|  |     let mut declaration: Option<Declaration> = None; | ||||||
|  | 
 | ||||||
|  |     for pair in declaration_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::r#extern => { | ||||||
|  |                 is_extern = true; | ||||||
|  |             } | ||||||
|  |             Rule::r#pub => { | ||||||
|  |                 is_public = true; | ||||||
|  |             } | ||||||
|  |             Rule::interface => { | ||||||
|  |                 declaration = Some(build_interface(is_extern, is_public, pair)); | ||||||
|  |             } | ||||||
|  |             Rule::implementation => { | ||||||
|  |                 declaration = Some(build_implementation(is_extern, is_public, pair)); | ||||||
|  |             } | ||||||
|  |             Rule::module => { | ||||||
|  |                 declaration = Some(build_module(is_extern, is_public, pair)); | ||||||
|  |             } | ||||||
|  |             Rule::function => { | ||||||
|  |                 declaration = Some(build_function(is_extern, is_public, pair)); | ||||||
|  |             } | ||||||
|  |             Rule::prop => { | ||||||
|  |                 declaration = Some(build_prop(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::field => { | ||||||
|  |                 declaration = Some(build_field(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!( | ||||||
|  |                 "Expected only interface, implementation, module, or function rules; found {}", | ||||||
|  |                 pair | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     declaration.expect("Expected declaration.") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_identifier(pair: Pair<Rule>) -> Identifier { | ||||||
|  |     match pair.as_rule() { | ||||||
|  |         Rule::identifier => Identifier { | ||||||
|  |             name: String::from(pair.as_str()), | ||||||
|  |         }, | ||||||
|  |         _ => panic!("Expected an identifier."), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_fqn(fqn_pair: Pair<Rule>) -> Fqn { | ||||||
|  |     let mut identifiers: Vec<Identifier> = vec![]; | ||||||
|  |     for pair in fqn_pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::identifier => { | ||||||
|  |                 identifiers.push(build_identifier(pair)); | ||||||
|  |             } | ||||||
|  |             _ => panic!("Expected only identifiers."), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Fqn { identifiers } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_compilation_unit(pair: Pair<Rule>) -> CompilationUnit { | ||||||
|  |     let mut namespace: Option<Fqn> = None; | ||||||
|  |     let mut declarations: Vec<Declaration> = vec![]; | ||||||
|  | 
 | ||||||
|  |     for pair in pair.into_inner() { | ||||||
|  |         match pair.as_rule() { | ||||||
|  |             Rule::namespace => { | ||||||
|  |                 let fqn_pair = pair.into_inner().next().unwrap(); | ||||||
|  |                 namespace = Some(build_fqn(fqn_pair)); | ||||||
|  |             } | ||||||
|  |             Rule::declaration => { | ||||||
|  |                 declarations.push(build_declaration(pair)); | ||||||
|  |             } | ||||||
|  |             Rule::EOI => {} // ignore
 | ||||||
|  |             _ => panic!( | ||||||
|  |                 "Expected only namespace, declaration, or EOI rules, found: {}", | ||||||
|  |                 pair | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     CompilationUnit { | ||||||
|  |         namespace, | ||||||
|  |         declarations, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn build_ast(src: &str) -> CompilationUnit { | ||||||
|  |     let pair = DeimosParser::parse(Rule::compilation_unit, src) | ||||||
|  |         .expect("Unsuccessful parse.") | ||||||
|  |         .next() | ||||||
|  |         .expect("Expcted compilation_unit."); | ||||||
|  |     match pair.as_rule() { | ||||||
|  |         Rule::compilation_unit => build_compilation_unit(pair), | ||||||
|  |         _ => panic!("Expected compilation_unit rule."), | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										548
									
								
								src/ast/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										548
									
								
								src/ast/mod.rs
									
									
									
									
									
								
							| @ -1,5 +1,7 @@ | |||||||
| use crate::parser::{DeimosParser, Rule}; | use crate::vm::source_code_location::SourceCodeLocation; | ||||||
| use pest::{iterators::Pair, Parser}; | use pest::Parser; | ||||||
|  | 
 | ||||||
|  | pub mod build; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct CompilationUnit { | pub struct CompilationUnit { | ||||||
| @ -7,11 +9,39 @@ pub struct CompilationUnit { | |||||||
|     declarations: Vec<Declaration>, |     declarations: Vec<Declaration>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl CompilationUnit { | ||||||
|  |     pub fn namespace(&self) -> &Option<Fqn> { | ||||||
|  |         &self.namespace | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn declarations(&self) -> &Vec<Declaration> { | ||||||
|  |         &self.declarations | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Fqn { | pub struct Fqn { | ||||||
|     identifiers: Vec<Identifier>, |     identifiers: Vec<Identifier>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl Fqn { | ||||||
|  |     pub fn new(identifiers: Vec<Identifier>) -> Self { | ||||||
|  |         Fqn { identifiers } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn identifiers(&self) -> &Vec<Identifier> { | ||||||
|  |         &self.identifiers | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn push_identifier(&mut self, identifier: Identifier) { | ||||||
|  |         self.identifiers.push(identifier); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn pop_identifier(&mut self) { | ||||||
|  |         self.identifiers.pop(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum Declaration { | pub enum Declaration { | ||||||
|     Interface { |     Interface { | ||||||
| @ -33,18 +63,36 @@ pub enum Declaration { | |||||||
|         is_public: bool, |         is_public: bool, | ||||||
|         declarations: Vec<Declaration>, |         declarations: Vec<Declaration>, | ||||||
|     }, |     }, | ||||||
|     Function { |     Function(FunctionDeclaration), | ||||||
|         identifier: Identifier, |  | ||||||
|         is_extern: bool, |  | ||||||
|         is_public: bool, |  | ||||||
|         parameters: Vec<Parameter>, |  | ||||||
|         declared_type: Option<TypeUse>, |  | ||||||
|         statement: Statement, |  | ||||||
|     }, |  | ||||||
|     Prop(Prop), |     Prop(Prop), | ||||||
|     Field(Field), |     Field(Field), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct FunctionDeclaration { | ||||||
|  |     source_code_location: SourceCodeLocation, | ||||||
|  |     identifier: Identifier, | ||||||
|  |     is_extern: bool, | ||||||
|  |     is_public: bool, | ||||||
|  |     parameters: Vec<Parameter>, | ||||||
|  |     declared_type: Option<TypeUse>, | ||||||
|  |     block_statement: BlockStatement, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FunctionDeclaration { | ||||||
|  |     pub fn source_code_location(&self) -> &SourceCodeLocation { | ||||||
|  |         &self.source_code_location | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn identifier(&self) -> &Identifier { | ||||||
|  |         &self.identifier | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn block_statement(&self) -> &BlockStatement { | ||||||
|  |         &self.block_statement | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct TypeDeclaration { | pub struct TypeDeclaration { | ||||||
|     generics: Vec<GenericParameter>, |     generics: Vec<GenericParameter>, | ||||||
| @ -66,11 +114,17 @@ impl TypeDeclaration { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub struct Identifier { | pub struct Identifier { | ||||||
|     name: String, |     name: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl Identifier { | ||||||
|  |     pub fn name(&self) -> &str { | ||||||
|  |         &self.name | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct GenericParameter { | pub struct GenericParameter { | ||||||
|     identifier: Identifier, |     identifier: Identifier, | ||||||
| @ -118,11 +172,71 @@ pub struct Field { | |||||||
|     r#type: TypeUse, |     r#type: TypeUse, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct BlockStatement { | ||||||
|  |     statements: Vec<Statement>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl BlockStatement { | ||||||
|  |     pub fn statements(&self) -> &Vec<Statement> { | ||||||
|  |         &self.statements | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum Statement { | pub enum Statement { | ||||||
|     BlockStatement { statements: Vec<Statement> }, |     CallStatement(CallExpression), | ||||||
|     CallStatement, |     AssignStatement(AssignExpression), | ||||||
|     AssignmentStatement, | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct CallExpression { | ||||||
|  |     receiver: Expression, | ||||||
|  |     actuals_list: Vec<Expression>, | ||||||
|  |     source_code_location: SourceCodeLocation, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl CallExpression { | ||||||
|  |     pub fn receiver(&self) -> &Expression { | ||||||
|  |         &self.receiver | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn actuals_list(&self) -> &Vec<Expression> { | ||||||
|  |         &self.actuals_list | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn source_code_location(&self) -> &SourceCodeLocation { | ||||||
|  |         &self.source_code_location | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct AssignExpression { | ||||||
|  |     left: LValue, | ||||||
|  |     right: Expression, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum Expression { | ||||||
|  |     CallExpression(Box<CallExpression>), | ||||||
|  |     AssignExpression(Box<AssignExpression>), | ||||||
|  |     LValue(Box<LValue>), | ||||||
|  |     Literal(Box<Literal>), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum LValue { | ||||||
|  |     Fqn(Fqn), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub enum Literal { | ||||||
|  |     IntegerLiteral(i32), | ||||||
|  |     LongLiteral(i64), | ||||||
|  |     DoubleLiteral(f64), | ||||||
|  |     USizeLiteral(usize), | ||||||
|  |     StringLiteral(String), | ||||||
|  |     BooleanLiteral(bool), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @ -130,409 +244,3 @@ pub struct Parameter { | |||||||
|     identifier: Identifier, |     identifier: Identifier, | ||||||
|     declared_type: Option<TypeUse>, |     declared_type: Option<TypeUse>, | ||||||
| } | } | ||||||
| 
 |  | ||||||
| fn build_field(field_pair: Pair<Rule>) -> Declaration { |  | ||||||
|     todo!() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_prop(prop_pair: Pair<Rule>) -> Declaration { |  | ||||||
|     todo!() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_impl_ctor_arg(impl_ctor_arg_pair: Pair<Rule>) -> ImplCtorArg { |  | ||||||
|     let mut is_field = false; |  | ||||||
|     let mut identifier: Option<Identifier> = None; |  | ||||||
|     let mut r#type: Option<TypeUse> = None; |  | ||||||
| 
 |  | ||||||
|     for pair in impl_ctor_arg_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::fld => { |  | ||||||
|                 is_field = true; |  | ||||||
|             } |  | ||||||
|             Rule::identifier => { |  | ||||||
|                 identifier = Some(build_identifier(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::type_use => { |  | ||||||
|                 r#type = Some(build_type_use(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Unexpected rule: {}", pair), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ImplCtorArg { |  | ||||||
|         is_field, |  | ||||||
|         identifier: identifier.unwrap(), |  | ||||||
|         r#type, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_impl_ctor(impl_ctor_pair: Pair<Rule>) -> ImplCtor { |  | ||||||
|     let impl_ctor_args_pair = impl_ctor_pair.into_inner().next().unwrap(); |  | ||||||
|     let mut args: Vec<ImplCtorArg> = vec![]; |  | ||||||
| 
 |  | ||||||
|     for pair in impl_ctor_args_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::impl_ctor_arg => { |  | ||||||
|                 args.push(build_impl_ctor_arg(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Unexpected rule: {}", pair), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ImplCtor { args } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_generic_argument(generic_argument_pair: Pair<Rule>) -> GenericArgument { |  | ||||||
|     let fqn_pair = generic_argument_pair.into_inner().next().unwrap(); |  | ||||||
|     GenericArgument { |  | ||||||
|         fqn: build_fqn(fqn_pair), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_generic_arguments_declaration( |  | ||||||
|     generic_arguments_declaration_pair: Pair<Rule>, |  | ||||||
| ) -> Vec<GenericArgument> { |  | ||||||
|     let mut generic_arguments: Vec<GenericArgument> = vec![]; |  | ||||||
|     for pair in generic_arguments_declaration_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::generic_argument => { |  | ||||||
|                 generic_arguments.push(build_generic_argument(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Expected only generic_argument rules. Found: {}", pair), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     generic_arguments |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_generic_parameter(generic_parameter_pair: Pair<Rule>) -> GenericParameter { |  | ||||||
|     let identifier_pair = generic_parameter_pair.into_inner().next().unwrap(); |  | ||||||
|     GenericParameter { |  | ||||||
|         identifier: build_identifier(identifier_pair), |  | ||||||
|         bound: None, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_type_use(type_pair: Pair<Rule>) -> TypeUse { |  | ||||||
|     let mut fqn: Option<Fqn> = None; |  | ||||||
|     let mut generic_arguments_declaration: Option<Vec<GenericArgument>> = None; |  | ||||||
| 
 |  | ||||||
|     for pair in type_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::fqn => { |  | ||||||
|                 fqn = Some(build_fqn(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::generic_arguments_declaration => { |  | ||||||
|                 generic_arguments_declaration = Some(build_generic_arguments_declaration(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!( |  | ||||||
|                 "Expected only fqn or generic_arguments_declaration rules. Found: {}", |  | ||||||
|                 pair |  | ||||||
|             ), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     TypeUse { |  | ||||||
|         fqn: fqn.unwrap(), |  | ||||||
|         generics: generic_arguments_declaration.unwrap_or(vec![]), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_generic_parameters_declaration( |  | ||||||
|     generic_parameters_declaration_pair: Pair<Rule>, |  | ||||||
| ) -> Vec<GenericParameter> { |  | ||||||
|     let mut parameters: Vec<GenericParameter> = vec![]; |  | ||||||
|     for pair in generic_parameters_declaration_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::generic_parameter => { |  | ||||||
|                 parameters.push(build_generic_parameter(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Expected only generic_parameter rule. Found: {}", pair), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     parameters |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_extends_list(extends_list_pair: Pair<Rule>) -> Vec<TypeUse> { |  | ||||||
|     let mut extensions: Vec<TypeUse> = vec![]; |  | ||||||
| 
 |  | ||||||
|     for pair in extends_list_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::type_use => { |  | ||||||
|                 extensions.push(build_type_use(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Expected only type rule. Found: {}", pair), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     extensions |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_interface(is_extern: bool, is_public: bool, interface_pair: Pair<Rule>) -> Declaration { |  | ||||||
|     let mut identifier: Option<Identifier> = None; |  | ||||||
|     let mut generic_parameters: Option<Vec<GenericParameter>> = None; |  | ||||||
|     let mut extends: Option<Vec<TypeUse>> = None; |  | ||||||
|     let mut declarations: Vec<Declaration> = vec![]; |  | ||||||
| 
 |  | ||||||
|     for pair in interface_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::identifier => { |  | ||||||
|                 identifier = Some(build_identifier(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::generic_parameters_declaration => { |  | ||||||
|                 generic_parameters = Some(build_generic_parameters_declaration(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::extends_list => { |  | ||||||
|                 extends = Some(build_extends_list(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::declaration => { |  | ||||||
|                 declarations.push(build_declaration(pair)); |  | ||||||
|             }, |  | ||||||
|             _ => panic!( |  | ||||||
|                 "Expected only identifier, generics_declaration, extends_list, or declaration rules. Found: {}", |  | ||||||
|                 pair |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Declaration::Interface { |  | ||||||
|         identifier: identifier.unwrap(), |  | ||||||
|         is_extern, |  | ||||||
|         is_public, |  | ||||||
|         type_declaration: TypeDeclaration::new( |  | ||||||
|             generic_parameters.unwrap_or(vec![]), |  | ||||||
|             extends.unwrap_or(vec![]), |  | ||||||
|             declarations, |  | ||||||
|         ), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_implementation( |  | ||||||
|     is_extern: bool, |  | ||||||
|     is_public: bool, |  | ||||||
|     implementation_pair: Pair<Rule>, |  | ||||||
| ) -> Declaration { |  | ||||||
|     let mut identifier: Option<Identifier> = None; |  | ||||||
|     let mut generic_parameters: Option<Vec<GenericParameter>> = None; |  | ||||||
|     let mut impl_ctor: Option<ImplCtor> = None; |  | ||||||
|     let mut extends: Option<Vec<TypeUse>> = None; |  | ||||||
|     let mut declarations: Vec<Declaration> = vec![]; |  | ||||||
| 
 |  | ||||||
|     for pair in implementation_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::identifier => { |  | ||||||
|                 identifier = Some(build_identifier(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::generic_parameters_declaration => { |  | ||||||
|                 generic_parameters = Some(build_generic_parameters_declaration(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::impl_ctor => { |  | ||||||
|                 impl_ctor = Some(build_impl_ctor(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::extends_list => { |  | ||||||
|                 extends = Some(build_extends_list(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::declaration => { |  | ||||||
|                 declarations.push(build_declaration(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Unexpected rule: {}", pair), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Declaration::Implementation { |  | ||||||
|         identifier: identifier.unwrap(), |  | ||||||
|         is_extern, |  | ||||||
|         is_public, |  | ||||||
|         type_declaration: TypeDeclaration::new( |  | ||||||
|             generic_parameters.unwrap_or(vec![]), |  | ||||||
|             extends.unwrap_or(vec![]), |  | ||||||
|             declarations, |  | ||||||
|         ), |  | ||||||
|         impl_ctor, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_module(is_extern: bool, is_public: bool, pair: Pair<Rule>) -> Declaration { |  | ||||||
|     todo!() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_parameter(pair: Pair<Rule>) -> Parameter { |  | ||||||
|     let mut identifier: Option<Identifier> = None; |  | ||||||
|     let mut declared_type: Option<TypeUse> = None; |  | ||||||
|     for pair in pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::identifier => { |  | ||||||
|                 identifier = Some(build_identifier(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::type_use => { |  | ||||||
|                 declared_type = Some(build_type_use(pair)); |  | ||||||
|             } |  | ||||||
|             _ => unreachable!(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     Parameter { |  | ||||||
|         identifier: identifier.unwrap(), |  | ||||||
|         declared_type, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_parameters_list(pair: Pair<Rule>) -> Vec<Parameter> { |  | ||||||
|     let mut parameters: Vec<Parameter> = vec![]; |  | ||||||
|     for pair in pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::parameter => { |  | ||||||
|                 parameters.push(build_parameter(pair)); |  | ||||||
|             } |  | ||||||
|             _ => unreachable!(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     parameters |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_function_body(pair: Pair<Rule>) -> Statement { |  | ||||||
|     todo!() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_function_equals_body(pair: Pair<Rule>) -> Statement { |  | ||||||
|     todo!() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_function(is_extern: bool, is_public: bool, pair: Pair<Rule>) -> Declaration { |  | ||||||
|     let mut generic_parameters: Option<Vec<GenericParameter>> = None; |  | ||||||
|     let mut identifier: Option<Identifier> = None; |  | ||||||
|     let mut parameters: Option<Vec<Parameter>> = None; |  | ||||||
|     let mut return_type: Option<TypeUse> = None; |  | ||||||
|     let mut statement: Option<Statement> = None; |  | ||||||
| 
 |  | ||||||
|     for pair in pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::generic_parameters_declaration => { |  | ||||||
|                 generic_parameters = Some(build_generic_parameters_declaration(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::identifier => { |  | ||||||
|                 identifier = Some(build_identifier(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::parameters_list => { |  | ||||||
|                 parameters = Some(build_parameters_list(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::type_use => { |  | ||||||
|                 return_type = Some(build_type_use(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::function_body => { |  | ||||||
|                 statement = Some(build_function_body(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::function_equals_body => { |  | ||||||
|                 statement = Some(build_function_equals_body(pair)); |  | ||||||
|             } |  | ||||||
|             _ => unreachable!(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     Declaration::Function { |  | ||||||
|         is_extern, |  | ||||||
|         is_public, |  | ||||||
|         identifier: identifier.unwrap(), |  | ||||||
|         parameters: parameters.unwrap(), |  | ||||||
|         declared_type: return_type, |  | ||||||
|         statement: statement.unwrap(), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_declaration(declaration_pair: Pair<Rule>) -> Declaration { |  | ||||||
|     let mut is_extern = false; |  | ||||||
|     let mut is_public = false; |  | ||||||
|     let mut declaration: Option<Declaration> = None; |  | ||||||
| 
 |  | ||||||
|     for pair in declaration_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::r#extern => { |  | ||||||
|                 is_extern = true; |  | ||||||
|             } |  | ||||||
|             Rule::r#pub => { |  | ||||||
|                 is_public = true; |  | ||||||
|             } |  | ||||||
|             Rule::interface => { |  | ||||||
|                 declaration = Some(build_interface(is_extern, is_public, pair)); |  | ||||||
|             } |  | ||||||
|             Rule::implementation => { |  | ||||||
|                 declaration = Some(build_implementation(is_extern, is_public, pair)); |  | ||||||
|             } |  | ||||||
|             Rule::module => { |  | ||||||
|                 declaration = Some(build_module(is_extern, is_public, pair)); |  | ||||||
|             } |  | ||||||
|             Rule::function => { |  | ||||||
|                 declaration = Some(build_function(is_extern, is_public, pair)); |  | ||||||
|             } |  | ||||||
|             Rule::prop => { |  | ||||||
|                 declaration = Some(build_prop(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::field => { |  | ||||||
|                 declaration = Some(build_field(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!( |  | ||||||
|                 "Expected only interface, implementation, module, or function rules; found {}", |  | ||||||
|                 pair |  | ||||||
|             ), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     declaration.expect("Expected declaration.") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_identifier(pair: Pair<Rule>) -> Identifier { |  | ||||||
|     match pair.as_rule() { |  | ||||||
|         Rule::identifier => Identifier { |  | ||||||
|             name: String::from(pair.as_str()), |  | ||||||
|         }, |  | ||||||
|         _ => panic!("Expected an identifier."), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_fqn(fqn_pair: Pair<Rule>) -> Fqn { |  | ||||||
|     let mut identifiers: Vec<Identifier> = vec![]; |  | ||||||
|     for pair in fqn_pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::identifier => { |  | ||||||
|                 identifiers.push(build_identifier(pair)); |  | ||||||
|             } |  | ||||||
|             _ => panic!("Expected only identifiers."), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     Fqn { identifiers } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn build_compilation_unit(pair: Pair<Rule>) -> CompilationUnit { |  | ||||||
|     let mut namespace: Option<Fqn> = None; |  | ||||||
|     let mut declarations: Vec<Declaration> = vec![]; |  | ||||||
| 
 |  | ||||||
|     for pair in pair.into_inner() { |  | ||||||
|         match pair.as_rule() { |  | ||||||
|             Rule::namespace => { |  | ||||||
|                 let fqn_pair = pair.into_inner().next().unwrap(); |  | ||||||
|                 namespace = Some(build_fqn(fqn_pair)); |  | ||||||
|             } |  | ||||||
|             Rule::declaration => { |  | ||||||
|                 declarations.push(build_declaration(pair)); |  | ||||||
|             } |  | ||||||
|             Rule::EOI => {} // ignore
 |  | ||||||
|             _ => panic!( |  | ||||||
|                 "Expected only namespace, declaration, or EOI rules, found: {}", |  | ||||||
|                 pair |  | ||||||
|             ), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     CompilationUnit { |  | ||||||
|         namespace, |  | ||||||
|         declarations, |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn build_ast(src: &str) -> CompilationUnit { |  | ||||||
|     let pair = DeimosParser::parse(Rule::compilation_unit, src) |  | ||||||
|         .expect("Unsuccessful parse.") |  | ||||||
|         .next() |  | ||||||
|         .expect("Expcted compilation_unit."); |  | ||||||
|     match pair.as_rule() { |  | ||||||
|         Rule::compilation_unit => build_compilation_unit(pair), |  | ||||||
|         _ => panic!("Expected compilation_unit rule."), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,10 +1,9 @@ | |||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
| 
 | 
 | ||||||
| use deimos::ast::build_ast; | use deimos::ast::build::build_ast; | ||||||
| 
 | 
 | ||||||
| pub fn dump_ast(path: &PathBuf) { | pub fn dump_ast(path: &PathBuf) { | ||||||
|     let src = std::fs::read_to_string(path) |     let src = std::fs::read_to_string(path).expect(&format!("Could not read {:?}", path)); | ||||||
|         .expect(&format!("Could not read {:?}", path)); |  | ||||||
|     let ast = build_ast(&src); |     let ast = build_ast(&src); | ||||||
|     println!("{:?}", ast); |     println!("{:?}", ast); | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,9 +16,7 @@ struct Cli { | |||||||
| #[derive(Debug, Subcommand)] | #[derive(Debug, Subcommand)] | ||||||
| enum Commands { | enum Commands { | ||||||
|     #[command(arg_required_else_help = true)] |     #[command(arg_required_else_help = true)] | ||||||
|     AstDump { |     AstDump { paths: Vec<PathBuf> }, | ||||||
|         paths: Vec<PathBuf> |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
| @ -31,4 +29,3 @@ fn main() { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| use deimos::object_file::{DvmObjectFile, DvmPath}; | use deimos::object_file::{DvmObjectFile, DvmPath}; | ||||||
| use deimos::vm::constant::DvmConstant; | use deimos::vm::constant::DvmConstant; | ||||||
| use deimos::vm::function::DvmFunction; | use deimos::vm::function::DvmFunction; | ||||||
| use deimos::vm::instruction::{Immediate, Instruction, Location}; | use deimos::vm::instruction::{Immediate, Instruction}; | ||||||
| use deimos::vm::platform::get_std_lib_platform_functions; | use deimos::vm::platform::get_std_lib_platform_functions; | ||||||
| use deimos::vm::source_code_location::SourceCodeLocation; | use deimos::vm::source_code_location::SourceCodeLocation; | ||||||
| use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState}; | use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState}; | ||||||
| @ -16,37 +16,81 @@ fn main() { | |||||||
|     //
 |     //
 | ||||||
|     // fn main() {
 |     // fn main() {
 | ||||||
|     //     println "Hello, World!"
 |     //     println "Hello, World!"
 | ||||||
|  |     //     println foo()
 | ||||||
|     // }
 |     // }
 | ||||||
|  |     //
 | ||||||
|  |     // fn foo() = 42
 | ||||||
|     let mut greeter_object_file = DvmObjectFile::new(DvmPath::new("greeter", "greeter.dmo")); |     let mut greeter_object_file = DvmObjectFile::new(DvmPath::new("greeter", "greeter.dmo")); | ||||||
|     
 | 
 | ||||||
|  |     use Instruction::*; | ||||||
|     let main_instructions = vec![ |     let main_instructions = vec![ | ||||||
|         Instruction::MoveImmediate { |         MoveImmediate { | ||||||
|             destination: Location::Register(0), |             destination_register: 0, | ||||||
|             immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))), |             immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))), | ||||||
|         }, |         }, | ||||||
|         Instruction::Push { source_register: 0 }, |         // prepare for call to println
 | ||||||
|         Instruction::InvokeStaticPlatform { |         Push { source_register: 0 }, // save r0
 | ||||||
|  |         Push { source_register: 0 }, // arg0
 | ||||||
|  |         // call
 | ||||||
|  |         InvokeStaticPlatform { | ||||||
|             function_name: Rc::new(String::from("std::core::println")), |             function_name: Rc::new(String::from("std::core::println")), | ||||||
|             source_code_location: SourceCodeLocation { |             source_code_location: SourceCodeLocation { | ||||||
|                 source_file_name: String::from("greeter.dm"), |                 source_file_name: String::from("greeter.dm"), | ||||||
|                 line: 4, |                 line: 4, | ||||||
|                 char: 5, |                 col: 5, | ||||||
|             }, |             }, | ||||||
|         }, |         }, | ||||||
|         Instruction::Pop { |         // unwind from call
 | ||||||
|             // println return value
 |         Pop { | ||||||
|             destination_register: None, |             destination_register: None, | ||||||
|  |         }, // arg0
 | ||||||
|  |         Pop { | ||||||
|  |             destination_register: Some(0), // restore r0
 | ||||||
|         }, |         }, | ||||||
|         Instruction::Pop { |         // prepare for call to foo
 | ||||||
|             // arg0 to println
 |         Push { source_register: 0 }, // save r0
 | ||||||
|  |         InvokeStatic { | ||||||
|  |             function_name: Rc::new(String::from("greeter::foo")), | ||||||
|  |             source_code_location: SourceCodeLocation { | ||||||
|  |                 source_file_name: String::from("greeter.dm"), | ||||||
|  |                 line: 5, | ||||||
|  |                 col: 13, | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         Pop { | ||||||
|  |             destination_register: Some(0), | ||||||
|  |         }, // restore r0
 | ||||||
|  |         TakeReturnValue { | ||||||
|  |             destination_register: 1, | ||||||
|  |         }, | ||||||
|  |         // call println again
 | ||||||
|  |         Push { source_register: 1 }, // save r1
 | ||||||
|  |         Push { source_register: 0 }, // save r0
 | ||||||
|  |         Push { source_register: 1 }, // arg0
 | ||||||
|  |         InvokeStaticPlatform { | ||||||
|  |             function_name: Rc::new(String::from("std::core::println")), | ||||||
|  |             source_code_location: SourceCodeLocation { | ||||||
|  |                 source_file_name: String::from("greeter.dm"), | ||||||
|  |                 line: 5, | ||||||
|  |                 col: 5, | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         Pop { | ||||||
|             destination_register: None, |             destination_register: None, | ||||||
|  |         }, // arg0
 | ||||||
|  |         Pop { | ||||||
|  |             destination_register: Some(0), // restore r0
 | ||||||
|         }, |         }, | ||||||
|         Instruction::MoveImmediate { |         Pop { | ||||||
|             destination: Location::Register(1), |             destination_register: Some(1), // restore r1
 | ||||||
|  |         }, | ||||||
|  |         // return 0
 | ||||||
|  |         MoveImmediate { | ||||||
|  |             destination_register: 2, | ||||||
|             immediate: Immediate::Int(0), |             immediate: Immediate::Int(0), | ||||||
|         }, |         }, | ||||||
|         Instruction::Push { source_register: 1 }, |         SetReturnValue { source_register: 2 }, | ||||||
|         Instruction::Return, |         Return, // explicit, not needed
 | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|     let main_function = DvmFunction::new( |     let main_function = DvmFunction::new( | ||||||
| @ -55,19 +99,37 @@ fn main() { | |||||||
|         SourceCodeLocation { |         SourceCodeLocation { | ||||||
|             source_file_name: String::from("greeter.dm"), |             source_file_name: String::from("greeter.dm"), | ||||||
|             line: 3, |             line: 3, | ||||||
|             char: 1, |             col: 1, | ||||||
|         }, |         }, | ||||||
|     ); |     ); | ||||||
|     
 | 
 | ||||||
|  |     let foo_function_instructions = vec![ | ||||||
|  |         MoveImmediate { | ||||||
|  |             destination_register: 0, | ||||||
|  |             immediate: Immediate::Int(42), | ||||||
|  |         }, | ||||||
|  |         SetReturnValue { source_register: 0 }, | ||||||
|  |         Return, // explicit, not needed
 | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     let foo_function = DvmFunction::new( | ||||||
|  |         "greeter::foo", | ||||||
|  |         &foo_function_instructions, | ||||||
|  |         SourceCodeLocation { | ||||||
|  |             source_file_name: String::from("greeter.dm"), | ||||||
|  |             line: 8, | ||||||
|  |             col: 1, | ||||||
|  |         }, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     greeter_object_file.add_function(main_function); |     greeter_object_file.add_function(main_function); | ||||||
|  |     greeter_object_file.add_function(foo_function); | ||||||
| 
 | 
 | ||||||
|     let mut state = DvmState::new(); |     let mut state = DvmState::new(); | ||||||
|     let mut context = DvmContext::new("greeter::main"); |     let mut context = DvmContext::new("greeter::main"); | ||||||
|     context.add_platform_functions(get_std_lib_platform_functions()); |     context.add_platform_functions(get_std_lib_platform_functions()); | ||||||
|     greeter_object_file.load_to_context(&mut context, &|path| { |     greeter_object_file.load_to_context(&mut context, &|path| todo!()); | ||||||
|         todo!() | 
 | ||||||
|     }); |  | ||||||
|     
 |  | ||||||
|     let exit_code = run_main_function(&mut state, &context); |     let exit_code = run_main_function(&mut state, &context); | ||||||
| 
 | 
 | ||||||
|     dump_state(&state, "After main!"); |     dump_state(&state, "After main!"); | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								src/compile/declared_type.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/compile/declared_type.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | pub enum DeclaredType { | ||||||
|  |     Function(FunctionType), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub enum FunctionType { | ||||||
|  |     StaticFunction, | ||||||
|  |     ObjectFunction, | ||||||
|  |     StaticPlatformFunction, | ||||||
|  |     ObjectPlatformFunction, | ||||||
|  | } | ||||||
							
								
								
									
										164
									
								
								src/compile/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/compile/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,164 @@ | |||||||
|  | use crate::ast::{ | ||||||
|  |     AssignExpression, BlockStatement, CallExpression, CompilationUnit, Declaration, Expression, | ||||||
|  |     Fqn, FunctionDeclaration, Identifier, LValue, Statement, | ||||||
|  | }; | ||||||
|  | use crate::object_file::{DvmObjectFile, DvmPath}; | ||||||
|  | use crate::vm::function::DvmFunction; | ||||||
|  | use crate::vm::instruction::Instruction; | ||||||
|  | use declared_type::{DeclaredType, FunctionType}; | ||||||
|  | use std::rc::Rc; | ||||||
|  | use symbol_table::SymbolTable; | ||||||
|  | 
 | ||||||
|  | mod declared_type; | ||||||
|  | mod symbol; | ||||||
|  | mod symbol_table; | ||||||
|  | 
 | ||||||
|  | struct CompilationState { | ||||||
|  |     fqn_part_stack: Vec<Identifier>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl CompilationState { | ||||||
|  |     fn push_fqn_identifier(&mut self, identifier: &Identifier) { | ||||||
|  |         self.fqn_part_stack.push(identifier.clone()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn pop_fqn_identifier(&mut self) { | ||||||
|  |         self.fqn_part_stack.pop(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn get_current_fqn(&self) -> Fqn { | ||||||
|  |         Fqn::new(self.fqn_part_stack.clone()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct CompilationContext { | ||||||
|  |     source_file_name: String, | ||||||
|  |     symbol_table: SymbolTable, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn compile_call_expression( | ||||||
|  |     context: &CompilationContext, | ||||||
|  |     call_expression: &CallExpression, | ||||||
|  |     instructions: &mut Vec<Instruction>, | ||||||
|  | ) { | ||||||
|  |     match call_expression.receiver() { | ||||||
|  |         Expression::LValue(lvalue) => { | ||||||
|  |             let lvalue = &**lvalue; | ||||||
|  |             if let LValue::Fqn(fqn) = lvalue { | ||||||
|  |                 let symbol = context.symbol_table.resolve(fqn); | ||||||
|  |                 match symbol.declared_type() { | ||||||
|  |                     DeclaredType::Function(function_type) => match function_type { | ||||||
|  |                         FunctionType::StaticFunction => { | ||||||
|  |                             instructions.push(Instruction::InvokeStatic { | ||||||
|  |                                 function_name: Rc::new(convert_fqn(&fqn)), | ||||||
|  |                                 source_code_location: call_expression | ||||||
|  |                                     .source_code_location() | ||||||
|  |                                     .clone(), | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                         _ => todo!(), | ||||||
|  |                     }, | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 todo!() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         _ => todo!(), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn compile_assign_expression( | ||||||
|  |     assign_expression: &AssignExpression, | ||||||
|  |     instruction: &mut Vec<Instruction>, | ||||||
|  | ) { | ||||||
|  |     todo!() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn convert_statement( | ||||||
|  |     context: &CompilationContext, | ||||||
|  |     statement: &Statement, | ||||||
|  |     instructions: &mut Vec<Instruction>, | ||||||
|  | ) { | ||||||
|  |     match statement { | ||||||
|  |         Statement::CallStatement(call_expression) => { | ||||||
|  |             compile_call_expression(context, call_expression, instructions); | ||||||
|  |         } | ||||||
|  |         Statement::AssignStatement(assign_expression) => { | ||||||
|  |             compile_assign_expression(assign_expression, instructions); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn convert_block_statement( | ||||||
|  |     context: &CompilationContext, | ||||||
|  |     block_statement: &BlockStatement, | ||||||
|  | ) -> Vec<Instruction> { | ||||||
|  |     let mut instructions = vec![]; | ||||||
|  |     for statement in block_statement.statements() { | ||||||
|  |         convert_statement(context, statement, &mut instructions); | ||||||
|  |     } | ||||||
|  |     instructions | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn convert_static_function( | ||||||
|  |     compilation_state: &CompilationState, | ||||||
|  |     context: &CompilationContext, | ||||||
|  |     function_declaration: &FunctionDeclaration, | ||||||
|  | ) -> DvmFunction { | ||||||
|  |     let mut fqn = compilation_state.get_current_fqn(); | ||||||
|  |     fqn.push_identifier(function_declaration.identifier().clone()); | ||||||
|  | 
 | ||||||
|  |     let instructions = convert_block_statement(context, function_declaration.block_statement()); | ||||||
|  | 
 | ||||||
|  |     DvmFunction::new( | ||||||
|  |         &convert_fqn(&fqn), | ||||||
|  |         &instructions, | ||||||
|  |         function_declaration.source_code_location().clone(), | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn convert_fqn(fqn: &Fqn) -> String { | ||||||
|  |     let mut as_string = String::new(); | ||||||
|  |     let mut i = 0; | ||||||
|  |     let identifiers = fqn.identifiers(); | ||||||
|  |     while i < identifiers.len() { | ||||||
|  |         as_string.push_str(identifiers[i].name()); | ||||||
|  |         i += 1; | ||||||
|  |         if i < identifiers.len() { | ||||||
|  |             as_string.push_str("::"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     as_string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn make_path(file_name: &str, file_namespace: &Option<Fqn>) -> DvmPath { | ||||||
|  |     if let Some(namespace) = file_namespace { | ||||||
|  |         DvmPath::new(&convert_fqn(namespace), file_name) | ||||||
|  |     } else { | ||||||
|  |         DvmPath::new("", file_name) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn convert(file_name: &str, ast: CompilationUnit) -> DvmObjectFile { | ||||||
|  |     let path = make_path(file_name, ast.namespace()); | ||||||
|  |     let mut object_file = DvmObjectFile::new(path); | ||||||
|  | 
 | ||||||
|  |     let mut state = CompilationState { | ||||||
|  |         fqn_part_stack: Vec::new(), | ||||||
|  |     }; | ||||||
|  |     let context = CompilationContext { | ||||||
|  |         source_file_name: file_name.to_string(), | ||||||
|  |         symbol_table: SymbolTable {}, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     for declaration in ast.declarations() { | ||||||
|  |         match declaration { | ||||||
|  |             Declaration::Function(function_declaration) => { | ||||||
|  |                 let function = convert_static_function(&state, &context, function_declaration); | ||||||
|  |                 object_file.add_function(function); | ||||||
|  |             } | ||||||
|  |             _ => todo!("Unimplemented declaration {:?}", declaration), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     object_file | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/compile/symbol.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/compile/symbol.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | use crate::ast::Fqn; | ||||||
|  | use crate::compile::declared_type::DeclaredType; | ||||||
|  | 
 | ||||||
|  | pub struct Symbol { | ||||||
|  |     fqn: Fqn, | ||||||
|  |     declared_type: DeclaredType, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Symbol { | ||||||
|  |     pub fn fqn(&self) -> &Fqn { | ||||||
|  |         &self.fqn | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn declared_type(&self) -> &DeclaredType { | ||||||
|  |         &self.declared_type | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/compile/symbol_table.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/compile/symbol_table.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | use crate::ast::Fqn; | ||||||
|  | use crate::compile::symbol::Symbol; | ||||||
|  | 
 | ||||||
|  | pub struct SymbolTable {} | ||||||
|  | 
 | ||||||
|  | impl SymbolTable { | ||||||
|  |     pub fn resolve(&self, fqn: &Fqn) -> Symbol { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,7 +0,0 @@ | |||||||
| use crate::ast::CompilationUnit; |  | ||||||
| use crate::parser::{DeimosParser, Rule}; |  | ||||||
| use crate::module::DmModule; |  | ||||||
| 
 |  | ||||||
| pub fn compile(module: &mut DmModule, compilation_unit: CompilationUnit) { |  | ||||||
|     todo!() |  | ||||||
| } |  | ||||||
| @ -1,6 +1,6 @@ | |||||||
| #![allow(warnings)] | #![allow(warnings)] | ||||||
| pub mod ast; | pub mod ast; | ||||||
| pub mod compiler; | pub mod compile; | ||||||
| pub mod module; | pub mod module; | ||||||
| pub mod object_file; | pub mod object_file; | ||||||
| pub mod parser; | pub mod parser; | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ use std::rc::Rc; | |||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum Instruction { | pub enum Instruction { | ||||||
|     MoveImmediate { |     MoveImmediate { | ||||||
|         destination: Location, |         destination_register: usize, | ||||||
|         immediate: Immediate, |         immediate: Immediate, | ||||||
|     }, |     }, | ||||||
|     Copy { |     Copy { | ||||||
| @ -40,6 +40,12 @@ pub enum Instruction { | |||||||
|         function_name: Rc<String>, |         function_name: Rc<String>, | ||||||
|         source_code_location: SourceCodeLocation, |         source_code_location: SourceCodeLocation, | ||||||
|     }, |     }, | ||||||
|  |     SetReturnValue { | ||||||
|  |         source_register: usize, | ||||||
|  |     }, | ||||||
|  |     TakeReturnValue { | ||||||
|  |         destination_register: usize, | ||||||
|  |     }, | ||||||
|     Add { |     Add { | ||||||
|         left: u8, |         left: u8, | ||||||
|         right: u8, |         right: u8, | ||||||
| @ -104,6 +110,9 @@ pub enum Instruction { | |||||||
|         offset: isize, |         offset: isize, | ||||||
|     }, |     }, | ||||||
|     Return, |     Return, | ||||||
|  |     DumpState { | ||||||
|  |         message: String | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| @ -121,8 +130,11 @@ pub enum Immediate { | |||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum Location { | pub enum Location { | ||||||
|     Register(usize), |     Register(usize), | ||||||
|     Stack { |     StackFrameBase { | ||||||
|         offset: usize, |         offset: isize, | ||||||
|  |     }, | ||||||
|  |     StackTop { | ||||||
|  |         offset: isize, | ||||||
|     }, |     }, | ||||||
|     Field { |     Field { | ||||||
|         object_register: usize, |         object_register: usize, | ||||||
| @ -131,6 +143,6 @@ pub enum Location { | |||||||
|     Array { |     Array { | ||||||
|         array_register: usize, |         array_register: usize, | ||||||
|         index_register: usize, |         index_register: usize, | ||||||
|         offset: Option<isize>, |         offset: isize, | ||||||
|     }, |     }, | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										140
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							| @ -43,10 +43,12 @@ pub fn dump_state(state: &DvmState, message: &str) { | |||||||
|     for (i, register) in state.registers.iter().enumerate() { |     for (i, register) in state.registers.iter().enumerate() { | ||||||
|         println!("\tr{:x}: {:?}", i, register); |         println!("\tr{:x}: {:?}", i, register); | ||||||
|     } |     } | ||||||
|  |     println!("Return value register: {}", state.return_value_register); | ||||||
|     println!("Call stack:"); |     println!("Call stack:"); | ||||||
|     for call in state.call_stack.iter() { |     for call in state.call_stack.iter() { | ||||||
|         println!("\t{}", call); |         println!("\t{}", call); | ||||||
|     } |     } | ||||||
|  |     println!("Frame base index: {}", state.frame_base_index); | ||||||
|     println!("Stack:"); |     println!("Stack:"); | ||||||
|     for (i, value) in state.stack.iter().enumerate() { |     for (i, value) in state.stack.iter().enumerate() { | ||||||
|         println!("\t{}: {}", i, value); |         println!("\t{}: {}", i, value); | ||||||
| @ -63,10 +65,13 @@ macro_rules! dvm_panic { | |||||||
| 
 | 
 | ||||||
| pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext); | pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext); | ||||||
| 
 | 
 | ||||||
|  | #[derive(Clone)] | ||||||
| pub struct DvmState { | pub struct DvmState { | ||||||
|     call_stack: Vec<DvmCall>, |     call_stack: Vec<DvmCall>, | ||||||
|     current_instruction: Option<Instruction>, |     current_instruction: Option<Instruction>, | ||||||
|  |     frame_base_index: usize, | ||||||
|     registers: Vec<DvmValue>, |     registers: Vec<DvmValue>, | ||||||
|  |     return_value_register: DvmValue, | ||||||
|     stack: Vec<DvmValue>, |     stack: Vec<DvmValue>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -75,7 +80,9 @@ impl DvmState { | |||||||
|         DvmState { |         DvmState { | ||||||
|             call_stack: vec![], |             call_stack: vec![], | ||||||
|             current_instruction: None, |             current_instruction: None, | ||||||
|  |             frame_base_index: 0, | ||||||
|             registers: vec![DvmValue::Empty; 16], |             registers: vec![DvmValue::Empty; 16], | ||||||
|  |             return_value_register: DvmValue::Empty, | ||||||
|             stack: vec![], |             stack: vec![], | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -87,8 +94,14 @@ impl DvmState { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_stack_argument(&self, index: usize) -> DvmValue { |     pub fn get_stack_argument(&self, index: usize) -> DvmValue { | ||||||
|  |         let target_index = self | ||||||
|  |             .frame_base_index | ||||||
|  |             .checked_sub(1 + index) | ||||||
|  |             .unwrap_or_else(|| { | ||||||
|  |                 dvm_panic!(self, "Unsigned overflow: calculated negative target_index."); | ||||||
|  |             }); | ||||||
|         self.stack |         self.stack | ||||||
|             .get(self.stack.len() - 2 - index) |             .get(target_index) | ||||||
|             .unwrap_or_else(|| { |             .unwrap_or_else(|| { | ||||||
|                 dvm_panic!(self, "Stack underflow!"); |                 dvm_panic!(self, "Stack underflow!"); | ||||||
|             }) |             }) | ||||||
| @ -150,6 +163,7 @@ impl DvmContext { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Clone)] | ||||||
| pub struct DvmCall { | pub struct DvmCall { | ||||||
|     function_name: Rc<String>, |     function_name: Rc<String>, | ||||||
|     source_code_location: SourceCodeLocation, |     source_code_location: SourceCodeLocation, | ||||||
| @ -162,16 +176,16 @@ impl Display for DvmCall { | |||||||
|             self.function_name, |             self.function_name, | ||||||
|             self.source_code_location.source_file_name, |             self.source_code_location.source_file_name, | ||||||
|             self.source_code_location.line, |             self.source_code_location.line, | ||||||
|             self.source_code_location.char |             self.source_code_location.col | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn update_index(index: &mut usize, offset: isize) { | fn update_index(index: &mut usize, offset: isize) { | ||||||
|     if offset.is_negative() { |     if offset.is_negative() { | ||||||
|         *index -= offset.abs() as usize; |         *index -= offset.unsigned_abs(); | ||||||
|     } else { |     } else { | ||||||
|         *index += offset as usize; |         *index += offset.unsigned_abs(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -193,27 +207,40 @@ fn pop_call_frame(state: &mut DvmState) { | |||||||
| fn compute_index_with_offset( | fn compute_index_with_offset( | ||||||
|     registers: &Vec<DvmValue>, |     registers: &Vec<DvmValue>, | ||||||
|     index_register: usize, |     index_register: usize, | ||||||
|     offset: &Option<isize>, |     offset: isize, | ||||||
| ) -> usize { | ) -> usize { | ||||||
|     let index = registers[index_register].as_usize().expect(&format!( |     let index = registers[index_register].as_usize().expect(&format!( | ||||||
|         "Could not convert the value of index_register {} to usize; found {:?}", |         "Could not convert the value of index_register {} to usize; found {:?}", | ||||||
|         index_register, registers[index_register] |         index_register, registers[index_register] | ||||||
|     )); |     )); | ||||||
|     if let Some(o) = offset { |     if offset.is_negative() { | ||||||
|         if o.is_negative() { |         index - offset.unsigned_abs() | ||||||
|             index - o.unsigned_abs() |  | ||||||
|         } else { |  | ||||||
|             index + o.unsigned_abs() |  | ||||||
|         } |  | ||||||
|     } else { |     } else { | ||||||
|         index |         index + offset.unsigned_abs() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { | fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { | ||||||
|     match source { |     match source { | ||||||
|         Location::Register(register) => state.registers[*register].clone(), |         Location::Register(register) => state.registers[*register].clone(), | ||||||
|         Location::Stack { offset } => state.stack[*offset].clone(), |         Location::StackFrameBase { offset } => { | ||||||
|  |             let index = if offset.is_negative() { | ||||||
|  |                 state.frame_base_index - offset.unsigned_abs() | ||||||
|  |             } else { | ||||||
|  |                 state.frame_base_index + offset.unsigned_abs() | ||||||
|  |             }; | ||||||
|  |             state.stack[index].clone() | ||||||
|  |         } | ||||||
|  |         Location::StackTop { offset } => { | ||||||
|  |             if *offset >= 0 { | ||||||
|  |                 dvm_panic!( | ||||||
|  |                     state, | ||||||
|  |                     &format!("Offset {} out of bounds (must be negative)", offset) | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             let stack_length = state.stack.len(); | ||||||
|  |             state.stack[stack_length - offset.unsigned_abs()].clone() | ||||||
|  |         } | ||||||
|         Location::Field { |         Location::Field { | ||||||
|             object_register, |             object_register, | ||||||
|             field_name, |             field_name, | ||||||
| @ -228,7 +255,7 @@ fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { | |||||||
|             index_register, |             index_register, | ||||||
|             offset, |             offset, | ||||||
|         } => { |         } => { | ||||||
|             let index = compute_index_with_offset(&state.registers, *index_register, offset); |             let index = compute_index_with_offset(&state.registers, *index_register, *offset); | ||||||
|             state.registers[*array_register].map_array( |             state.registers[*array_register].map_array( | ||||||
|                 |a| a.borrow().read_element(index), |                 |a| a.borrow().read_element(index), | ||||||
|                 |v| { |                 |v| { | ||||||
| @ -244,8 +271,26 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm | |||||||
|         Location::Register(register) => { |         Location::Register(register) => { | ||||||
|             state.registers[*register] = value; |             state.registers[*register] = value; | ||||||
|         } |         } | ||||||
|         Location::Stack { offset } => { |         Location::StackFrameBase { offset } => { | ||||||
|             state.stack[*offset] = value; |             let index = if offset.is_negative() { | ||||||
|  |                 state.frame_base_index - offset.unsigned_abs() | ||||||
|  |             } else { | ||||||
|  |                 state.frame_base_index + offset.unsigned_abs() | ||||||
|  |             }; | ||||||
|  |             state.stack[index] = value; | ||||||
|  |         } | ||||||
|  |         Location::StackTop { offset } => { | ||||||
|  |             if *offset >= 0 { | ||||||
|  |                 dvm_panic!( | ||||||
|  |                     state, | ||||||
|  |                     &format!( | ||||||
|  |                         "Stack top offset {} is out of range (must be negative)", | ||||||
|  |                         offset | ||||||
|  |                     ) | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             let stack_length = state.stack.len(); | ||||||
|  |             state.stack[stack_length - offset.unsigned_abs()] = value; | ||||||
|         } |         } | ||||||
|         Location::Field { |         Location::Field { | ||||||
|             object_register, |             object_register, | ||||||
| @ -261,7 +306,7 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm | |||||||
|             index_register, |             index_register, | ||||||
|             offset, |             offset, | ||||||
|         } => { |         } => { | ||||||
|             let index = compute_index_with_offset(&state.registers, *index_register, offset); |             let index = compute_index_with_offset(&state.registers, *index_register, *offset); | ||||||
|             state.registers[*array_register] |             state.registers[*array_register] | ||||||
|                 .expect_array() |                 .expect_array() | ||||||
|                 .borrow_mut() |                 .borrow_mut() | ||||||
| @ -310,7 +355,9 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 { | pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 { | ||||||
|     let main_function = context.static_functions.get(&context.main_function) |     let main_function = context | ||||||
|  |         .static_functions | ||||||
|  |         .get(&context.main_function) | ||||||
|         .expect(&format!("No such main function: {}", context.main_function)); |         .expect(&format!("No such main function: {}", context.main_function)); | ||||||
|     push_call_frame( |     push_call_frame( | ||||||
|         Rc::new(main_function.fqn().to_string()), |         Rc::new(main_function.fqn().to_string()), | ||||||
| @ -319,23 +366,29 @@ pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 { | |||||||
|     ); |     ); | ||||||
|     run(main_function.instructions(), state, context); |     run(main_function.instructions(), state, context); | ||||||
|     pop_call_frame(state); |     pop_call_frame(state); | ||||||
|     state.pop_stack().expect_int_or_else(|v| { |     state.return_value_register.expect_int_or_else(|v| { | ||||||
|         dvm_panic!(state, &format!("Expected DvmValue::Int, but found {}", v)); |         dvm_panic!( | ||||||
|  |             state, | ||||||
|  |             &format!("Expected main to return DvmValue::Int, but found {}", v) | ||||||
|  |         ); | ||||||
|     }) |     }) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: find all possible unwraps/expects and wrap with call to dvm_panic
 | // TODO: find all possible unwraps/expects and wrap with call to dvm_panic
 | ||||||
| pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) { | pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) { | ||||||
|  |     state.frame_base_index = state.stack.len(); | ||||||
|     let mut index = 0; |     let mut index = 0; | ||||||
|     while index < instructions.len() { |     while index < instructions.len() { | ||||||
|         state.current_instruction = Some(instructions[index].clone()); |         let current_instruction = &instructions[index]; | ||||||
|  |         state.current_instruction = Some(current_instruction.clone()); | ||||||
|  |         index += 1; | ||||||
|         use Instruction::*; |         use Instruction::*; | ||||||
|         match &instructions[index] { |         match current_instruction { | ||||||
|             MoveImmediate { |             MoveImmediate { | ||||||
|                 destination, |                 destination_register, | ||||||
|                 immediate, |                 immediate, | ||||||
|             } => { |             } => { | ||||||
|                 write_to_destination(state, destination, immediate_to_value(immediate)); |                 state.registers[*destination_register] = immediate_to_value(immediate); | ||||||
|             } |             } | ||||||
|             Copy { |             Copy { | ||||||
|                 source, |                 source, | ||||||
| @ -392,9 +445,18 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | |||||||
|                     .clone(); |                     .clone(); | ||||||
| 
 | 
 | ||||||
|                 // Do call
 |                 // Do call
 | ||||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 |                 // before:
 | ||||||
|  |                 // - push call frame
 | ||||||
|  |                 // - save current frame base index
 | ||||||
|  |                 // - set current frame base index to current stack size
 | ||||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); |                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||||
|  |                 let saved_frame_base_index = state.frame_base_index; | ||||||
|  |                 state.frame_base_index = state.stack.len(); | ||||||
|  |                 // actual call
 | ||||||
|                 run(static_function.instructions(), state, context); |                 run(static_function.instructions(), state, context); | ||||||
|  | 
 | ||||||
|  |                 // reverse order
 | ||||||
|  |                 state.frame_base_index = saved_frame_base_index; | ||||||
|                 pop_call_frame(state); |                 pop_call_frame(state); | ||||||
|             } |             } | ||||||
|             InvokeObject { |             InvokeObject { | ||||||
| @ -426,12 +488,12 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | |||||||
|                 let instructions = function.instructions(); |                 let instructions = function.instructions(); | ||||||
| 
 | 
 | ||||||
|                 // Do call
 |                 // Do call
 | ||||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 |  | ||||||
|                 state.stack.push(object_value); // self object
 |  | ||||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); |                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||||
|  |                 let saved_frame_base_index = state.frame_base_index; | ||||||
|  |                 state.frame_base_index = state.stack.len(); | ||||||
|                 run(instructions, state, context); |                 run(instructions, state, context); | ||||||
|  |                 state.frame_base_index = saved_frame_base_index; | ||||||
|                 pop_call_frame(state); |                 pop_call_frame(state); | ||||||
|                 state.stack.pop(); // self object
 |  | ||||||
|             } |             } | ||||||
|             InvokeStaticPlatform { |             InvokeStaticPlatform { | ||||||
|                 function_name, |                 function_name, | ||||||
| @ -449,9 +511,11 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | |||||||
|                     }); |                     }); | ||||||
| 
 | 
 | ||||||
|                 // Do call
 |                 // Do call
 | ||||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 |  | ||||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); |                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||||
|  |                 let saved_frame_base_index = state.frame_base_index; | ||||||
|  |                 state.frame_base_index = state.stack.len(); | ||||||
|                 platform_function(state, context); |                 platform_function(state, context); | ||||||
|  |                 state.frame_base_index = saved_frame_base_index; | ||||||
|                 pop_call_frame(state); |                 pop_call_frame(state); | ||||||
|             } |             } | ||||||
|             InvokeObjectPlatform { |             InvokeObjectPlatform { | ||||||
| @ -483,12 +547,22 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // Do call
 |                 // Do call
 | ||||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 |  | ||||||
|                 state.stack.push(object_value); // self object
 |  | ||||||
|                 push_call_frame(function_name.clone(), source_code_location.clone(), state); |                 push_call_frame(function_name.clone(), source_code_location.clone(), state); | ||||||
|  |                 let saved_frame_base_index = state.frame_base_index; | ||||||
|  |                 state.frame_base_index = state.stack.len(); | ||||||
|                 object_platform_function(state, context); |                 object_platform_function(state, context); | ||||||
|  |                 state.frame_base_index = saved_frame_base_index; | ||||||
|                 pop_call_frame(state); |                 pop_call_frame(state); | ||||||
|                 state.stack.pop(); // self object
 |             } | ||||||
|  |             SetReturnValue { source_register } => { | ||||||
|  |                 state.return_value_register = | ||||||
|  |                     std::mem::take(&mut state.registers[*source_register]); | ||||||
|  |             } | ||||||
|  |             TakeReturnValue { | ||||||
|  |                 destination_register, | ||||||
|  |             } => { | ||||||
|  |                 state.registers[*destination_register] = | ||||||
|  |                     std::mem::take(&mut state.return_value_register); | ||||||
|             } |             } | ||||||
|             Add { .. } => {} |             Add { .. } => {} | ||||||
|             Subtract { .. } => {} |             Subtract { .. } => {} | ||||||
| @ -518,7 +592,7 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | |||||||
|             Return => { |             Return => { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|  |             DumpState { message } => dump_state(state, message), | ||||||
|         } |         } | ||||||
|         index += 1; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,16 @@ | |||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub struct SourceCodeLocation { | pub struct SourceCodeLocation { | ||||||
|     pub source_file_name: String, |     pub source_file_name: String, | ||||||
|     pub line: i64, |     pub line: usize, | ||||||
|     pub char: i64, |     pub col: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SourceCodeLocation { | ||||||
|  |     pub fn new(source_file_name: &str, line: usize, col: usize) -> Self { | ||||||
|  |         SourceCodeLocation { | ||||||
|  |             source_file_name: source_file_name.to_string(), | ||||||
|  |             line, | ||||||
|  |             col | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user