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));
|
let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
|
||||||
quote! {
|
quote! {
|
||||||
#type_ident::#rule_ident(#child_ident) => vec![
|
#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<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl AstNode for #type_ident {
|
impl<'a> AstNode<'a> for #type_ident {
|
||||||
fn children(&self) -> Vec<AstNodeRef> {
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||||
match self {
|
match self {
|
||||||
#(#match_arms,)*
|
#(#match_arms,)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node_ref(&self) -> AstNodeRef {
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||||
AstNodeRef::#type_ident(&self)
|
AstNodeRef::#type_ident(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
|
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
|
|
||||||
|
|
||||||
pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
|
pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
|
||||||
let type_ident = format_ident!("{}", spec.build());
|
let type_ident = format_ident!("{}", spec.build());
|
||||||
quote! {
|
quote! {
|
||||||
impl AstNode for #type_ident {
|
impl<'a> AstNode<'a> for #type_ident {
|
||||||
fn children(&self) -> Vec<AstNodeRef> {
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node_ref(&self) -> AstNodeRef {
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||||
AstNodeRef::#type_ident(&self)
|
AstNodeRef::#type_ident(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,12 @@ use quote::{format_ident, quote};
|
|||||||
pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream {
|
pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream {
|
||||||
let type_ident = format_ident!("{}", spec.build());
|
let type_ident = format_ident!("{}", spec.build());
|
||||||
quote! {
|
quote! {
|
||||||
impl AstNode for #type_ident {
|
impl<'a> AstNode<'a> for #type_ident {
|
||||||
fn children(&self) -> Vec<AstNodeRef> {
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node_ref(&self) -> AstNodeRef {
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||||
AstNodeRef::#type_ident(&self)
|
AstNodeRef::#type_ident(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,4 +70,35 @@ pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> {
|
|||||||
#type_ident(&'a #type_ident)
|
#type_ident(&'a #type_ident)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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! {
|
quote! {
|
||||||
children.push(self.#child_ident().as_node_ref())
|
children.push(self.#child_ident() as &dyn AstNode);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl AstNode for #type_ident {
|
impl<'a> AstNode<'a> for #type_ident {
|
||||||
fn children(&self) -> Vec<AstNodeRef> {
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||||
let mut children: Vec<AstNodeRef> = vec![];
|
let mut children = vec![];
|
||||||
#(#child_adders;)*
|
#(#child_adders;)*
|
||||||
children
|
children
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node_ref(&self) -> AstNodeRef {
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||||
AstNodeRef::#type_ident(&self)
|
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 variant_ident = format_ident!("{}", variant.name());
|
||||||
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
|
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
|
||||||
quote! {
|
quote! {
|
||||||
#type_ident::#variant_ident(#child_ident) => vec![#child_ident.as_node_ref()]
|
#type_ident::#variant_ident(#child_ident) => vec![#child_ident]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl AstNode for #type_ident {
|
impl<'a> AstNode<'a> for #type_ident {
|
||||||
fn children(&self) -> Vec<AstNodeRef> {
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||||
match self {
|
match self {
|
||||||
#(#match_arms,)*
|
#(#match_arms,)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node_ref(&self) -> AstNodeRef {
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||||
AstNodeRef::#type_ident(&self)
|
AstNodeRef::#type_ident(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,8 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
|
|||||||
VecChildBuild::Node(_) => {
|
VecChildBuild::Node(_) => {
|
||||||
let child_ident = format_ident!("{}", vec_child.name());
|
let child_ident = format_ident!("{}", vec_child.name());
|
||||||
let children_stream = quote! {
|
let children_stream = quote! {
|
||||||
for child in self.#child_ident().map(AstNode::as_node_ref) {
|
for child in self.#child_ident() {
|
||||||
children.push(child);
|
children.push(child as &dyn AstNode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(children_stream)
|
Some(children_stream)
|
||||||
@ -26,12 +26,12 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
|
|||||||
if member_child.optional() {
|
if member_child.optional() {
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
if let Some(#child_ident) = self.#child_ident() {
|
if let Some(#child_ident) = self.#child_ident() {
|
||||||
children.push(#child_ident.as_node_ref());
|
children.push(#child_ident as &dyn AstNode);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Some(quote! {
|
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<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl AstNode for #type_ident {
|
impl<'a> AstNode<'a> for #type_ident {
|
||||||
fn children(&self) -> Vec<AstNodeRef> {
|
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
|
||||||
let mut children: Vec<AstNodeRef> = vec![];
|
let mut children = vec![];
|
||||||
#(#child_adders;)*
|
#(#child_adders;)*
|
||||||
children
|
children
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node_ref(&self) -> AstNodeRef {
|
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
|
||||||
AstNodeRef::#type_ident(&self)
|
AstNodeRef::#type_ident(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ mod spec;
|
|||||||
mod type_gen;
|
mod type_gen;
|
||||||
mod walk;
|
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::build_fn::make_build_fn;
|
||||||
use crate::deserialize::deserialize_yaml_spec;
|
use crate::deserialize::deserialize_yaml_spec;
|
||||||
use crate::pretty_print::make_pretty_print_impl;
|
use crate::pretty_print::make_pretty_print_impl;
|
||||||
@ -165,6 +165,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|||||||
.map(Option::unwrap)
|
.map(Option::unwrap)
|
||||||
.collect::<Vec<_>>();
|
.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! {
|
let combined = quote! {
|
||||||
use crate::ast::node::*;
|
use crate::ast::node::*;
|
||||||
|
|
||||||
@ -172,10 +179,18 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|||||||
#(#ast_enum_members,)*
|
#(#ast_enum_members,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AstNode {
|
impl<'a> AstNodeRef<'a> {
|
||||||
fn children(&self) -> Vec<AstNodeRef>;
|
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)*
|
#(#impls)*
|
||||||
|
|||||||
@ -1,59 +1,16 @@
|
|||||||
use crate::spec::BuildSpec;
|
use crate::spec::BuildSpec;
|
||||||
use convert_case::{Case, Casing};
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::quote;
|
||||||
|
|
||||||
pub fn make_walk_fn(specs: &[BuildSpec]) -> TokenStream {
|
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! {
|
quote! {
|
||||||
use crate::ast::node::*;
|
use crate::ast::node::*;
|
||||||
use crate::ast::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::*;
|
use AstNodeRef::*;
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
match child {
|
walk_depth_first(child, f);
|
||||||
#(#child_match_arms,)*
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
f(node.as_node_ref());
|
f(node.as_node_ref());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,8 @@ fn getWorlds() -> List<World> = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
fn findWorldByColor(worlds: List<World>, color: String) -> String
|
fn findWorldByColor(worlds: List<World>, color: String) -> String
|
||||||
worlds.find { it.color == color }
|
worlds.find { it -> it.color == color }
|
||||||
.map { it.name }
|
.map { it -> it.name }
|
||||||
.expect "No world has the given color ${color}"
|
.expect "No world has the given color ${color}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -28,9 +28,9 @@ pub mod node {
|
|||||||
OperatorInner::CallOp => "op_call",
|
OperatorInner::CallOp => "op_call",
|
||||||
OperatorInner::Index => "op_index",
|
OperatorInner::Index => "op_index",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Parameters {
|
impl Default for Parameters {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(vec![])
|
Self::new(vec![])
|
||||||
|
|||||||
@ -31,7 +31,7 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
|
|||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
|
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() {
|
if diagnostics.is_empty() {
|
||||||
println!("Name analysis complete.");
|
println!("Name analysis complete.");
|
||||||
println!("{}", symbol_table);
|
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.
|
`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::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::gather::gather_compilation_unit;
|
use crate::name_analysis::gather::gather_compilation_unit;
|
||||||
// use crate::name_analysis::resolve::resolve_compilation_unit;
|
|
||||||
use crate::name_analysis::symbol_table::SymbolTable;
|
use crate::name_analysis::symbol_table::SymbolTable;
|
||||||
use codespan_reporting::files::Files;
|
use codespan_reporting::files::Files;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use crate::name_analysis::scope_table::ScopeTable;
|
||||||
|
|
||||||
pub(self) mod fqn_context;
|
pub(self) mod fqn_context;
|
||||||
mod gather;
|
mod gather;
|
||||||
// mod resolve;
|
// mod resolve;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod symbol_table;
|
pub mod symbol_table;
|
||||||
|
mod scope_table;
|
||||||
|
|
||||||
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
||||||
compilation_units: &mut [Box<CompilationUnit>],
|
compilation_units: &[Box<CompilationUnit>],
|
||||||
files: &'a F,
|
files: &'a F,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
) -> Vec<DmDiagnostic> {
|
) -> Vec<DmDiagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
let mut scope_ids: HashMap<VariableUse, usize> = HashMap::new();
|
let mut scope_table = ScopeTable::new();
|
||||||
|
|
||||||
// gather symbols
|
// 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();
|
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
||||||
gather_compilation_unit(
|
gather_compilation_unit(
|
||||||
compilation_unit,
|
compilation_unit,
|
||||||
&file_name,
|
&file_name,
|
||||||
symbol_table,
|
symbol_table,
|
||||||
&mut scope_ids,
|
&mut scope_table,
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve symbols
|
// 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);
|
// 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) {
|
pub fn push_scope(&mut self, debug_name: &str) {
|
||||||
let id = self.scopes.len();
|
let id = self.scopes.len();
|
||||||
self.scopes
|
self.scopes.push(Scope::new(
|
||||||
.push(Scope::new(Some(self.current_scope_id), id, debug_name.to_string()));
|
Some(self.current_scope_id),
|
||||||
|
id,
|
||||||
|
debug_name.to_string(),
|
||||||
|
));
|
||||||
self.current_scope_id = id;
|
self.current_scope_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +319,61 @@ impl SymbolTable {
|
|||||||
Some(&self.scopes[parent_id])
|
Some(&self.scopes[parent_id])
|
||||||
} else {
|
} else {
|
||||||
None
|
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)
|
Err(NoDefinition)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,7 +50,6 @@ Identifier:
|
|||||||
- range:
|
- range:
|
||||||
kind: range
|
kind: range
|
||||||
derive:
|
derive:
|
||||||
- Clone
|
|
||||||
- PartialEq
|
- PartialEq
|
||||||
- Eq
|
- Eq
|
||||||
- Hash
|
- Hash
|
||||||
@ -60,6 +59,10 @@ FullyQualifiedName:
|
|||||||
- identifiers:
|
- identifiers:
|
||||||
vec:
|
vec:
|
||||||
rule: Identifier
|
rule: Identifier
|
||||||
|
derive:
|
||||||
|
- PartialEq
|
||||||
|
- Eq
|
||||||
|
- Hash
|
||||||
|
|
||||||
# Lists
|
# Lists
|
||||||
TypeUseList:
|
TypeUseList:
|
||||||
@ -74,7 +77,7 @@ IdentifierList:
|
|||||||
- identifiers:
|
- identifiers:
|
||||||
vec:
|
vec:
|
||||||
rule: Identifier
|
rule: Identifier
|
||||||
ParenthesesOptionalTypeUseList:
|
ParenthesesTypeUseList:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
- type_use_list:
|
- type_use_list:
|
||||||
@ -90,19 +93,29 @@ TypeUse:
|
|||||||
- TupleTypeUse
|
- TupleTypeUse
|
||||||
- FunctionTypeUse
|
- FunctionTypeUse
|
||||||
PrimitiveType:
|
PrimitiveType:
|
||||||
leaf_enum:
|
tree_enum:
|
||||||
rules:
|
rules:
|
||||||
- Byte
|
- Byte:
|
||||||
- Short
|
child: false
|
||||||
- Char
|
- Short:
|
||||||
- Int
|
child: false
|
||||||
- Long
|
- Char:
|
||||||
- Double
|
child: false
|
||||||
- Bool
|
- Int:
|
||||||
- String
|
child: false
|
||||||
|
- Long:
|
||||||
|
child: false
|
||||||
|
- Double:
|
||||||
|
child: false
|
||||||
|
- Bool:
|
||||||
|
child: false
|
||||||
|
- String:
|
||||||
|
child: false
|
||||||
- TypedArray
|
- TypedArray
|
||||||
- Any
|
- Any:
|
||||||
- Void
|
child: false
|
||||||
|
- Void:
|
||||||
|
child: false
|
||||||
TypedArray:
|
TypedArray:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
@ -160,7 +173,7 @@ GenericParameters:
|
|||||||
TupleArguments:
|
TupleArguments:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
- parentheses_optional_type_use_list
|
- parentheses_type_use_list
|
||||||
|
|
||||||
# Implements List
|
# Implements List
|
||||||
ImplementsList:
|
ImplementsList:
|
||||||
@ -656,7 +669,7 @@ IfClause:
|
|||||||
skip:
|
skip:
|
||||||
rule: Then
|
rule: Then
|
||||||
- statements:
|
- statements:
|
||||||
skip:
|
vec:
|
||||||
rule: Statement
|
rule: Statement
|
||||||
IfElseIf:
|
IfElseIf:
|
||||||
struct:
|
struct:
|
||||||
@ -704,7 +717,7 @@ ForStatement:
|
|||||||
- do_kw:
|
- do_kw:
|
||||||
skip:
|
skip:
|
||||||
rule: Do
|
rule: Do
|
||||||
- statement:
|
- statements:
|
||||||
vec:
|
vec:
|
||||||
rule: Statement
|
rule: Statement
|
||||||
- end_kw:
|
- end_kw:
|
||||||
@ -731,7 +744,6 @@ VariableUse:
|
|||||||
children:
|
children:
|
||||||
- identifier
|
- identifier
|
||||||
derive:
|
derive:
|
||||||
- Clone
|
|
||||||
- PartialEq
|
- PartialEq
|
||||||
- Eq
|
- Eq
|
||||||
- Hash
|
- Hash
|
||||||
|
|||||||
@ -199,7 +199,7 @@ IdentifierList = {
|
|||||||
~ ( "," ~ Identifier )*
|
~ ( "," ~ Identifier )*
|
||||||
}
|
}
|
||||||
|
|
||||||
ParenthesesOptionalTypeUseList = {
|
ParenthesesTypeUseList = {
|
||||||
"("
|
"("
|
||||||
~ TypeUseList?
|
~ TypeUseList?
|
||||||
~ ")"
|
~ ")"
|
||||||
@ -272,7 +272,7 @@ GenericParameters = {
|
|||||||
// Tuple Arguments
|
// Tuple Arguments
|
||||||
|
|
||||||
TupleArguments = {
|
TupleArguments = {
|
||||||
ParenthesesOptionalTypeUseList
|
ParenthesesTypeUseList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements list
|
// 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 instruction;
|
||||||
pub mod interface;
|
pub mod interface;
|
||||||
pub mod lib;
|
pub mod lib;
|
||||||
|
mod mem;
|
||||||
pub mod method;
|
pub mod method;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
pub mod op_codes;
|
pub mod op_codes;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user