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 pest::{iterators::Pair, Parser}; | ||||
| use crate::vm::source_code_location::SourceCodeLocation; | ||||
| use pest::Parser; | ||||
| 
 | ||||
| pub mod build; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct CompilationUnit { | ||||
| @ -7,11 +9,39 @@ pub struct CompilationUnit { | ||||
|     declarations: Vec<Declaration>, | ||||
| } | ||||
| 
 | ||||
| impl CompilationUnit { | ||||
|     pub fn namespace(&self) -> &Option<Fqn> { | ||||
|         &self.namespace | ||||
|     } | ||||
| 
 | ||||
|     pub fn declarations(&self) -> &Vec<Declaration> { | ||||
|         &self.declarations | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct Fqn { | ||||
|     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)] | ||||
| pub enum Declaration { | ||||
|     Interface { | ||||
| @ -33,18 +63,36 @@ pub enum Declaration { | ||||
|         is_public: bool, | ||||
|         declarations: Vec<Declaration>, | ||||
|     }, | ||||
|     Function { | ||||
|         identifier: Identifier, | ||||
|         is_extern: bool, | ||||
|         is_public: bool, | ||||
|         parameters: Vec<Parameter>, | ||||
|         declared_type: Option<TypeUse>, | ||||
|         statement: Statement, | ||||
|     }, | ||||
|     Function(FunctionDeclaration), | ||||
|     Prop(Prop), | ||||
|     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)] | ||||
| pub struct TypeDeclaration { | ||||
|     generics: Vec<GenericParameter>, | ||||
| @ -66,11 +114,17 @@ impl TypeDeclaration { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Identifier { | ||||
|     name: String, | ||||
| } | ||||
| 
 | ||||
| impl Identifier { | ||||
|     pub fn name(&self) -> &str { | ||||
|         &self.name | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct GenericParameter { | ||||
|     identifier: Identifier, | ||||
| @ -118,11 +172,71 @@ pub struct Field { | ||||
|     r#type: TypeUse, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct BlockStatement { | ||||
|     statements: Vec<Statement>, | ||||
| } | ||||
| 
 | ||||
| impl BlockStatement { | ||||
|     pub fn statements(&self) -> &Vec<Statement> { | ||||
|         &self.statements | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum Statement { | ||||
|     BlockStatement { statements: Vec<Statement> }, | ||||
|     CallStatement, | ||||
|     AssignmentStatement, | ||||
|     CallStatement(CallExpression), | ||||
|     AssignStatement(AssignExpression), | ||||
| } | ||||
| 
 | ||||
| #[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)] | ||||
| @ -130,409 +244,3 @@ pub struct Parameter { | ||||
|     identifier: Identifier, | ||||
|     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 deimos::ast::build_ast; | ||||
| use deimos::ast::build::build_ast; | ||||
| 
 | ||||
| pub fn dump_ast(path: &PathBuf) { | ||||
|     let src = std::fs::read_to_string(path) | ||||
|         .expect(&format!("Could not read {:?}", path)); | ||||
|     let src = std::fs::read_to_string(path).expect(&format!("Could not read {:?}", path)); | ||||
|     let ast = build_ast(&src); | ||||
|     println!("{:?}", ast); | ||||
| } | ||||
|  | ||||
| @ -16,9 +16,7 @@ struct Cli { | ||||
| #[derive(Debug, Subcommand)] | ||||
| enum Commands { | ||||
|     #[command(arg_required_else_help = true)] | ||||
|     AstDump { | ||||
|         paths: Vec<PathBuf> | ||||
|     } | ||||
|     AstDump { paths: Vec<PathBuf> }, | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
| @ -31,4 +29,3 @@ fn main() { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| use deimos::object_file::{DvmObjectFile, DvmPath}; | ||||
| use deimos::vm::constant::DvmConstant; | ||||
| 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::source_code_location::SourceCodeLocation; | ||||
| use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState}; | ||||
| @ -16,37 +16,81 @@ fn main() { | ||||
|     //
 | ||||
|     // fn main() {
 | ||||
|     //     println "Hello, World!"
 | ||||
|     //     println foo()
 | ||||
|     // }
 | ||||
|     //
 | ||||
|     // fn foo() = 42
 | ||||
|     let mut greeter_object_file = DvmObjectFile::new(DvmPath::new("greeter", "greeter.dmo")); | ||||
|     
 | ||||
| 
 | ||||
|     use Instruction::*; | ||||
|     let main_instructions = vec![ | ||||
|         Instruction::MoveImmediate { | ||||
|             destination: Location::Register(0), | ||||
|         MoveImmediate { | ||||
|             destination_register: 0, | ||||
|             immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))), | ||||
|         }, | ||||
|         Instruction::Push { source_register: 0 }, | ||||
|         Instruction::InvokeStaticPlatform { | ||||
|         // prepare for call to println
 | ||||
|         Push { source_register: 0 }, // save r0
 | ||||
|         Push { source_register: 0 }, // arg0
 | ||||
|         // call
 | ||||
|         InvokeStaticPlatform { | ||||
|             function_name: Rc::new(String::from("std::core::println")), | ||||
|             source_code_location: SourceCodeLocation { | ||||
|                 source_file_name: String::from("greeter.dm"), | ||||
|                 line: 4, | ||||
|                 char: 5, | ||||
|                 col: 5, | ||||
|             }, | ||||
|         }, | ||||
|         Instruction::Pop { | ||||
|             // println return value
 | ||||
|         // unwind from call
 | ||||
|         Pop { | ||||
|             destination_register: None, | ||||
|         }, // arg0
 | ||||
|         Pop { | ||||
|             destination_register: Some(0), // restore r0
 | ||||
|         }, | ||||
|         Instruction::Pop { | ||||
|             // arg0 to println
 | ||||
|         // prepare for call to foo
 | ||||
|         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, | ||||
|         }, // arg0
 | ||||
|         Pop { | ||||
|             destination_register: Some(0), // restore r0
 | ||||
|         }, | ||||
|         Instruction::MoveImmediate { | ||||
|             destination: Location::Register(1), | ||||
|         Pop { | ||||
|             destination_register: Some(1), // restore r1
 | ||||
|         }, | ||||
|         // return 0
 | ||||
|         MoveImmediate { | ||||
|             destination_register: 2, | ||||
|             immediate: Immediate::Int(0), | ||||
|         }, | ||||
|         Instruction::Push { source_register: 1 }, | ||||
|         Instruction::Return, | ||||
|         SetReturnValue { source_register: 2 }, | ||||
|         Return, // explicit, not needed
 | ||||
|     ]; | ||||
| 
 | ||||
|     let main_function = DvmFunction::new( | ||||
| @ -55,19 +99,37 @@ fn main() { | ||||
|         SourceCodeLocation { | ||||
|             source_file_name: String::from("greeter.dm"), | ||||
|             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(foo_function); | ||||
| 
 | ||||
|     let mut state = DvmState::new(); | ||||
|     let mut context = DvmContext::new("greeter::main"); | ||||
|     context.add_platform_functions(get_std_lib_platform_functions()); | ||||
|     greeter_object_file.load_to_context(&mut context, &|path| { | ||||
|         todo!() | ||||
|     }); | ||||
|     
 | ||||
|     greeter_object_file.load_to_context(&mut context, &|path| todo!()); | ||||
| 
 | ||||
|     let exit_code = run_main_function(&mut state, &context); | ||||
| 
 | ||||
|     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)] | ||||
| pub mod ast; | ||||
| pub mod compiler; | ||||
| pub mod compile; | ||||
| pub mod module; | ||||
| pub mod object_file; | ||||
| pub mod parser; | ||||
|  | ||||
| @ -5,7 +5,7 @@ use std::rc::Rc; | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Instruction { | ||||
|     MoveImmediate { | ||||
|         destination: Location, | ||||
|         destination_register: usize, | ||||
|         immediate: Immediate, | ||||
|     }, | ||||
|     Copy { | ||||
| @ -40,6 +40,12 @@ pub enum Instruction { | ||||
|         function_name: Rc<String>, | ||||
|         source_code_location: SourceCodeLocation, | ||||
|     }, | ||||
|     SetReturnValue { | ||||
|         source_register: usize, | ||||
|     }, | ||||
|     TakeReturnValue { | ||||
|         destination_register: usize, | ||||
|     }, | ||||
|     Add { | ||||
|         left: u8, | ||||
|         right: u8, | ||||
| @ -104,6 +110,9 @@ pub enum Instruction { | ||||
|         offset: isize, | ||||
|     }, | ||||
|     Return, | ||||
|     DumpState { | ||||
|         message: String | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| @ -121,8 +130,11 @@ pub enum Immediate { | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Location { | ||||
|     Register(usize), | ||||
|     Stack { | ||||
|         offset: usize, | ||||
|     StackFrameBase { | ||||
|         offset: isize, | ||||
|     }, | ||||
|     StackTop { | ||||
|         offset: isize, | ||||
|     }, | ||||
|     Field { | ||||
|         object_register: usize, | ||||
| @ -131,6 +143,6 @@ pub enum Location { | ||||
|     Array { | ||||
|         array_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() { | ||||
|         println!("\tr{:x}: {:?}", i, register); | ||||
|     } | ||||
|     println!("Return value register: {}", state.return_value_register); | ||||
|     println!("Call stack:"); | ||||
|     for call in state.call_stack.iter() { | ||||
|         println!("\t{}", call); | ||||
|     } | ||||
|     println!("Frame base index: {}", state.frame_base_index); | ||||
|     println!("Stack:"); | ||||
|     for (i, value) in state.stack.iter().enumerate() { | ||||
|         println!("\t{}: {}", i, value); | ||||
| @ -63,10 +65,13 @@ macro_rules! dvm_panic { | ||||
| 
 | ||||
| pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext); | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct DvmState { | ||||
|     call_stack: Vec<DvmCall>, | ||||
|     current_instruction: Option<Instruction>, | ||||
|     frame_base_index: usize, | ||||
|     registers: Vec<DvmValue>, | ||||
|     return_value_register: DvmValue, | ||||
|     stack: Vec<DvmValue>, | ||||
| } | ||||
| 
 | ||||
| @ -75,7 +80,9 @@ impl DvmState { | ||||
|         DvmState { | ||||
|             call_stack: vec![], | ||||
|             current_instruction: None, | ||||
|             frame_base_index: 0, | ||||
|             registers: vec![DvmValue::Empty; 16], | ||||
|             return_value_register: DvmValue::Empty, | ||||
|             stack: vec![], | ||||
|         } | ||||
|     } | ||||
| @ -87,8 +94,14 @@ impl DvmState { | ||||
|     } | ||||
| 
 | ||||
|     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 | ||||
|             .get(self.stack.len() - 2 - index) | ||||
|             .get(target_index) | ||||
|             .unwrap_or_else(|| { | ||||
|                 dvm_panic!(self, "Stack underflow!"); | ||||
|             }) | ||||
| @ -150,6 +163,7 @@ impl DvmContext { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct DvmCall { | ||||
|     function_name: Rc<String>, | ||||
|     source_code_location: SourceCodeLocation, | ||||
| @ -162,16 +176,16 @@ impl Display for DvmCall { | ||||
|             self.function_name, | ||||
|             self.source_code_location.source_file_name, | ||||
|             self.source_code_location.line, | ||||
|             self.source_code_location.char | ||||
|             self.source_code_location.col | ||||
|         )) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn update_index(index: &mut usize, offset: isize) { | ||||
|     if offset.is_negative() { | ||||
|         *index -= offset.abs() as usize; | ||||
|         *index -= offset.unsigned_abs(); | ||||
|     } 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( | ||||
|     registers: &Vec<DvmValue>, | ||||
|     index_register: usize, | ||||
|     offset: &Option<isize>, | ||||
|     offset: isize, | ||||
| ) -> usize { | ||||
|     let index = registers[index_register].as_usize().expect(&format!( | ||||
|         "Could not convert the value of index_register {} to usize; found {:?}", | ||||
|         index_register, registers[index_register] | ||||
|     )); | ||||
|     if let Some(o) = offset { | ||||
|         if o.is_negative() { | ||||
|             index - o.unsigned_abs() | ||||
|         } else { | ||||
|             index + o.unsigned_abs() | ||||
|         } | ||||
|     if offset.is_negative() { | ||||
|         index - offset.unsigned_abs() | ||||
|     } else { | ||||
|         index | ||||
|         index + offset.unsigned_abs() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { | ||||
|     match source { | ||||
|         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 { | ||||
|             object_register, | ||||
|             field_name, | ||||
| @ -228,7 +255,7 @@ fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { | ||||
|             index_register, | ||||
|             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( | ||||
|                 |a| a.borrow().read_element(index), | ||||
|                 |v| { | ||||
| @ -244,8 +271,26 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm | ||||
|         Location::Register(register) => { | ||||
|             state.registers[*register] = value; | ||||
|         } | ||||
|         Location::Stack { offset } => { | ||||
|             state.stack[*offset] = value; | ||||
|         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] = 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 { | ||||
|             object_register, | ||||
| @ -261,7 +306,7 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm | ||||
|             index_register, | ||||
|             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] | ||||
|                 .expect_array() | ||||
|                 .borrow_mut() | ||||
| @ -310,7 +355,9 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue { | ||||
| } | ||||
| 
 | ||||
| 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)); | ||||
|     push_call_frame( | ||||
|         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); | ||||
|     pop_call_frame(state); | ||||
|     state.pop_stack().expect_int_or_else(|v| { | ||||
|         dvm_panic!(state, &format!("Expected DvmValue::Int, but found {}", v)); | ||||
|     state.return_value_register.expect_int_or_else(|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
 | ||||
| pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) { | ||||
|     state.frame_base_index = state.stack.len(); | ||||
|     let mut index = 0; | ||||
|     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::*; | ||||
|         match &instructions[index] { | ||||
|         match current_instruction { | ||||
|             MoveImmediate { | ||||
|                 destination, | ||||
|                 destination_register, | ||||
|                 immediate, | ||||
|             } => { | ||||
|                 write_to_destination(state, destination, immediate_to_value(immediate)); | ||||
|                 state.registers[*destination_register] = immediate_to_value(immediate); | ||||
|             } | ||||
|             Copy { | ||||
|                 source, | ||||
| @ -392,9 +445,18 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | ||||
|                     .clone(); | ||||
| 
 | ||||
|                 // 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); | ||||
|                 let saved_frame_base_index = state.frame_base_index; | ||||
|                 state.frame_base_index = state.stack.len(); | ||||
|                 // actual call
 | ||||
|                 run(static_function.instructions(), state, context); | ||||
| 
 | ||||
|                 // reverse order
 | ||||
|                 state.frame_base_index = saved_frame_base_index; | ||||
|                 pop_call_frame(state); | ||||
|             } | ||||
|             InvokeObject { | ||||
| @ -426,12 +488,12 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | ||||
|                 let instructions = function.instructions(); | ||||
| 
 | ||||
|                 // 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); | ||||
|                 let saved_frame_base_index = state.frame_base_index; | ||||
|                 state.frame_base_index = state.stack.len(); | ||||
|                 run(instructions, state, context); | ||||
|                 state.frame_base_index = saved_frame_base_index; | ||||
|                 pop_call_frame(state); | ||||
|                 state.stack.pop(); // self object
 | ||||
|             } | ||||
|             InvokeStaticPlatform { | ||||
|                 function_name, | ||||
| @ -449,9 +511,11 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | ||||
|                     }); | ||||
| 
 | ||||
|                 // Do call
 | ||||
|                 state.stack.push(DvmValue::Empty); // space for return value
 | ||||
|                 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); | ||||
|                 state.frame_base_index = saved_frame_base_index; | ||||
|                 pop_call_frame(state); | ||||
|             } | ||||
|             InvokeObjectPlatform { | ||||
| @ -483,12 +547,22 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | ||||
|                 } | ||||
| 
 | ||||
|                 // 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); | ||||
|                 let saved_frame_base_index = state.frame_base_index; | ||||
|                 state.frame_base_index = state.stack.len(); | ||||
|                 object_platform_function(state, context); | ||||
|                 state.frame_base_index = saved_frame_base_index; | ||||
|                 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 { .. } => {} | ||||
|             Subtract { .. } => {} | ||||
| @ -518,7 +592,7 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont | ||||
|             Return => { | ||||
|                 break; | ||||
|             } | ||||
|             DumpState { message } => dump_state(state, message), | ||||
|         } | ||||
|         index += 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,16 @@ | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct SourceCodeLocation { | ||||
|     pub source_file_name: String, | ||||
|     pub line: i64, | ||||
|     pub char: i64, | ||||
|     pub line: usize, | ||||
|     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