Work on basic name analysis.
This commit is contained in:
parent
9805a3aad5
commit
ce20cece21
10
sketching/may_2025/name_one.dm
Normal file
10
sketching/may_2025/name_one.dm
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
ns greeter
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 'Hello';
|
||||||
|
let y = 'World';
|
||||||
|
{
|
||||||
|
let test = 'Test';
|
||||||
|
};
|
||||||
|
x = y;
|
||||||
|
}
|
@ -14,13 +14,11 @@ pub fn build_ast(compilation_unit_pair: Pair<Rule>) -> CompilationUnit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn build_identifier(identifier_pair: Pair<Rule>) -> Identifier {
|
fn build_identifier(identifier_pair: Pair<Rule>) -> Identifier {
|
||||||
Identifier {
|
Identifier::new(identifier_pair.as_span().as_str())
|
||||||
name: identifier_pair.as_str().to_string(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_fqn(fqn_pair: Pair<Rule>) -> FullyQualifiedName {
|
fn build_fqn(fqn_pair: Pair<Rule>) -> FullyQualifiedName {
|
||||||
FullyQualifiedName(
|
FullyQualifiedName::new(
|
||||||
fqn_pair
|
fqn_pair
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.map(|identifier_pair| {
|
.map(|identifier_pair| {
|
||||||
@ -745,14 +743,10 @@ fn build_call_statement(call_statement_pair: Pair<Rule>) -> CallStatement {
|
|||||||
while let Some(inner_pair) = inner.next() {
|
while let Some(inner_pair) = inner.next() {
|
||||||
match inner_pair.as_rule() {
|
match inner_pair.as_rule() {
|
||||||
Rule::ObjectAccess => {
|
Rule::ObjectAccess => {
|
||||||
result = Expression::ObjectAccess(build_object_access(
|
result = Expression::ObjectAccess(build_object_access(result, inner_pair));
|
||||||
result, inner_pair,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Rule::ParenthesesCall => {
|
Rule::ParenthesesCall => {
|
||||||
result = Expression::Call(build_call_expression(
|
result = Expression::Call(build_call_expression(result, inner_pair));
|
||||||
result, inner_pair,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Rule::PlusPlus => {
|
Rule::PlusPlus => {
|
||||||
result = Expression::UnarySuffix(SuffixExpression {
|
result = Expression::UnarySuffix(SuffixExpression {
|
||||||
@ -971,16 +965,10 @@ fn build_suffix_expression(suffix_pair: Pair<Rule>) -> Expression {
|
|||||||
while let Some(suffix_pair) = inner.next() {
|
while let Some(suffix_pair) = inner.next() {
|
||||||
match suffix_pair.as_rule() {
|
match suffix_pair.as_rule() {
|
||||||
Rule::ObjectAccess => {
|
Rule::ObjectAccess => {
|
||||||
result = Expression::ObjectAccess(build_object_access(
|
result = Expression::ObjectAccess(build_object_access(result, suffix_pair))
|
||||||
result,
|
|
||||||
suffix_pair,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Rule::ParenthesesCall => {
|
Rule::ParenthesesCall => {
|
||||||
result = Expression::Call(build_call_expression(
|
result = Expression::Call(build_call_expression(result, suffix_pair))
|
||||||
result,
|
|
||||||
suffix_pair,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Rule::PlusPlus => {
|
Rule::PlusPlus => {
|
||||||
result = Expression::UnarySuffix(SuffixExpression {
|
result = Expression::UnarySuffix(SuffixExpression {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
use crate::compile::name_analysis::Symbol;
|
||||||
use pest::Parser;
|
use pest::Parser;
|
||||||
|
|
||||||
pub mod build;
|
pub mod build;
|
||||||
|
pub mod named;
|
||||||
pub mod pretty_print;
|
pub mod pretty_print;
|
||||||
pub mod unparse;
|
pub mod unparse;
|
||||||
// Operators
|
// Operators
|
||||||
@ -52,10 +54,68 @@ pub enum SuffixUnaryOperator {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Identifier {
|
pub struct Identifier {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
scope_id: Option<usize>,
|
||||||
|
symbol: Option<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Identifier {
|
||||||
|
pub fn new(name: &str) -> Self {
|
||||||
|
Identifier {
|
||||||
|
name: name.to_string(),
|
||||||
|
scope_id: None,
|
||||||
|
symbol: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scope_id(&mut self, id: usize) {
|
||||||
|
self.scope_id = Some(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope_id(&self) -> Option<usize> {
|
||||||
|
self.scope_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_symbol(&mut self, symbol: Symbol) {
|
||||||
|
self.symbol = Some(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbol(&self) -> &Option<Symbol> {
|
||||||
|
&self.symbol
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FullyQualifiedName(pub Vec<Identifier>);
|
pub struct FullyQualifiedName {
|
||||||
|
pub identifiers: Vec<Identifier>,
|
||||||
|
scope_id: Option<usize>,
|
||||||
|
symbol: Option<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FullyQualifiedName {
|
||||||
|
pub fn new(identifiers: Vec<Identifier>) -> Self {
|
||||||
|
FullyQualifiedName {
|
||||||
|
identifiers,
|
||||||
|
scope_id: None,
|
||||||
|
symbol: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scope_id(&mut self, scope_id: usize) {
|
||||||
|
self.scope_id = Some(scope_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope_id(&self) -> Option<usize> {
|
||||||
|
self.scope_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_symbol(&mut self, symbol: Symbol) {
|
||||||
|
self.symbol = Some(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbol(&self) -> &Option<Symbol> {
|
||||||
|
&self.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Type Use */
|
/* Type Use */
|
||||||
|
|
||||||
@ -400,10 +460,10 @@ pub enum Statement {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VariableDeclarationStatement {
|
pub struct VariableDeclarationStatement {
|
||||||
is_mutable: bool,
|
pub is_mutable: bool,
|
||||||
identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
declared_type: Option<TypeUse>,
|
pub declared_type: Option<TypeUse>,
|
||||||
initializer: Option<Expression>,
|
pub initializer: Option<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
29
src/ast/named.rs
Normal file
29
src/ast/named.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use crate::ast::{FullyQualifiedName, Identifier};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
pub trait Named {
|
||||||
|
fn name(&self) -> Cow<'_, str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for Identifier {
|
||||||
|
fn name(&self) -> Cow<'_, str> {
|
||||||
|
Cow::Borrowed(&self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for FullyQualifiedName {
|
||||||
|
fn name(&self) -> Cow<'_, str> {
|
||||||
|
if self.identifiers.len() == 1 {
|
||||||
|
self.identifiers[0].name()
|
||||||
|
} else {
|
||||||
|
let mut acc = String::new();
|
||||||
|
for (i, identifier) in self.identifiers.iter().enumerate() {
|
||||||
|
acc += &identifier.name();
|
||||||
|
if i < self.identifiers.len() - 1 {
|
||||||
|
acc += "::";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cow::Owned(acc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -74,7 +74,7 @@ impl PrettyPrint for FullyQualifiedName {
|
|||||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||||
writer.writeln_indented("FullyQualifiedName")?;
|
writer.writeln_indented("FullyQualifiedName")?;
|
||||||
writer.increase_indent();
|
writer.increase_indent();
|
||||||
for identifier in &self.0 {
|
for identifier in &self.identifiers {
|
||||||
identifier.pretty_print(writer)?;
|
identifier.pretty_print(writer)?;
|
||||||
}
|
}
|
||||||
writer.decrease_indent();
|
writer.decrease_indent();
|
||||||
|
@ -147,7 +147,7 @@ impl ListUnparse for FullyQualifiedName {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn inner(&self) -> Vec<&dyn Unparse> {
|
fn inner(&self) -> Vec<&dyn Unparse> {
|
||||||
to_unparse_vec!(self.0)
|
to_unparse_vec!(self.identifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
mod name_analysis;
|
||||||
mod p3;
|
mod p3;
|
||||||
mod unparse;
|
mod unparse;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::name_analysis::name_analysis;
|
||||||
use crate::p3::pretty_print_parse;
|
use crate::p3::pretty_print_parse;
|
||||||
use crate::unparse::unparse;
|
use crate::unparse::unparse;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
@ -24,6 +26,9 @@ enum Commands {
|
|||||||
P3 {
|
P3 {
|
||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
},
|
},
|
||||||
|
NameAnalysis {
|
||||||
|
paths: Vec<PathBuf>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -39,5 +44,10 @@ fn main() {
|
|||||||
pretty_print_parse(&path)
|
pretty_print_parse(&path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Commands::NameAnalysis { paths } => {
|
||||||
|
for path in paths {
|
||||||
|
name_analysis(&path)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
src/bin/dmc/name_analysis.rs
Normal file
36
src/bin/dmc/name_analysis.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use deimos::ast::build::build_ast;
|
||||||
|
use deimos::compile::name_analysis::{analyze_names, SymbolTable};
|
||||||
|
use deimos::parser::{DeimosParser, Rule};
|
||||||
|
use pest::Parser;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub fn name_analysis(path: &Path) {
|
||||||
|
let src = std::fs::read_to_string(path).unwrap();
|
||||||
|
let parse_result = DeimosParser::parse(
|
||||||
|
Rule::CompilationUnit,
|
||||||
|
&src
|
||||||
|
);
|
||||||
|
match parse_result {
|
||||||
|
Ok(mut pairs) => {
|
||||||
|
let compilation_unit_pair = pairs.next().unwrap();
|
||||||
|
let mut compilation_unit = build_ast(compilation_unit_pair);
|
||||||
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let name_analysis_result = analyze_names(
|
||||||
|
&mut compilation_unit,
|
||||||
|
&mut symbol_table,
|
||||||
|
);
|
||||||
|
match name_analysis_result {
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
|
println!("name_analysis complete");
|
||||||
|
println!("{}", symbol_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/compile/mod.rs
Normal file
1
src/compile/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod name_analysis;
|
450
src/compile/name_analysis.rs
Normal file
450
src/compile/name_analysis.rs
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
use crate::ast::named::Named;
|
||||||
|
use crate::ast::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Symbol {
|
||||||
|
Function(FunctionSymbol),
|
||||||
|
Variable(VariableSymbol),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Symbol {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
use Symbol::*;
|
||||||
|
match self {
|
||||||
|
Function(function_symbol) => write!(f, "{}", function_symbol),
|
||||||
|
Variable(variable_symbol) => write!(f, "{}", variable_symbol),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FunctionSymbol {
|
||||||
|
pub fqn: String,
|
||||||
|
pub declared_name: String,
|
||||||
|
pub is_public: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for FunctionSymbol {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"FunctionSymbol(fqn = {}, declared_name = {}, is_public = {})",
|
||||||
|
self.fqn, self.declared_name, self.is_public
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VariableSymbol {
|
||||||
|
pub name: String,
|
||||||
|
pub is_mutable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for VariableSymbol {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"VariableSymbol(name = {}, is_mutable = {})",
|
||||||
|
self.name, self.is_mutable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Scope {
|
||||||
|
parent: Option<usize>,
|
||||||
|
symbols: HashMap<String, Symbol>,
|
||||||
|
debug_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SymbolTable {
|
||||||
|
scopes: Vec<Scope>,
|
||||||
|
current_scope_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains a vec of scopes, like a flattened tree
|
||||||
|
impl SymbolTable {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut t = SymbolTable::default();
|
||||||
|
t.scopes.push(Scope::default());
|
||||||
|
t.current_scope_id = 0;
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_scope_id(&self) -> usize {
|
||||||
|
self.current_scope_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_scope(&mut self, debug_name: &str) {
|
||||||
|
let id = self.scopes.len();
|
||||||
|
self.scopes.push(Scope {
|
||||||
|
symbols: HashMap::new(),
|
||||||
|
parent: Some(self.current_scope_id),
|
||||||
|
debug_name: debug_name.to_string(),
|
||||||
|
});
|
||||||
|
self.current_scope_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_scope(&mut self) {
|
||||||
|
if let Some(parent_id) = self.scopes[self.current_scope_id].parent {
|
||||||
|
self.current_scope_id = parent_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, name: String, symbol: Symbol) -> Result<(), String> {
|
||||||
|
if let Some(current_symbol) = self.scopes[self.current_scope_id].symbols.get(&name) {
|
||||||
|
Err(format!("Symbol '{}' already defined", current_symbol))
|
||||||
|
} else {
|
||||||
|
self.scopes[self.current_scope_id]
|
||||||
|
.symbols
|
||||||
|
.insert(name, symbol);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, String> {
|
||||||
|
let mut scope_opt = Some(&self.scopes[scope_id]);
|
||||||
|
while let Some(scope) = scope_opt {
|
||||||
|
if let Some(symbol) = scope.symbols.get(name) {
|
||||||
|
return Ok(symbol);
|
||||||
|
}
|
||||||
|
scope_opt = if let Some(parent_id) = scope.parent {
|
||||||
|
Some(&self.scopes[parent_id])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(format!("Symbol '{}' not found", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SymbolTable {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
for (i, scope) in self.scopes.iter().enumerate() {
|
||||||
|
writeln!(f, "Scope {} {}", i, scope.debug_name)?;
|
||||||
|
for (name, symbol) in &scope.symbols {
|
||||||
|
writeln!(f, " {}({})", name, symbol)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FqnContext {
|
||||||
|
stack: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FqnContext {
|
||||||
|
fn new() -> Self {
|
||||||
|
FqnContext { stack: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, name: String) {
|
||||||
|
self.stack.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) {
|
||||||
|
self.stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current(&self) -> String {
|
||||||
|
let mut acc = String::new();
|
||||||
|
for (i, name) in self.stack.iter().enumerate() {
|
||||||
|
acc.push_str(name);
|
||||||
|
if i != self.stack.len() - 1 {
|
||||||
|
acc.push_str("::")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(&self, name: &str) -> String {
|
||||||
|
let mut acc = String::new();
|
||||||
|
if !self.stack.is_empty() {
|
||||||
|
acc.push_str(&self.current());
|
||||||
|
acc.push_str("::");
|
||||||
|
}
|
||||||
|
acc.push_str(name);
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn analyze_names(
|
||||||
|
compilation_unit: &mut CompilationUnit,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let mut fqn_context = FqnContext::new();
|
||||||
|
if let Some(namespace) = &compilation_unit.namespace {
|
||||||
|
fqn_context.push(namespace.name().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
for declaration in &mut compilation_unit.declarations {
|
||||||
|
gather_module_level_declaration(declaration, symbol_table, &mut fqn_context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(symbol_table.current_scope_id, 0);
|
||||||
|
|
||||||
|
for declaration in &mut compilation_unit.declarations {
|
||||||
|
resolve_module_level_declaration(declaration, symbol_table)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_module_level_declaration(
|
||||||
|
declaration: &mut ModuleLevelDeclaration,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use ModuleLevelDeclaration::*;
|
||||||
|
match declaration {
|
||||||
|
Function(function_definition) => {
|
||||||
|
gather_function_definition(function_definition, symbol_table, fqn_context)
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_function_definition(
|
||||||
|
function: &mut FunctionDefinition,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let declared_name = function.identifier.name().to_string();
|
||||||
|
let resolved_name = fqn_context.resolve(&declared_name);
|
||||||
|
symbol_table.insert(
|
||||||
|
declared_name.clone(),
|
||||||
|
Symbol::Function(FunctionSymbol {
|
||||||
|
fqn: resolved_name.clone(),
|
||||||
|
declared_name,
|
||||||
|
is_public: function.is_public,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
function
|
||||||
|
.identifier
|
||||||
|
.set_scope_id(symbol_table.current_scope_id());
|
||||||
|
symbol_table.push_scope(&format!("FunctionScope({})", resolved_name));
|
||||||
|
// TODO: params
|
||||||
|
gather_function_body(&mut function.body, symbol_table, fqn_context)?;
|
||||||
|
symbol_table.pop_scope();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_function_body(
|
||||||
|
function_body: &mut FunctionBody,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use FunctionBody::*;
|
||||||
|
match function_body {
|
||||||
|
Block(block) => gather_block_statement(block, symbol_table, fqn_context),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_block_statement(
|
||||||
|
block: &mut BlockStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
symbol_table.push_scope("BlockStatementScope");
|
||||||
|
for statement in &mut block.statements {
|
||||||
|
gather_statement(statement, symbol_table, fqn_context)?;
|
||||||
|
}
|
||||||
|
symbol_table.pop_scope();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_statement(
|
||||||
|
statement: &mut Statement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use Statement::*;
|
||||||
|
match statement {
|
||||||
|
BlockStatement(block) => gather_block_statement(block, symbol_table, fqn_context),
|
||||||
|
VariableDeclarationStatement(variable_declaration) => {
|
||||||
|
gather_variable_declaration(variable_declaration, symbol_table, fqn_context)
|
||||||
|
}
|
||||||
|
AssignStatement(assign_statement) => {
|
||||||
|
gather_assign_statement(assign_statement, symbol_table, fqn_context)
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_variable_declaration(
|
||||||
|
variable_declaration: &mut VariableDeclarationStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let variable_name = variable_declaration.identifier.name().to_string();
|
||||||
|
symbol_table.insert(
|
||||||
|
variable_name.clone(),
|
||||||
|
Symbol::Variable(VariableSymbol {
|
||||||
|
name: variable_name,
|
||||||
|
is_mutable: variable_declaration.is_mutable,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
variable_declaration
|
||||||
|
.identifier
|
||||||
|
.set_scope_id(symbol_table.current_scope_id());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_assign_statement(
|
||||||
|
assign_statement: &mut AssignStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
gather_expression(&mut assign_statement.lhs, symbol_table, fqn_context)?;
|
||||||
|
gather_expression(&mut assign_statement.rhs, symbol_table, fqn_context)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_expression(
|
||||||
|
expression: &mut Expression,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use Expression::*;
|
||||||
|
match expression {
|
||||||
|
FullyQualifiedName(fully_qualified_name) => {
|
||||||
|
gather_fully_qualified_name(fully_qualified_name, symbol_table, fqn_context)?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gather_fully_qualified_name(
|
||||||
|
fully_qualified_name: &mut FullyQualifiedName,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
fqn_context: &mut FqnContext,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
fully_qualified_name.set_scope_id(symbol_table.current_scope_id());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve */
|
||||||
|
|
||||||
|
fn resolve_module_level_declaration(
|
||||||
|
declaration: &mut ModuleLevelDeclaration,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use ModuleLevelDeclaration::*;
|
||||||
|
match declaration {
|
||||||
|
Function(function_definition) => {
|
||||||
|
resolve_function_definition(function_definition, symbol_table)
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_function_definition(
|
||||||
|
function_definition: &mut FunctionDefinition,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
resolve_function_body(&mut function_definition.body, symbol_table)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_function_body(
|
||||||
|
function_body: &mut FunctionBody,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use FunctionBody::*;
|
||||||
|
match function_body {
|
||||||
|
Block(block) => resolve_block(block, symbol_table),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_block(
|
||||||
|
block_statement: &mut BlockStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
for statement in &mut block_statement.statements {
|
||||||
|
resolve_statement(statement, symbol_table)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_statement(
|
||||||
|
statement: &mut Statement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use Statement::*;
|
||||||
|
match statement {
|
||||||
|
BlockStatement(block) => resolve_block(block, symbol_table),
|
||||||
|
VariableDeclarationStatement(variable_declaration) => {
|
||||||
|
resolve_variable_declaration(variable_declaration, symbol_table)
|
||||||
|
}
|
||||||
|
AssignStatement(assign_statement) => {
|
||||||
|
resolve_assign_statement(assign_statement, symbol_table)
|
||||||
|
}
|
||||||
|
CallStatement(call_statement) => resolve_call_statement(call_statement, symbol_table),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_variable_declaration(
|
||||||
|
variable_declaration: &mut VariableDeclarationStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if let Some(initializer) = &mut variable_declaration.initializer {
|
||||||
|
resolve_expression(initializer, symbol_table)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_assign_statement(
|
||||||
|
assign_statement: &mut AssignStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
resolve_expression(&mut assign_statement.lhs, symbol_table)?;
|
||||||
|
resolve_expression(&mut assign_statement.rhs, symbol_table)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_call_statement(
|
||||||
|
call_statement: &mut CallStatement,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
resolve_expression(&mut call_statement.0, symbol_table)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_expression(
|
||||||
|
expression: &mut Expression,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
use Expression::*;
|
||||||
|
match expression {
|
||||||
|
FullyQualifiedName(fqn) => resolve_fully_qualified_name(fqn, symbol_table),
|
||||||
|
Literal(_) => Ok(()),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_fully_qualified_name(
|
||||||
|
fully_qualified_name: &mut FullyQualifiedName,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let lookup_result = symbol_table.lookup(
|
||||||
|
fully_qualified_name.name().as_ref(),
|
||||||
|
fully_qualified_name.scope_id().expect(&format!(
|
||||||
|
"FullyQualifiedName has no scope_id set: {:?}",
|
||||||
|
fully_qualified_name
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
match lookup_result {
|
||||||
|
Ok(symbol) => {
|
||||||
|
fully_qualified_name.set_symbol(symbol.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
|
pub mod compile;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod object_file;
|
pub mod object_file;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
Loading…
Reference in New Issue
Block a user