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