Successfully fixed implicit global println test.
This commit is contained in:
parent
0550df534e
commit
6bcef184eb
@ -11,6 +11,10 @@ use convert_case::{Case, Casing};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
fn make_result() -> TokenStream {
|
||||
quote! { std::fmt::Result }
|
||||
}
|
||||
|
||||
fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", spec.name());
|
||||
let type_string = spec.name();
|
||||
@ -44,9 +48,11 @@ fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> To
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(#type_string)?;
|
||||
writer.increase_indent();
|
||||
#(#child_print_statements)*
|
||||
@ -70,9 +76,11 @@ fn make_polymorphic_type_p2_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
match self {
|
||||
#(#child_matchers,)*
|
||||
}
|
||||
@ -94,9 +102,11 @@ fn make_leaf_enum_p2_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
match self {
|
||||
#(#child_matchers,)*
|
||||
}
|
||||
@ -137,9 +147,11 @@ fn make_tree_enum_p2_impl(spec: &TreeEnumBuildSpec) -> TokenStream {
|
||||
.map(Option::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(#type_str)?;
|
||||
writer.increase_indent();
|
||||
match self {
|
||||
@ -184,9 +196,11 @@ fn make_leaf_struct_p2_impl(leaf_struct_build_spec: &LeafStructBuildSpec) -> Tok
|
||||
.map(Option::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(&format!(#format_string, #(#members),*))
|
||||
}
|
||||
}
|
||||
@ -232,7 +246,7 @@ fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
|
||||
})
|
||||
}
|
||||
},
|
||||
StructChild::Special(_) => None
|
||||
StructChild::Special(_) => None,
|
||||
})
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
@ -241,9 +255,11 @@ fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", struct_build_spec.build());
|
||||
let type_string = struct_build_spec.build();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(#type_string)?;
|
||||
writer.increase_indent();
|
||||
#(#child_print_statements)*
|
||||
|
||||
@ -166,7 +166,7 @@ pub mod pretty_print {
|
||||
use crate::util::indent_writer::IndentWriter;
|
||||
|
||||
pub trait PrettyPrint {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()>;
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result;
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/src/ast/pretty_print.rs"));
|
||||
|
||||
@ -11,10 +11,12 @@ pub fn pretty_print_parse(path: &PathBuf) {
|
||||
match parse_result {
|
||||
Ok(mut pairs) => {
|
||||
let compilation_unit = build_ast(0, &mut pairs);
|
||||
let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout()));
|
||||
let mut acc = String::new();
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
compilation_unit
|
||||
.pretty_print(&mut indent_writer)
|
||||
.expect("Unable to pretty-print.");
|
||||
println!("{}", acc);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
|
||||
@ -33,6 +33,8 @@ pub fn na_p1_compilation_unit(
|
||||
.set_current_fqn(&fqn.identifiers().map(Identifier::name).collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
symbol_table.set_current_fqn(&[]);
|
||||
}
|
||||
|
||||
symbol_table.push_scope(&format!("FileScope {}", file_name));
|
||||
|
||||
@ -67,20 +67,22 @@ pub fn analyze_names<
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::ast_node::AstNodeRef;
|
||||
use crate::ast::build::build_ast;
|
||||
use crate::ast::pretty_print::PrettyPrint;
|
||||
use crate::ast::walk::walk_depth_first;
|
||||
use crate::name_analysis::symbol::use_symbol::StarUseSymbol;
|
||||
use crate::name_analysis::symbol::{ExpressibleSymbol, PrimitiveTypeSymbol, TypeSymbol};
|
||||
use crate::name_analysis::util::str_slice_to_rcs;
|
||||
use crate::parser::{DeimosParser, Rule};
|
||||
use crate::std_core::add_std_core_symbols;
|
||||
use crate::util::indent_writer::IndentWriter;
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use pest::Parser;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use crate::ast::ast_node::AstNodeRef;
|
||||
use crate::ast::walk::walk_depth_first;
|
||||
use crate::name_analysis::symbol::{LVSymbol, PrimitiveTypeSymbol, TypeSymbol};
|
||||
|
||||
fn parse_compilation_units<'a>(
|
||||
files: &mut SimpleFiles<&'a str, &'a str>,
|
||||
@ -100,7 +102,7 @@ mod tests {
|
||||
let file_id = files.add(file_name, source);
|
||||
compilation_units.push(build_ast(file_id, &mut pairs));
|
||||
}
|
||||
|
||||
|
||||
compilation_units
|
||||
}
|
||||
|
||||
@ -110,13 +112,9 @@ mod tests {
|
||||
number_of_diagnostics: usize,
|
||||
) -> (Vec<CompilationUnit>, SimpleFiles<&'a str, &'a str>) {
|
||||
let mut files = SimpleFiles::<&'a str, &'a str>::new();
|
||||
let mut to_analyze = parse_compilation_units(&mut files, sources);
|
||||
|
||||
let diagnostics = analyze_names(
|
||||
&mut to_analyze,
|
||||
&files,
|
||||
symbol_table
|
||||
);
|
||||
let mut compilation_units = parse_compilation_units(&mut files, sources);
|
||||
|
||||
let diagnostics = analyze_names(&mut compilation_units, &files, symbol_table);
|
||||
|
||||
if diagnostics.len() != number_of_diagnostics {
|
||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||
@ -127,11 +125,20 @@ mod tests {
|
||||
}
|
||||
|
||||
eprintln!("{}", symbol_table);
|
||||
|
||||
for compilation_unit in &compilation_units {
|
||||
let mut acc = String::new();
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
compilation_unit
|
||||
.pretty_print(&mut indent_writer)
|
||||
.expect("Pretty print failed");
|
||||
eprintln!("{}", acc);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(number_of_diagnostics, diagnostics.len());
|
||||
|
||||
(to_analyze, files)
|
||||
(compilation_units, files)
|
||||
}
|
||||
|
||||
fn assert_no_diagnostics<'a>(
|
||||
@ -140,19 +147,19 @@ mod tests {
|
||||
) -> (Vec<CompilationUnit>, SimpleFiles<&'a str, &'a str>) {
|
||||
assert_number_of_diagnostics(sources, symbol_table, 0)
|
||||
}
|
||||
|
||||
|
||||
fn make_names_to_cus_map<'a>(
|
||||
compilation_units: &'a [CompilationUnit],
|
||||
files: &SimpleFiles<&'a str, &str>,
|
||||
) -> HashMap<&'a str, &'a CompilationUnit> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
|
||||
for compilation_unit in compilation_units {
|
||||
let file_id = compilation_unit.file_id();
|
||||
let name = files.name(file_id).unwrap();
|
||||
map.insert(name, compilation_unit);
|
||||
}
|
||||
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
@ -171,11 +178,11 @@ mod tests {
|
||||
let (cus, files) = assert_no_diagnostics(sources, &mut symbol_table);
|
||||
let results_map = make_names_to_cus_map(&cus, &files);
|
||||
let main_cu = *results_map.get("main.dm").unwrap();
|
||||
|
||||
|
||||
let mut found_main = false;
|
||||
let mut found_x = false;
|
||||
let mut found_args_ref = false;
|
||||
|
||||
|
||||
walk_depth_first(main_cu, &mut |node| {
|
||||
use AstNodeRef::*;
|
||||
match node {
|
||||
@ -209,34 +216,35 @@ mod tests {
|
||||
_ => panic!("Expected a primitive type symbol for args.")
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
VariableDeclaration(variable_declaration) => {
|
||||
if variable_declaration.identifier().name() == "x" {
|
||||
found_x = true;
|
||||
assert_eq!(
|
||||
variable_declaration.variable_symbol().unwrap().borrow().declared_name(),
|
||||
variable_declaration
|
||||
.variable_symbol()
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.declared_name(),
|
||||
"x"
|
||||
);
|
||||
}
|
||||
}
|
||||
VariableUse(variable_use) => {
|
||||
if variable_use.identifier().name() == "args" {
|
||||
IdentifierExpression(identifier_expression) => {
|
||||
if identifier_expression.identifier().name() == "args" {
|
||||
found_args_ref = true;
|
||||
match variable_use.lv_symbol().unwrap() {
|
||||
LVSymbol::Parameter(parameter_symbol) => {
|
||||
assert_eq!(
|
||||
parameter_symbol.borrow().declared_name(),
|
||||
"args"
|
||||
)
|
||||
match identifier_expression.expressible_symbol().unwrap() {
|
||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||
assert_eq!(parameter_symbol.borrow().declared_name(), "args")
|
||||
}
|
||||
_ => panic!("Expected args variable use to be a parameter symbol.")
|
||||
_ => panic!("Expected args variable use to be a parameter symbol."),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assert!(found_main);
|
||||
assert!(found_x);
|
||||
assert!(found_args_ref);
|
||||
@ -299,17 +307,24 @@ mod tests {
|
||||
fn main(args: Array<String>)
|
||||
println args
|
||||
end
|
||||
"
|
||||
",
|
||||
)]);
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let global_std_core_use = StarUseSymbol::new(
|
||||
&[Rc::from("std"), Rc::from("core")],
|
||||
None
|
||||
);
|
||||
symbol_table.insert_star_use_symbol(global_std_core_use)
|
||||
let global_std_core_star_use_to_insert =
|
||||
StarUseSymbol::new(&[Rc::from("std"), Rc::from("core")], None);
|
||||
let global_std_core_star_use = symbol_table
|
||||
.insert_star_use_symbol(global_std_core_star_use_to_insert)
|
||||
.expect("Failed to insert star use symbol.");
|
||||
|
||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std/core symbols.");
|
||||
|
||||
let resolved_std_core_symbols = symbol_table
|
||||
.find_usable_symbols_by_base_fqn(&str_slice_to_rcs(&["std", "core"]))
|
||||
.unwrap();
|
||||
global_std_core_star_use
|
||||
.borrow_mut()
|
||||
.set_resolved_symbols(resolved_std_core_symbols);
|
||||
|
||||
assert_no_diagnostics(sources, &mut symbol_table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
use crate::ast::node::{
|
||||
AssignmentStatement, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix,
|
||||
Expression, ExpressionStatement, Function, FunctionAliasBody, FunctionBlockBody, FunctionBody,
|
||||
FunctionEqualsBody, GenericParameters, Identifier, IdentifierOrFqn, LValue, LValueSuffix,
|
||||
ModuleLevelDeclaration, Parameter, Parameters, PrimitiveType, ReturnType, StarUseStatement,
|
||||
Statement, TypeUse, TypedArray, UseStatement, UseStatementIdentifier, UseStatementPrefix,
|
||||
VariableDeclaration, VariableUse,
|
||||
AssignmentStatement, Call, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix,
|
||||
Expression, ExpressionList, ExpressionStatement, Function, FunctionAliasBody,
|
||||
FunctionBlockBody, FunctionBody, FunctionEqualsBody, GenericParameters, Identifier,
|
||||
IdentifierExpression, IdentifierOrFqn, LValue, LValueSuffix, ModuleLevelDeclaration,
|
||||
ObjectIndex, Parameter, Parameters, PrimitiveType, ReturnType, StarUseStatement, Statement,
|
||||
SuffixExpression, SuffixOperator, TypeUse, TypedArray, UseStatement, UseStatementIdentifier,
|
||||
UseStatementPrefix, VariableDeclaration,
|
||||
};
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
@ -516,7 +517,20 @@ fn na_p2_l_value(
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_variable_use(l_value.variable_use_mut(), symbol_table, diagnostics);
|
||||
match symbol_table.lookup_lv_symbol(l_value.identifier().name()) {
|
||||
Ok(lv_symbol) => {
|
||||
l_value.set_lv_symbol(lv_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
l_value.identifier().name(),
|
||||
l_value.identifier().file_id(),
|
||||
l_value.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
// "Name analysis" of suffixes is done during type-checking. We don't want to deal with getting
|
||||
// out the different potential return types of things until that point, especially if we end up
|
||||
// adding dynamic objects to the language. However, suffixes may contain things (like arguments)
|
||||
@ -554,27 +568,6 @@ fn na_p2_expression_statement(
|
||||
);
|
||||
}
|
||||
|
||||
fn na_p2_variable_use(
|
||||
variable_use: &mut VariableUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match symbol_table.lookup_lv_symbol(variable_use.identifier().name()) {
|
||||
Ok(lv_symbol) => {
|
||||
variable_use.set_lv_symbol(lv_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
variable_use.identifier().name(),
|
||||
variable_use.identifier().file_id(),
|
||||
variable_use.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_expression(
|
||||
expression: &mut Expression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
@ -606,13 +599,13 @@ fn na_p2_expression(
|
||||
todo!()
|
||||
}
|
||||
Expression::Suffix(suffix) => {
|
||||
todo!()
|
||||
na_p2_suffix_expression(suffix, symbol_table, diagnostics);
|
||||
}
|
||||
Expression::Literal(literal) => {
|
||||
todo!()
|
||||
}
|
||||
Expression::VariableUse(variable_use) => {
|
||||
na_p2_variable_use(variable_use, symbol_table, diagnostics);
|
||||
Expression::Identifier(identifier_expression) => {
|
||||
na_p2_identifier_expression(identifier_expression, symbol_table, diagnostics);
|
||||
}
|
||||
Expression::Fqn(fqn) => {
|
||||
todo!()
|
||||
@ -625,3 +618,111 @@ fn na_p2_expression(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_suffix_expression(
|
||||
suffix_expression: &mut SuffixExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_expression(
|
||||
suffix_expression.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
na_p2_suffix_operator(suffix_expression.operator_mut(), symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn na_p2_suffix_operator(
|
||||
suffix_operator: &mut SuffixOperator,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match suffix_operator {
|
||||
SuffixOperator::PlusPlus => {
|
||||
// no-op
|
||||
}
|
||||
SuffixOperator::MinusMinus => {
|
||||
// no-op
|
||||
}
|
||||
SuffixOperator::ObjectProperty(_) => {
|
||||
// no-op; props checked during type checking
|
||||
}
|
||||
SuffixOperator::ObjectIndex(object_index) => {
|
||||
na_p2_object_index(object_index, symbol_table, diagnostics);
|
||||
}
|
||||
SuffixOperator::Call(call) => {
|
||||
na_p2_call(call, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_object_index(
|
||||
object_index: &mut ObjectIndex,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_expression(object_index.expression_mut(), symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn na_p2_call(
|
||||
call: &mut Call,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
// TODO: modify the ast-gen so that we don't have to match on these. They should be the same.
|
||||
match call {
|
||||
Call::ParenthesesCall(parentheses_call) => {
|
||||
if let Some(turbo_fish) = parentheses_call.turbo_fish_mut() {
|
||||
todo!()
|
||||
}
|
||||
if let Some(expression_list) = parentheses_call.expression_list_mut() {
|
||||
na_p2_expression_list(expression_list, symbol_table, diagnostics);
|
||||
}
|
||||
if let Some(closure) = parentheses_call.closure_mut() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Call::NonParenthesesCall(non_parentheses_call) => {
|
||||
if let Some(turbo_fish) = non_parentheses_call.turbo_fish_mut() {
|
||||
todo!()
|
||||
}
|
||||
if let Some(expression_list) = non_parentheses_call.expression_list_mut() {
|
||||
na_p2_expression_list(expression_list, symbol_table, diagnostics);
|
||||
}
|
||||
if let Some(closure) = non_parentheses_call.closure_mut() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_identifier_expression(
|
||||
identifier_expression: &mut IdentifierExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match symbol_table.lookup_expressible_symbol(identifier_expression.identifier().name()) {
|
||||
Ok(expressible_symbol) => {
|
||||
identifier_expression.set_expressible_symbol(expressible_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
identifier_expression.identifier().name(),
|
||||
identifier_expression.identifier().file_id(),
|
||||
identifier_expression.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_expression_list(
|
||||
expression_list: &mut ExpressionList,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for expression in expression_list.expressions_mut() {
|
||||
na_p2_expression(expression, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
33
src/name_analysis/symbol/expressible_symbol.rs
Normal file
33
src/name_analysis/symbol/expressible_symbol.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use crate::name_analysis::symbol::{ClassMemberSymbol, ClassSymbol, FunctionSymbol, ParameterSymbol, Symbol, VariableSymbol};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub enum ExpressibleSymbol {
|
||||
Class(Rc<RefCell<ClassSymbol>>),
|
||||
Function(Rc<RefCell<FunctionSymbol>>),
|
||||
ClassMember(Rc<RefCell<ClassMemberSymbol>>),
|
||||
Parameter(Rc<RefCell<ParameterSymbol>>),
|
||||
Variable(Rc<RefCell<VariableSymbol>>),
|
||||
}
|
||||
|
||||
impl ExpressibleSymbol {
|
||||
pub fn to_symbol(self) -> Rc<RefCell<dyn Symbol>> {
|
||||
match self {
|
||||
ExpressibleSymbol::Class(class_symbol) => {
|
||||
class_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::Function(function_symbol) => {
|
||||
function_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::ClassMember(class_member_symbol) => {
|
||||
class_member_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||
parameter_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||
variable_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod class_member_symbol;
|
||||
pub mod class_symbol;
|
||||
pub mod expressible_symbol;
|
||||
pub mod function_symbol;
|
||||
pub mod generic_type_symbol;
|
||||
pub mod interface_symbol;
|
||||
@ -18,10 +19,10 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use self::{
|
||||
class_member_symbol::*, class_symbol::*, function_symbol::*, function_symbol::*,
|
||||
generic_type_symbol::*, interface_symbol::*, lv_symbol::*, module_level_symbol::*,
|
||||
module_symbol::*, parameter_symbol::*, primitive_type_symbol::*, type_symbol::*,
|
||||
usable_symbol::*, use_symbol::*, variable_symbol::*,
|
||||
class_member_symbol::*, class_symbol::*, expressible_symbol::*, function_symbol::*,
|
||||
function_symbol::*, generic_type_symbol::*, interface_symbol::*, lv_symbol::*,
|
||||
module_level_symbol::*, module_symbol::*, parameter_symbol::*, primitive_type_symbol::*,
|
||||
type_symbol::*, usable_symbol::*, use_symbol::*, variable_symbol::*,
|
||||
};
|
||||
|
||||
pub trait Symbol: Debug {
|
||||
|
||||
@ -51,6 +51,7 @@ impl Debug for ParameterSymbol {
|
||||
f.debug_struct("ParameterSymbol")
|
||||
.field("declared_name", &self.declared_name)
|
||||
.field("source_definition", &self.source_definition)
|
||||
.field("type_symbol", &self.type_symbol)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,9 +109,10 @@ impl Symbol for StarUseSymbol {
|
||||
|
||||
impl Debug for StarUseSymbol {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("StarUseStatementSymbol")
|
||||
f.debug_struct("StarUseSymbol")
|
||||
.field("fqn", &join_fqn_parts(&self.fqn_parts))
|
||||
.field("source_definition", &self.source_definition)
|
||||
.field("resolved_symbols", &self.resolved_symbols)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,8 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
|
||||
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol::{LVSymbol, Symbol};
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::name_analysis::symbol::{ExpressibleSymbol, LVSymbol, Symbol};
|
||||
use crate::name_analysis::symbol_table::fqn_context::FqnContext;
|
||||
use crate::name_analysis::symbol_table::symbol_tree::SymbolTree;
|
||||
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
|
||||
@ -14,7 +15,6 @@ use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
|
||||
pub(self) mod fqn_context;
|
||||
mod scope;
|
||||
@ -25,6 +25,7 @@ pub enum SymbolInsertError {
|
||||
SymbolAlreadyDefined(Rc<RefCell<dyn Symbol>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SymbolLookupError {
|
||||
NoDefinition,
|
||||
NoSuchNamespace,
|
||||
@ -44,7 +45,7 @@ impl SymbolTable {
|
||||
Self {
|
||||
scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))],
|
||||
current_scope_id: 0,
|
||||
symbol_tree: Box::new(SymbolTree::new()),
|
||||
symbol_tree: Box::new(SymbolTree::new("<DEFAULT>")),
|
||||
fqn_context: Box::new(FqnContext::new()),
|
||||
}
|
||||
}
|
||||
@ -68,7 +69,7 @@ impl SymbolTable {
|
||||
self.current_scope_id = parent_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn set_current_scope(&mut self, id: usize) {
|
||||
self.current_scope_id = id;
|
||||
}
|
||||
@ -122,6 +123,15 @@ impl SymbolTable {
|
||||
self.symbol_tree.register_module_by_fqn_parts(fqn_parts);
|
||||
}
|
||||
|
||||
pub fn register_function_symbol(
|
||||
&mut self,
|
||||
function_symbol: FunctionSymbol,
|
||||
) -> Rc<RefCell<FunctionSymbol>> {
|
||||
let as_rc = Rc::new(RefCell::new(function_symbol));
|
||||
self.symbol_tree.register_function(as_rc.clone());
|
||||
as_rc
|
||||
}
|
||||
|
||||
pub fn find_usable_symbols_by_base_fqn(
|
||||
&self,
|
||||
fqn_parts: &[Rc<str>],
|
||||
@ -231,7 +241,7 @@ impl SymbolTable {
|
||||
Ok(inserted)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn insert_variable_symbol(
|
||||
&mut self,
|
||||
variable_symbol: VariableSymbol,
|
||||
@ -266,8 +276,11 @@ impl SymbolTable {
|
||||
pub fn lookup_type_by_fqn(&self, fqn_parts: &[&str]) -> Result<TypeSymbol, SymbolLookupError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn lookup_function_symbol(&self, declared_name: &str) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolLookupError> {
|
||||
|
||||
pub fn lookup_function_symbol(
|
||||
&self,
|
||||
declared_name: &str,
|
||||
) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolLookupError> {
|
||||
let mut current_scope: Option<&Scope> = Some(self.current_scope());
|
||||
while let Some(scope) = current_scope.take() {
|
||||
if let Some(function_symbol) = scope.find_function_symbol(declared_name) {
|
||||
@ -280,12 +293,29 @@ impl SymbolTable {
|
||||
}
|
||||
Err(SymbolLookupError::NoDefinition)
|
||||
}
|
||||
|
||||
|
||||
pub fn lookup_lv_symbol(&self, declared_name: &str) -> Result<LVSymbol, SymbolLookupError> {
|
||||
let mut current_scope: Option<&Scope> = Some(self.current_scope());
|
||||
while let Some(scope) = current_scope.take() {
|
||||
if let Some(lv_symbol) = scope.find_lv_symbol(declared_name) {
|
||||
return Ok(lv_symbol)
|
||||
return Ok(lv_symbol);
|
||||
} else {
|
||||
current_scope = scope
|
||||
.parent()
|
||||
.and_then(|parent_id| self.scopes.get(parent_id));
|
||||
}
|
||||
}
|
||||
Err(SymbolLookupError::NoDefinition)
|
||||
}
|
||||
|
||||
pub fn lookup_expressible_symbol(
|
||||
&self,
|
||||
declared_name: &str,
|
||||
) -> Result<ExpressibleSymbol, SymbolLookupError> {
|
||||
let mut current_scope: Option<&Scope> = Some(self.current_scope());
|
||||
while let Some(scope) = current_scope.take() {
|
||||
if let Some(expressible_symbol) = scope.find_expressible_symbol(declared_name) {
|
||||
return Ok(expressible_symbol);
|
||||
} else {
|
||||
current_scope = scope
|
||||
.parent()
|
||||
@ -302,6 +332,8 @@ impl Display for SymbolTable {
|
||||
for scope in &self.scopes {
|
||||
writeln!(f, "{}", scope)?;
|
||||
}
|
||||
writeln!(f, "---SymbolTable: SymbolTree---")?;
|
||||
writeln!(f, "{}", self.symbol_tree)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::name_analysis::symbol::{ExpressibleSymbol, UsableSymbol};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -142,7 +143,7 @@ impl Scope {
|
||||
let key = symbol.declared_name_owned();
|
||||
insert_symbol!(self.parameter_symbols, symbol, key)
|
||||
}
|
||||
|
||||
|
||||
pub fn insert_variable_symbol(
|
||||
&mut self,
|
||||
symbol: VariableSymbol,
|
||||
@ -203,11 +204,84 @@ impl Scope {
|
||||
.map(|variable_symbol| LVSymbol::Variable(variable_symbol.clone()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_function_symbol(&self, declared_name: &str) -> Option<&Rc<RefCell<FunctionSymbol>>> {
|
||||
|
||||
pub fn find_function_symbol(
|
||||
&self,
|
||||
declared_name: &str,
|
||||
) -> Option<&Rc<RefCell<FunctionSymbol>>> {
|
||||
self.function_symbols.get(declared_name)
|
||||
}
|
||||
|
||||
pub fn find_expressible_symbol(&self, declared_name: &str) -> Option<ExpressibleSymbol> {
|
||||
// First, try all the usual suspects: classes, functions, members, parameters, and variables
|
||||
// which are in scope. If we don't find any of those, try looking through imports; start
|
||||
// with concrete imports by declared name; if none of those match, check all resolved
|
||||
// symbols of the star imports until one is found or none.
|
||||
// !! Eventually consider registering star-imported symbols in a scope so that we can just
|
||||
// check them via the hash maps instead of looping through the star symbols.
|
||||
self.class_symbols
|
||||
.get(declared_name)
|
||||
.map(|class_symbol| ExpressibleSymbol::Class(class_symbol.clone()))
|
||||
.or_else(|| {
|
||||
self.function_symbols
|
||||
.get(declared_name)
|
||||
.map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
self.class_member_symbols
|
||||
.get(declared_name)
|
||||
.map(|class_member_symbol| {
|
||||
ExpressibleSymbol::ClassMember(class_member_symbol.clone())
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
self.parameter_symbols
|
||||
.get(declared_name)
|
||||
.map(|parameter_symbol| ExpressibleSymbol::Parameter(parameter_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
self.variable_symbols
|
||||
.get(declared_name)
|
||||
.map(|variable_symbol| ExpressibleSymbol::Variable(variable_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
if let Some(concrete_use_symbol) = self.concrete_use_symbols.get(declared_name) {
|
||||
return match concrete_use_symbol.borrow().resolved_symbol().unwrap() {
|
||||
UsableSymbol::Interface(_) => {
|
||||
None
|
||||
}
|
||||
UsableSymbol::Class(class_symbol) => {
|
||||
Some(ExpressibleSymbol::Class(class_symbol.clone()))
|
||||
}
|
||||
UsableSymbol::Function(function_symbol) => {
|
||||
Some(ExpressibleSymbol::Function(function_symbol.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.or_else(|| {
|
||||
for star_use_symbol in self.star_use_symbols.values() {
|
||||
for usable_symbol in star_use_symbol.borrow().resolved_symbols() {
|
||||
match usable_symbol {
|
||||
UsableSymbol::Class(class_symbol) => {
|
||||
if class_symbol.borrow().declared_name() == declared_name {
|
||||
return Some(ExpressibleSymbol::Class(class_symbol.clone()));
|
||||
}
|
||||
}
|
||||
UsableSymbol::Function(function_symbol) => {
|
||||
if function_symbol.borrow().declared_name() == declared_name {
|
||||
return Some(ExpressibleSymbol::Function(function_symbol.clone()));
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn debug_name(&self) -> &str {
|
||||
&self.debug_name
|
||||
}
|
||||
|
||||
@ -4,12 +4,15 @@ use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
||||
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
||||
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||
use crate::name_analysis::symbol_table::SymbolLookupError;
|
||||
use crate::util::indent_writer::IndentWriter;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SymbolTree {
|
||||
debug_name: String,
|
||||
children: Box<HashMap<Rc<str>, SymbolTree>>,
|
||||
classes: Box<HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>>,
|
||||
interfaces: Box<HashMap<Rc<str>, Rc<RefCell<InterfaceSymbol>>>>,
|
||||
@ -17,8 +20,9 @@ pub struct SymbolTree {
|
||||
}
|
||||
|
||||
impl SymbolTree {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(debug_name: &str) -> Self {
|
||||
Self {
|
||||
debug_name: debug_name.to_string(),
|
||||
children: Box::new(HashMap::new()),
|
||||
classes: Box::new(HashMap::new()),
|
||||
interfaces: Box::new(HashMap::new()),
|
||||
@ -78,13 +82,13 @@ impl SymbolTree {
|
||||
}
|
||||
if fqn_parts.len() == 1 {
|
||||
self.children
|
||||
.insert(fqn_parts[0].clone(), SymbolTree::new());
|
||||
.insert(fqn_parts[0].clone(), SymbolTree::new(fqn_parts[0].as_ref()));
|
||||
} else {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
let child = self.children.get_mut(fqn_parts[0].as_ref()).unwrap();
|
||||
child.recurse_register_module(&fqn_parts[1..]);
|
||||
} else {
|
||||
let mut child = SymbolTree::new();
|
||||
let mut child = SymbolTree::new(fqn_parts[0].as_ref());
|
||||
child.recurse_register_module(&fqn_parts[1..]);
|
||||
self.children.insert(fqn_parts[0].clone(), child);
|
||||
}
|
||||
@ -105,6 +109,12 @@ impl SymbolTree {
|
||||
panic!("Unable to register function fqn with no parts.");
|
||||
}
|
||||
if fqn_parts.len() == 1 {
|
||||
if self.functions.contains_key(fqn_parts[0].as_ref()) {
|
||||
panic!(
|
||||
"There is already a function registered in this symbol tree with the name {}",
|
||||
fqn_parts[0]
|
||||
);
|
||||
}
|
||||
self.functions.insert(fqn_parts[0].clone(), function_symbol);
|
||||
} else {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
@ -137,7 +147,7 @@ impl SymbolTree {
|
||||
_ => {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
let child = self.children.get(fqn_parts[0].as_ref()).unwrap();
|
||||
child.find_all_by_base_fqn(fqn_parts)
|
||||
child.find_all_by_base_fqn(&fqn_parts[1..])
|
||||
} else {
|
||||
Err(SymbolLookupError::NoSuchNamespace)
|
||||
}
|
||||
@ -145,3 +155,55 @@ impl SymbolTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FormatAction<'a> {
|
||||
PrintSymbolTree(&'a SymbolTree),
|
||||
IncreaseIndent,
|
||||
DecreaseIndent
|
||||
}
|
||||
|
||||
impl Display for SymbolTree {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let mut acc = String::new();
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
let mut stack: Vec<FormatAction> = vec![];
|
||||
stack.push(FormatAction::PrintSymbolTree(self));
|
||||
|
||||
while let Some(format_action) = stack.pop() {
|
||||
match format_action {
|
||||
FormatAction::PrintSymbolTree(symbol_tree) => {
|
||||
// reverse order: start with decrease
|
||||
stack.push(FormatAction::DecreaseIndent);
|
||||
// add children
|
||||
for child in symbol_tree.children.values() {
|
||||
stack.push(FormatAction::PrintSymbolTree(child));
|
||||
}
|
||||
// increase for the first child
|
||||
stack.push(FormatAction::IncreaseIndent);
|
||||
|
||||
indent_writer.writeln_indented(&format!("SymbolTree(debug_name = {})", symbol_tree.debug_name))?;
|
||||
|
||||
indent_writer.increase_indent();
|
||||
for interface in symbol_tree.interfaces.values() {
|
||||
indent_writer.writeln_indented(&format!("Interface({:?}", interface))?;
|
||||
}
|
||||
for class in symbol_tree.classes.values() {
|
||||
indent_writer.writeln_indented(&format!("Class({:?})", class))?;
|
||||
}
|
||||
for function in symbol_tree.functions.values() {
|
||||
indent_writer.writeln_indented(&format!("Function({:?})", function))?;
|
||||
}
|
||||
indent_writer.decrease_indent();
|
||||
}
|
||||
FormatAction::IncreaseIndent => {
|
||||
indent_writer.increase_indent();
|
||||
}
|
||||
FormatAction::DecreaseIndent => {
|
||||
indent_writer.decrease_indent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(f, "{}", acc)
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,12 +50,12 @@ pub fn handle_lookup_error(
|
||||
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
},
|
||||
}
|
||||
SymbolLookupError::NoSuchNamespace => {
|
||||
let diagnostic = Diagnostic::error()
|
||||
.with_message(format!("No such namespace '{}' found", error_symbol_name))
|
||||
.with_label(
|
||||
Label::primary(error_file_id, error_range).with_message("Namespace used here.")
|
||||
Label::primary(error_file_id, error_range).with_message("Namespace used here."),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@ -69,3 +69,7 @@ pub fn format_fqn(parts: &[&str]) -> String {
|
||||
pub fn join_fqn_parts(parts: &[Rc<str>]) -> String {
|
||||
format_fqn(&parts.iter().map(|part| part.as_ref()).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn str_slice_to_rcs(str_slice: &[&str]) -> Vec<Rc<str>> {
|
||||
str_slice.iter().map(|s| Rc::from(*s)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
@ -785,25 +785,19 @@ ForStatement:
|
||||
LValue:
|
||||
struct:
|
||||
children:
|
||||
- variable_use
|
||||
- identifier
|
||||
- suffixes:
|
||||
vec:
|
||||
rule: LValueSuffix
|
||||
fields:
|
||||
- lv_symbol:
|
||||
kind: LVSymbol
|
||||
LValueSuffix:
|
||||
tree_enum:
|
||||
rules:
|
||||
- ObjectProperty
|
||||
- ObjectIndex
|
||||
|
||||
# VariableUse
|
||||
VariableUse:
|
||||
struct:
|
||||
children:
|
||||
- identifier
|
||||
fields:
|
||||
- lv_symbol:
|
||||
kind: LVSymbol
|
||||
|
||||
# Expressions
|
||||
Expression:
|
||||
polymorphic_type:
|
||||
@ -838,9 +832,9 @@ Expression:
|
||||
- Literal:
|
||||
inner:
|
||||
kind: Literal
|
||||
- VariableUse:
|
||||
- Identifier:
|
||||
inner:
|
||||
kind: VariableUse
|
||||
kind: IdentifierExpression
|
||||
- Fqn:
|
||||
inner:
|
||||
kind: FullyQualifiedName
|
||||
@ -1183,9 +1177,9 @@ PrimaryExpression:
|
||||
- Literal:
|
||||
inner:
|
||||
kind: Literal
|
||||
- VariableUse:
|
||||
- Identifier:
|
||||
inner:
|
||||
kind: VariableUse
|
||||
kind: IdentifierExpression
|
||||
- Fqn:
|
||||
inner:
|
||||
kind: FullyQualifiedName
|
||||
@ -1198,6 +1192,13 @@ PrimaryExpression:
|
||||
- ParenthesizedExpression:
|
||||
pass_through:
|
||||
kind: Expression
|
||||
IdentifierExpression:
|
||||
struct:
|
||||
children:
|
||||
- identifier
|
||||
fields:
|
||||
- expressible_symbol:
|
||||
kind: ExpressibleSymbol
|
||||
ListExpression:
|
||||
struct:
|
||||
children:
|
||||
|
||||
@ -615,7 +615,7 @@ ForStatement = {
|
||||
// LValue
|
||||
|
||||
LValue = {
|
||||
VariableUse
|
||||
Identifier
|
||||
~ LValueSuffix*
|
||||
}
|
||||
|
||||
@ -624,12 +624,6 @@ LValueSuffix = {
|
||||
| ObjectIndex
|
||||
}
|
||||
|
||||
// Variable Use
|
||||
|
||||
VariableUse = {
|
||||
Identifier
|
||||
}
|
||||
|
||||
// Expressions
|
||||
|
||||
Expression = {
|
||||
@ -778,13 +772,17 @@ ObjectIndex = {
|
||||
|
||||
PrimaryExpression = {
|
||||
Literal
|
||||
| VariableUse
|
||||
| IdentifierExpression
|
||||
| FullyQualifiedName
|
||||
| Closure
|
||||
| ListExpression
|
||||
| ParenthesizedExpression
|
||||
}
|
||||
|
||||
IdentifierExpression = {
|
||||
Identifier
|
||||
}
|
||||
|
||||
ListExpression = {
|
||||
"["
|
||||
~ ExpressionList?
|
||||
|
||||
@ -26,7 +26,7 @@ pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), Symbol
|
||||
&vec![Rc::new(RefCell::new(println_msg_symbol))],
|
||||
None,
|
||||
);
|
||||
symbol_table.insert_function_symbol(println_symbol)?;
|
||||
symbol_table.register_function_symbol(println_symbol);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
pub struct IndentWriter {
|
||||
pub struct IndentWriter<'a> {
|
||||
indent_level: usize,
|
||||
indent_string: String,
|
||||
out: Box<dyn std::io::Write>,
|
||||
out: &'a mut dyn std::fmt::Write,
|
||||
}
|
||||
|
||||
impl IndentWriter {
|
||||
pub fn new(
|
||||
start_level: usize,
|
||||
indent_string: &str,
|
||||
out: Box<dyn std::io::Write>,
|
||||
) -> IndentWriter {
|
||||
impl<'a> IndentWriter<'a> {
|
||||
pub fn new(start_level: usize, indent_string: &str, out: &'a mut dyn std::fmt::Write) -> Self {
|
||||
IndentWriter {
|
||||
indent_level: start_level,
|
||||
indent_string: indent_string.to_string(),
|
||||
@ -25,22 +21,22 @@ impl IndentWriter {
|
||||
self.indent_level -= 1;
|
||||
}
|
||||
|
||||
pub fn write(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn write(&mut self, s: &str) -> std::fmt::Result {
|
||||
write!(self.out, "{}", s)
|
||||
}
|
||||
|
||||
pub fn writeln(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn writeln(&mut self, s: &str) -> std::fmt::Result {
|
||||
self.write(&format!("{}\n", s))
|
||||
}
|
||||
|
||||
pub fn write_indented(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn write_indented(&mut self, s: &str) -> std::fmt::Result {
|
||||
for _ in 0..self.indent_level {
|
||||
write!(self.out, "{}", self.indent_string)?;
|
||||
}
|
||||
write!(self.out, "{}", s)
|
||||
}
|
||||
|
||||
pub fn writeln_indented(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn writeln_indented(&mut self, s: &str) -> std::fmt::Result {
|
||||
self.write_indented(&format!("{}\n", s))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user