Compare commits
6 Commits
f0772fbf11
...
d09d945323
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d09d945323 | ||
|
|
34fae6ccca | ||
|
|
dd249dd5bd | ||
|
|
6b206605c1 | ||
|
|
b47dea9136 | ||
|
|
2b5be6ca49 |
@ -16,7 +16,7 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
|
||||
let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
|
||||
quote! {
|
||||
#type_ident::#rule_ident(#child_ident) => vec![
|
||||
#child_ident.as_node_ref()
|
||||
#child_ident
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -35,14 +35,14 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl AstNode for #type_ident {
|
||||
fn children(&self) -> Vec<AstNodeRef> {
|
||||
impl<'a> AstNode<'a> for #type_ident {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||
match self {
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef {
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||
AstNodeRef::#type_ident(&self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
|
||||
|
||||
pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", spec.build());
|
||||
quote! {
|
||||
impl AstNode for #type_ident {
|
||||
fn children(&self) -> Vec<AstNodeRef> {
|
||||
impl<'a> AstNode<'a> for #type_ident {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef {
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||
AstNodeRef::#type_ident(&self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,12 +5,12 @@ use quote::{format_ident, quote};
|
||||
pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", spec.build());
|
||||
quote! {
|
||||
impl AstNode for #type_ident {
|
||||
fn children(&self) -> Vec<AstNodeRef> {
|
||||
impl<'a> AstNode<'a> for #type_ident {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef {
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||
AstNodeRef::#type_ident(&self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,3 +71,34 @@ pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_ast_node_ref_unwrapper(build_spec: &BuildSpec) -> Option<TokenStream> {
|
||||
match build_spec {
|
||||
BuildSpec::Enum(enum_spec) => {
|
||||
Some(format_ident!("{}", enum_spec.build()))
|
||||
}
|
||||
BuildSpec::LeafEnum(leaf_enum) => {
|
||||
Some(format_ident!("{}", leaf_enum.build()))
|
||||
}
|
||||
BuildSpec::Struct(struct_spec) => {
|
||||
Some(format_ident!("{}", struct_spec.build()))
|
||||
}
|
||||
BuildSpec::LeafStruct(leaf_struct) => {
|
||||
Some(format_ident!("{}", leaf_struct.build()))
|
||||
}
|
||||
BuildSpec::Production(_) => None,
|
||||
BuildSpec::NodeProduction(_) => None,
|
||||
BuildSpec::PolymorphicType(polymorphic_type) => {
|
||||
Some(format_ident!("{}", polymorphic_type.name()))
|
||||
}
|
||||
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
|
||||
Some(format_ident!("{}", polymorphic_enum_loop.name()))
|
||||
}
|
||||
BuildSpec::PolymorphicPassThrough(_) => None
|
||||
}
|
||||
.map(|type_ident| {
|
||||
quote! {
|
||||
AstNodeRef::#type_ident(inner) => *inner
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -28,20 +28,20 @@ pub fn make_polymorphic_enum_loop_ast_node_impl(
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
children.push(self.#child_ident().as_node_ref())
|
||||
children.push(self.#child_ident() as &dyn AstNode);
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl AstNode for #type_ident {
|
||||
fn children(&self) -> Vec<AstNodeRef> {
|
||||
let mut children: Vec<AstNodeRef> = vec![];
|
||||
impl<'a> AstNode<'a> for #type_ident {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||
let mut children = vec![];
|
||||
#(#child_adders;)*
|
||||
children
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef {
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||
AstNodeRef::#type_ident(&self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,20 +11,20 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T
|
||||
let variant_ident = format_ident!("{}", variant.name());
|
||||
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
|
||||
quote! {
|
||||
#type_ident::#variant_ident(#child_ident) => vec![#child_ident.as_node_ref()]
|
||||
#type_ident::#variant_ident(#child_ident) => vec![#child_ident]
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl AstNode for #type_ident {
|
||||
fn children(&self) -> Vec<AstNodeRef> {
|
||||
impl<'a> AstNode<'a> for #type_ident {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||
match self {
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef {
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||
AstNodeRef::#type_ident(&self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,8 +13,8 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
|
||||
VecChildBuild::Node(_) => {
|
||||
let child_ident = format_ident!("{}", vec_child.name());
|
||||
let children_stream = quote! {
|
||||
for child in self.#child_ident().map(AstNode::as_node_ref) {
|
||||
children.push(child);
|
||||
for child in self.#child_ident() {
|
||||
children.push(child as &dyn AstNode);
|
||||
}
|
||||
};
|
||||
Some(children_stream)
|
||||
@ -26,12 +26,12 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
|
||||
if member_child.optional() {
|
||||
Some(quote! {
|
||||
if let Some(#child_ident) = self.#child_ident() {
|
||||
children.push(#child_ident.as_node_ref());
|
||||
children.push(#child_ident as &dyn AstNode);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
children.push(self.#child_ident().as_node_ref())
|
||||
children.push(self.#child_ident() as &dyn AstNode)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -44,14 +44,14 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl AstNode for #type_ident {
|
||||
fn children(&self) -> Vec<AstNodeRef> {
|
||||
let mut children: Vec<AstNodeRef> = vec![];
|
||||
impl<'a> AstNode<'a> for #type_ident {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||
let mut children = vec![];
|
||||
#(#child_adders;)*
|
||||
children
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef {
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||
AstNodeRef::#type_ident(&self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ mod spec;
|
||||
mod type_gen;
|
||||
mod walk;
|
||||
|
||||
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl};
|
||||
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl, make_ast_node_ref_unwrapper};
|
||||
use crate::build_fn::make_build_fn;
|
||||
use crate::deserialize::deserialize_yaml_spec;
|
||||
use crate::pretty_print::make_pretty_print_impl;
|
||||
@ -165,6 +165,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
||||
.map(Option::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let inner_unwrappers = build_specs
|
||||
.iter()
|
||||
.map(|build_spec| make_ast_node_ref_unwrapper(build_spec))
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let combined = quote! {
|
||||
use crate::ast::node::*;
|
||||
|
||||
@ -172,10 +179,18 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
||||
#(#ast_enum_members,)*
|
||||
}
|
||||
|
||||
pub trait AstNode {
|
||||
fn children(&self) -> Vec<AstNodeRef>;
|
||||
impl<'a> AstNodeRef<'a> {
|
||||
pub fn inner(&self) -> &dyn AstNode<'a> {
|
||||
match self {
|
||||
#(#inner_unwrappers,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_node_ref(&self) -> AstNodeRef;
|
||||
pub trait AstNode<'a> {
|
||||
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>>;
|
||||
|
||||
fn as_node_ref(&'a self) -> AstNodeRef<'a>;
|
||||
}
|
||||
|
||||
#(#impls)*
|
||||
|
||||
@ -1,59 +1,16 @@
|
||||
use crate::spec::BuildSpec;
|
||||
use convert_case::{Case, Casing};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use quote::quote;
|
||||
|
||||
pub fn make_walk_fn(specs: &[BuildSpec]) -> TokenStream {
|
||||
let child_match_arms = specs
|
||||
.iter()
|
||||
.map(|spec| match spec {
|
||||
BuildSpec::Enum(enum_spec) => Some((
|
||||
format_ident!("{}", enum_spec.build()),
|
||||
format_ident!("{}", enum_spec.build().to_case(Case::Snake)),
|
||||
)),
|
||||
BuildSpec::LeafEnum(leaf_enum) => Some((
|
||||
format_ident!("{}", leaf_enum.build()),
|
||||
format_ident!("{}", leaf_enum.build().to_case(Case::Snake)),
|
||||
)),
|
||||
BuildSpec::Struct(struct_spec) => Some((
|
||||
format_ident!("{}", struct_spec.build()),
|
||||
format_ident!("{}", struct_spec.build().to_case(Case::Snake)),
|
||||
)),
|
||||
BuildSpec::LeafStruct(leaf_struct) => Some((
|
||||
format_ident!("{}", leaf_struct.build()),
|
||||
format_ident!("{}", leaf_struct.build().to_case(Case::Snake)),
|
||||
)),
|
||||
BuildSpec::Production(_) => None,
|
||||
BuildSpec::NodeProduction(_) => None,
|
||||
BuildSpec::PolymorphicType(polymorphic_type) => Some((
|
||||
format_ident!("{}", polymorphic_type.name()),
|
||||
format_ident!("{}", polymorphic_type.name().to_case(Case::Snake)),
|
||||
)),
|
||||
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => Some((
|
||||
format_ident!("{}", polymorphic_enum_loop.name()),
|
||||
format_ident!("{}", polymorphic_enum_loop.name().to_case(Case::Snake)),
|
||||
)),
|
||||
BuildSpec::PolymorphicPassThrough(_) => None,
|
||||
})
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
.map(|(type_ident, inner_ident)| {
|
||||
quote! {
|
||||
#type_ident(#inner_ident) => walk_depth_first(#inner_ident, f)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
use crate::ast::node::*;
|
||||
use crate::ast::ast_node::*;
|
||||
|
||||
pub fn walk_depth_first(node: &impl AstNode, f: &mut impl FnMut(AstNodeRef)) {
|
||||
pub fn walk_depth_first<'a>(node: &'a dyn AstNode<'a>, f: &mut impl FnMut(AstNodeRef<'a>)) {
|
||||
use AstNodeRef::*;
|
||||
for child in node.children() {
|
||||
match child {
|
||||
#(#child_match_arms,)*
|
||||
}
|
||||
walk_depth_first(child, f);
|
||||
}
|
||||
f(node.as_node_ref());
|
||||
}
|
||||
|
||||
@ -7,8 +7,8 @@ fn getWorlds() -> List<World> = [
|
||||
]
|
||||
|
||||
fn findWorldByColor(worlds: List<World>, color: String) -> String
|
||||
worlds.find { it.color == color }
|
||||
.map { it.name }
|
||||
worlds.find { it -> it.color == color }
|
||||
.map { it -> it.name }
|
||||
.expect "No world has the given color ${color}"
|
||||
end
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
|
||||
|
||||
let diagnostics = analyze_names(compilation_units.as_mut_slice(), &files, &mut symbol_table);
|
||||
let diagnostics = analyze_names(&compilation_units, &files, &mut symbol_table);
|
||||
if diagnostics.is_empty() {
|
||||
println!("Name analysis complete.");
|
||||
println!("{}", symbol_table);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -19,42 +19,46 @@ The resolve phase has one main responsibility: resolve all references based on t
|
||||
`scope_id` property.
|
||||
*/
|
||||
|
||||
use crate::ast::node::{CompilationUnit, VariableUse};
|
||||
// use crate::name_analysis::resolve::resolve_compilation_unit;
|
||||
use crate::ast::ast_node::AstNode;
|
||||
use crate::ast::node::CompilationUnit;
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::gather::gather_compilation_unit;
|
||||
// use crate::name_analysis::resolve::resolve_compilation_unit;
|
||||
use crate::name_analysis::symbol_table::SymbolTable;
|
||||
use codespan_reporting::files::Files;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use crate::name_analysis::scope_table::ScopeTable;
|
||||
|
||||
pub(self) mod fqn_context;
|
||||
mod gather;
|
||||
// mod resolve;
|
||||
pub mod symbol;
|
||||
pub mod symbol_table;
|
||||
mod scope_table;
|
||||
|
||||
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
||||
compilation_units: &mut [Box<CompilationUnit>],
|
||||
compilation_units: &[Box<CompilationUnit>],
|
||||
files: &'a F,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Vec<DmDiagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
let mut scope_ids: HashMap<VariableUse, usize> = HashMap::new();
|
||||
let mut scope_table = ScopeTable::new();
|
||||
|
||||
// gather symbols
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
for compilation_unit in compilation_units {
|
||||
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
||||
gather_compilation_unit(
|
||||
compilation_unit,
|
||||
&file_name,
|
||||
symbol_table,
|
||||
&mut scope_ids,
|
||||
&mut scope_table,
|
||||
&mut diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
// resolve symbols
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
for compilation_unit in compilation_units {
|
||||
// resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
||||
}
|
||||
|
||||
|
||||
32
src/name_analysis/scope_table/mod.rs
Normal file
32
src/name_analysis/scope_table/mod.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use crate::ast::node::{FullyQualifiedName, VariableUse};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct ScopeTable<'a> {
|
||||
variable_use_scopes: HashMap<&'a VariableUse, usize>,
|
||||
fqn_scopes: HashMap<&'a FullyQualifiedName, usize>,
|
||||
}
|
||||
|
||||
impl<'a> ScopeTable<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
variable_use_scopes: HashMap::new(),
|
||||
fqn_scopes: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_variable_use_scope(&mut self, variable_use: &'a VariableUse, scope_id: usize) {
|
||||
self.variable_use_scopes.insert(variable_use, scope_id);
|
||||
}
|
||||
|
||||
pub fn insert_fqn_scope(&mut self, fqn: &'a FullyQualifiedName, scope_id: usize) {
|
||||
self.fqn_scopes.insert(fqn, scope_id);
|
||||
}
|
||||
|
||||
pub fn variable_use_scope(&self, variable_use: &'a VariableUse) -> Option<usize> {
|
||||
self.variable_use_scopes.get(&variable_use).copied()
|
||||
}
|
||||
|
||||
pub fn fqn_scope(&self, fqn: &'a FullyQualifiedName) -> Option<usize> {
|
||||
self.fqn_scopes.get(&fqn).copied()
|
||||
}
|
||||
}
|
||||
@ -45,8 +45,11 @@ impl SymbolTable {
|
||||
|
||||
pub fn push_scope(&mut self, debug_name: &str) {
|
||||
let id = self.scopes.len();
|
||||
self.scopes
|
||||
.push(Scope::new(Some(self.current_scope_id), id, debug_name.to_string()));
|
||||
self.scopes.push(Scope::new(
|
||||
Some(self.current_scope_id),
|
||||
id,
|
||||
debug_name.to_string(),
|
||||
));
|
||||
self.current_scope_id = id;
|
||||
}
|
||||
|
||||
@ -316,7 +319,61 @@ impl SymbolTable {
|
||||
Some(&self.scopes[parent_id])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
Err(NoDefinition)
|
||||
}
|
||||
|
||||
fn lookup_addressable_in_scope_by_identifier(
|
||||
scope: &Scope,
|
||||
identifier: &str,
|
||||
) -> Option<Symbol> {
|
||||
scope
|
||||
.variable_symbols()
|
||||
.get(identifier)
|
||||
.map(|variable_symbol| Symbol::Variable(variable_symbol.clone()))
|
||||
.or_else(|| {
|
||||
scope
|
||||
.parameter_symbols()
|
||||
.get(identifier)
|
||||
.map(|parameter_symbol| Symbol::Parameter(parameter_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
scope
|
||||
.class_member_symbols()
|
||||
.get(identifier)
|
||||
.map(|class_member_symbol| Symbol::ClassMember(class_member_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
scope
|
||||
.function_symbols()
|
||||
.get(identifier)
|
||||
.map(|function_symbol| Symbol::Function(function_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
scope
|
||||
.type_symbols()
|
||||
.get(identifier)
|
||||
.map(|type_symbol| Symbol::Type(type_symbol.clone()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lookup_addressable_by_identifier(
|
||||
&self,
|
||||
identifier: &str,
|
||||
scope_id: usize,
|
||||
) -> Result<Symbol, SymbolLookupError> {
|
||||
let mut scope_opt = Some(&self.scopes[scope_id]);
|
||||
while let Some(scope) = scope_opt {
|
||||
if let Some(symbol) = Self::lookup_addressable_in_scope_by_identifier(scope, identifier)
|
||||
{
|
||||
return Ok(symbol);
|
||||
}
|
||||
scope_opt = if let Some(parent_id) = scope.parent() {
|
||||
Some(&self.scopes[parent_id])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
Err(NoDefinition)
|
||||
}
|
||||
|
||||
@ -50,7 +50,6 @@ Identifier:
|
||||
- range:
|
||||
kind: range
|
||||
derive:
|
||||
- Clone
|
||||
- PartialEq
|
||||
- Eq
|
||||
- Hash
|
||||
@ -60,6 +59,10 @@ FullyQualifiedName:
|
||||
- identifiers:
|
||||
vec:
|
||||
rule: Identifier
|
||||
derive:
|
||||
- PartialEq
|
||||
- Eq
|
||||
- Hash
|
||||
|
||||
# Lists
|
||||
TypeUseList:
|
||||
@ -74,7 +77,7 @@ IdentifierList:
|
||||
- identifiers:
|
||||
vec:
|
||||
rule: Identifier
|
||||
ParenthesesOptionalTypeUseList:
|
||||
ParenthesesTypeUseList:
|
||||
struct:
|
||||
children:
|
||||
- type_use_list:
|
||||
@ -90,19 +93,29 @@ TypeUse:
|
||||
- TupleTypeUse
|
||||
- FunctionTypeUse
|
||||
PrimitiveType:
|
||||
leaf_enum:
|
||||
tree_enum:
|
||||
rules:
|
||||
- Byte
|
||||
- Short
|
||||
- Char
|
||||
- Int
|
||||
- Long
|
||||
- Double
|
||||
- Bool
|
||||
- String
|
||||
- Byte:
|
||||
child: false
|
||||
- Short:
|
||||
child: false
|
||||
- Char:
|
||||
child: false
|
||||
- Int:
|
||||
child: false
|
||||
- Long:
|
||||
child: false
|
||||
- Double:
|
||||
child: false
|
||||
- Bool:
|
||||
child: false
|
||||
- String:
|
||||
child: false
|
||||
- TypedArray
|
||||
- Any
|
||||
- Void
|
||||
- Any:
|
||||
child: false
|
||||
- Void:
|
||||
child: false
|
||||
TypedArray:
|
||||
struct:
|
||||
children:
|
||||
@ -160,7 +173,7 @@ GenericParameters:
|
||||
TupleArguments:
|
||||
struct:
|
||||
children:
|
||||
- parentheses_optional_type_use_list
|
||||
- parentheses_type_use_list
|
||||
|
||||
# Implements List
|
||||
ImplementsList:
|
||||
@ -656,7 +669,7 @@ IfClause:
|
||||
skip:
|
||||
rule: Then
|
||||
- statements:
|
||||
skip:
|
||||
vec:
|
||||
rule: Statement
|
||||
IfElseIf:
|
||||
struct:
|
||||
@ -704,7 +717,7 @@ ForStatement:
|
||||
- do_kw:
|
||||
skip:
|
||||
rule: Do
|
||||
- statement:
|
||||
- statements:
|
||||
vec:
|
||||
rule: Statement
|
||||
- end_kw:
|
||||
@ -731,7 +744,6 @@ VariableUse:
|
||||
children:
|
||||
- identifier
|
||||
derive:
|
||||
- Clone
|
||||
- PartialEq
|
||||
- Eq
|
||||
- Hash
|
||||
|
||||
@ -199,7 +199,7 @@ IdentifierList = {
|
||||
~ ( "," ~ Identifier )*
|
||||
}
|
||||
|
||||
ParenthesesOptionalTypeUseList = {
|
||||
ParenthesesTypeUseList = {
|
||||
"("
|
||||
~ TypeUseList?
|
||||
~ ")"
|
||||
@ -272,7 +272,7 @@ GenericParameters = {
|
||||
// Tuple Arguments
|
||||
|
||||
TupleArguments = {
|
||||
ParenthesesOptionalTypeUseList
|
||||
ParenthesesTypeUseList
|
||||
}
|
||||
|
||||
// Implements list
|
||||
|
||||
205
src/vm/mem/mod.rs
Normal file
205
src/vm/mem/mod.rs
Normal file
@ -0,0 +1,205 @@
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Mul;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Gc<T> {
|
||||
inner: *mut GcInner,
|
||||
data: *const T,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GcInner {
|
||||
color: GcColor,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl GcInner {
|
||||
pub fn new(size: usize) -> Self {
|
||||
Self {
|
||||
color: GcColor::White,
|
||||
size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum GcColor {
|
||||
White,
|
||||
Black,
|
||||
}
|
||||
|
||||
impl<T> Gc<T> {
|
||||
pub fn new(data: T) -> Self {
|
||||
let inner = Box::into_raw(Box::new(GcInner::new(size_of::<T>())));
|
||||
let boxed_data = Box::into_raw(Box::new(data)) as *const T;
|
||||
Self {
|
||||
inner,
|
||||
data: boxed_data,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_color(&mut self, color: GcColor) {
|
||||
unsafe {
|
||||
(*self.inner).color = color;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color(&self) -> GcColor {
|
||||
unsafe { (*self.inner).color }
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
unsafe { (*self.inner).size }
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &T {
|
||||
unsafe { &*self.data }
|
||||
}
|
||||
|
||||
pub fn dealloc(&mut self) {
|
||||
unsafe {
|
||||
drop(Box::from_raw(self.inner));
|
||||
drop(Box::from_raw(self.data as *mut T));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Gc<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner,
|
||||
data: self.data,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum DvmValue {
|
||||
Primitive(usize),
|
||||
Object(Gc<RefCell<DvmObject>>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DvmObject {
|
||||
fields: Vec<DvmValue>,
|
||||
}
|
||||
|
||||
impl DvmObject {
|
||||
pub fn new() -> Self {
|
||||
Self { fields: vec![] }
|
||||
}
|
||||
|
||||
pub fn fields(&self) -> &[DvmValue] {
|
||||
&self.fields
|
||||
}
|
||||
|
||||
pub fn fields_mut(&mut self) -> &mut Vec<DvmValue> {
|
||||
&mut self.fields
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_garbage(
|
||||
next_gc: &mut usize,
|
||||
current_size: &mut usize,
|
||||
stack: &Vec<DvmValue>,
|
||||
gcs: &mut Vec<Gc<RefCell<DvmObject>>>,
|
||||
) {
|
||||
let mut gray_stack: Vec<Gc<RefCell<DvmObject>>> = vec![];
|
||||
|
||||
for stack_value in stack {
|
||||
match stack_value {
|
||||
DvmValue::Object(gc) => {
|
||||
if gc.color() == GcColor::White {
|
||||
gray_stack.push(gc.clone());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(mut current) = gray_stack.pop() {
|
||||
for field in current.data().borrow().fields() {
|
||||
match field {
|
||||
DvmValue::Object(object) => {
|
||||
gray_stack.push(object.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
current.set_color(GcColor::Black);
|
||||
}
|
||||
|
||||
let mut collected_size: usize = 0;
|
||||
|
||||
for i in (0..gcs.len()).rev() {
|
||||
if gcs[i].color() == GcColor::White {
|
||||
let mut gc = gcs.remove(i);
|
||||
let size = gc.size();
|
||||
*current_size -= size;
|
||||
collected_size += size;
|
||||
gc.dealloc();
|
||||
} else {
|
||||
gcs[i].set_color(GcColor::White);
|
||||
}
|
||||
}
|
||||
|
||||
*next_gc = std::cmp::max(1024 * 1024, current_size.mul(2));
|
||||
println!(
|
||||
"collected_size: {}, current_size: {}, next_gc: {}",
|
||||
collected_size, current_size, next_gc
|
||||
);
|
||||
}
|
||||
|
||||
fn maybe_collect_garbage(
|
||||
next_gc: &mut usize,
|
||||
current_size: &mut usize,
|
||||
stack: &Vec<DvmValue>,
|
||||
gcs: &mut Vec<Gc<RefCell<DvmObject>>>,
|
||||
) {
|
||||
if current_size > next_gc {
|
||||
collect_garbage(next_gc, current_size, stack, gcs);
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_dvm_object(
|
||||
next_gc: &mut usize,
|
||||
current_size: &mut usize,
|
||||
stack: &Vec<DvmValue>,
|
||||
gcs: &mut Vec<Gc<RefCell<DvmObject>>>,
|
||||
) -> Gc<RefCell<DvmObject>> {
|
||||
maybe_collect_garbage(next_gc, current_size, stack, gcs);
|
||||
let mut object = DvmObject::new();
|
||||
object.fields_mut().push(DvmValue::Nil);
|
||||
let gc = Gc::new(RefCell::new(object));
|
||||
*current_size += gc.size();
|
||||
gcs.push(gc.clone());
|
||||
gc
|
||||
}
|
||||
|
||||
fn set_field(obj: &mut Gc<RefCell<DvmObject>>, field_index: usize, value: DvmValue) {
|
||||
let mut binding = obj.data().borrow_mut();
|
||||
binding.fields_mut()[field_index] = value;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vm::mem::{alloc_dvm_object, collect_garbage, DvmObject, DvmValue, Gc};
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut stack: Vec<DvmValue> = vec![];
|
||||
let mut heap: Vec<Gc<RefCell<DvmObject>>> = vec![];
|
||||
let mut next_gc: usize = 1024 * 1024;
|
||||
let mut current_size: usize = 0;
|
||||
for i in 0..100_000_000 {
|
||||
let mut o = alloc_dvm_object(&mut next_gc, &mut current_size, &stack, &mut heap);
|
||||
}
|
||||
collect_garbage(&mut next_gc, &mut current_size, &stack, &mut heap);
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ pub mod implementation;
|
||||
pub mod instruction;
|
||||
pub mod interface;
|
||||
pub mod lib;
|
||||
mod mem;
|
||||
pub mod method;
|
||||
pub mod object;
|
||||
pub mod op_codes;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user