Add primitive type uses and related.

This commit is contained in:
Jesse Brault 2025-05-19 13:52:42 -05:00
parent abb7aab3a4
commit 0c2d9f8b2f
13 changed files with 242 additions and 131 deletions

View File

@ -1,11 +1,5 @@
ns greeter;
class Array<T> {}
class String {}
platform fn println(msg: Any) -> Void;
fn main(args: Array<String>) {
println(args);
}

View File

@ -0,0 +1,7 @@
ns std::core;
class Array<T> {}
class String {}
platform fn println(msg: Any) -> Void;

View File

@ -55,7 +55,9 @@ fn build_fqn(file_id: usize, fqn_pair: Pair<Rule>) -> FullyQualifiedName {
fn build_type_use(file_id: usize, type_use_pair: Pair<Rule>) -> TypeUse {
let inner_pair = type_use_pair.into_inner().next().unwrap();
match inner_pair.as_rule() {
Rule::Void => TypeUse::Void,
Rule::PrimitiveType => {
TypeUse::Primitive(build_primitive_type(file_id, inner_pair))
},
Rule::InterfaceOrClassTypeUse => {
TypeUse::InterfaceOrClass(build_interface_or_class_type_use(file_id, inner_pair))
}
@ -65,6 +67,35 @@ fn build_type_use(file_id: usize, type_use_pair: Pair<Rule>) -> TypeUse {
}
}
fn build_primitive_type(
file_id: usize,
primitive_type_pair: Pair<Rule>,
) -> PrimitiveTypeUse {
let mut inner = primitive_type_pair.into_inner();
match inner.next().unwrap().as_rule() {
Rule::Byte => PrimitiveTypeUse::Byte,
Rule::Short => PrimitiveTypeUse::Short,
Rule::Char => PrimitiveTypeUse::Char,
Rule::Int => PrimitiveTypeUse::Int,
Rule::Long => PrimitiveTypeUse::Long,
Rule::Double => PrimitiveTypeUse::Double,
Rule::Bool => PrimitiveTypeUse::Bool,
Rule::String => PrimitiveTypeUse::String,
Rule::Array => {
if let Some(generic_arguments_pair) = inner.next() {
PrimitiveTypeUse::Array(
Some(Box::new(build_generic_arguments(file_id, generic_arguments_pair)))
)
} else {
PrimitiveTypeUse::Array(None)
}
}
Rule::Any => PrimitiveTypeUse::Any,
Rule::Void => PrimitiveTypeUse::Void,
_ => unreachable!(),
}
}
fn build_interface_or_class_type_use(file_id: usize, pair: Pair<Rule>) -> InterfaceOrClassTypeUse {
let mut borrow_count = 0;
let mut is_mutable = false;

View File

@ -93,7 +93,7 @@ impl Identifier {
pub fn set_saved_symbol(&mut self, saved_symbol: SavedSymbol) {
self.saved_symbol = Some(saved_symbol);
}
pub fn saved_symbol(&self) -> Option<SavedSymbol> {
self.saved_symbol.clone()
}
@ -140,12 +140,27 @@ impl FullyQualifiedName {
#[derive(Debug)]
pub enum TypeUse {
Void,
Primitive(PrimitiveTypeUse),
InterfaceOrClass(InterfaceOrClassTypeUse),
Tuple(TupleTypeUse),
Function(FunctionTypeUse),
}
#[derive(Debug)]
pub enum PrimitiveTypeUse {
Byte,
Short,
Char,
Int,
Long,
Double,
Bool,
String,
Array(Option<Box<GenericArguments>>),
Any,
Void,
}
#[derive(Debug)]
pub struct InterfaceOrClassTypeUse {
pub borrow_count: usize,
@ -270,7 +285,7 @@ pub struct ReturnType {
impl ReturnType {
pub fn void() -> Self {
ReturnType {
declared_type: Box::new(TypeUse::Void),
declared_type: Box::new(TypeUse::Primitive(PrimitiveTypeUse::Void)),
references: References::default(),
}
}

View File

@ -7,6 +7,7 @@ use deimos::name_analysis::symbol_table::SymbolTable;
use deimos::parser::{DeimosParser, Rule};
use pest::Parser;
use std::path::PathBuf;
use deimos::std_core::add_std_core_symbols;
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
let mut compilation_units = vec![];
@ -29,6 +30,7 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
}
let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table);
if diagnostics.is_empty() {

View File

@ -6,6 +6,6 @@ pub mod module;
pub mod name_analysis;
pub mod object_file;
pub mod parser;
mod std_core;
pub mod std_core;
pub mod util;
pub mod vm;

View File

@ -60,7 +60,21 @@ fn gather_type_use(
diagnostics: &mut Vec<DmDiagnostic>,
) {
match type_use {
TypeUse::Void => {}
TypeUse::Primitive(primitive_type_use) => {
match primitive_type_use {
PrimitiveTypeUse::Array(generic_arguments_opt) => {
if let Some(generic_arguments) = generic_arguments_opt {
gather_generic_arguments(
generic_arguments,
symbol_table,
fqn_context,
diagnostics,
);
}
}
_ => {}
}
}
TypeUse::InterfaceOrClass(interface_or_class_type_use) => {
gather_interface_or_class_type_use(
interface_or_class_type_use,

View File

@ -43,7 +43,7 @@ mod tests {
use pest::Parser;
use std::collections::HashMap;
fn assert_no_diagnostics(sources: HashMap<&str, &str>) -> SymbolTable {
fn assert_no_diagnostics(sources: HashMap<&str, &str>, symbol_table: &mut SymbolTable) {
let mut files = SimpleFiles::new();
let mut compilation_units = vec![];
@ -61,10 +61,7 @@ mod tests {
compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap()))
}
let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std_core_symbols");
let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table);
let diagnostics = analyze_names(&mut compilation_units, symbol_table);
if !diagnostics.is_empty() {
let writer = StandardStream::stderr(ColorChoice::Always);
@ -81,8 +78,6 @@ mod tests {
for compilation_unit in &compilation_units {
dbg!(compilation_unit);
}
symbol_table
}
#[test]
@ -95,7 +90,7 @@ mod tests {
}"},
)]);
assert_no_diagnostics(sources);
assert_no_diagnostics(sources, &mut SymbolTable::new());
}
#[test]
@ -117,7 +112,7 @@ mod tests {
),
]);
assert_no_diagnostics(sources);
assert_no_diagnostics(sources, &mut SymbolTable::new());
}
#[test]
@ -125,12 +120,14 @@ mod tests {
let sources: HashMap<&str, &str> = HashMap::from([(
"main.dm",
indoc! {"
fn main(args: Array<String>) {
println(args)
}
"},
fn main(args: Array<String>) {
println(args)
}
"},
)]);
assert_no_diagnostics(sources);
let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
assert_no_diagnostics(sources, &mut symbol_table);
}
}

View File

@ -43,7 +43,20 @@ fn resolve_type_use(
diagnostics: &mut Vec<DmDiagnostic>,
) {
match type_use {
TypeUse::Void => {}
TypeUse::Primitive(primitive_type_use) => {
match primitive_type_use {
PrimitiveTypeUse::Array(generic_arguments_opt) => {
if let Some(generic_arguments) = generic_arguments_opt {
resolve_generic_arguments(
generic_arguments,
symbol_table,
diagnostics,
);
}
}
_ => {}
}
}
TypeUse::InterfaceOrClass(interface_or_class_type_use) => {
resolve_interface_or_class_type_use(
interface_or_class_type_use,

View File

@ -1,6 +1,6 @@
use crate::ast::{Identifier, UseStatement};
use std::cell::RefCell;
use std::fmt::Display;
use std::fmt::{Debug, Display, Formatter};
use std::range::Range;
use std::rc::Rc;
@ -80,23 +80,8 @@ impl Symbol {
}
}
impl Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use Symbol::*;
match self {
UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol.borrow()),
Module(module_symbol) => write!(f, "{}", module_symbol),
Type(class_symbol) => write!(f, "{}", class_symbol),
Function(function_symbol) => write!(f, "{}", function_symbol.borrow()),
Parameter(parameter_symbol) => write!(f, "{}", parameter_symbol),
Variable(variable_symbol) => write!(f, "{}", variable_symbol),
}
}
}
/* Use-statement */
#[derive(Debug, Clone)]
pub struct UseStatementSymbol {
pub fqn: String,
pub declared_name: String,
@ -137,19 +122,18 @@ impl SymbolInner for UseStatementSymbol {
}
}
impl Display for UseStatementSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"UseStatementSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name
)
impl Debug for UseStatementSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UseStatementSymbol")
.field("fqn", &self.fqn)
.field("declared_name", &self.declared_name)
.field("referenced_symbol", &self.referenced_symbol)
.finish()
}
}
/* Module */
#[derive(Debug)]
pub struct ModuleSymbol {
fqn: String,
declared_name: String,
@ -183,19 +167,18 @@ impl SymbolInner for ModuleSymbol {
}
}
impl Display for ModuleSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"ModuleSymbol(name = {}, is_public = {})",
self.fqn, self.is_public
)
impl Debug for ModuleSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ModuleSymbol")
.field("fqn", &self.fqn)
.field("declared_name", &self.declared_name)
.field("is_public", &self.is_public)
.finish()
}
}
/* Class */
/* TypeSymbol */
#[derive(Debug)]
pub struct TypeSymbol {
fqn: String,
declared_name: String,
@ -237,19 +220,18 @@ impl SymbolInner for TypeSymbol {
}
}
impl Display for TypeSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"TypeSymbol(fqn = {}, declared_name = {})",
self.fqn, self.declared_name
)
impl Debug for TypeSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TypeSymbol")
.field("fqn", &self.fqn)
.field("declared_name", &self.declared_name)
.field("is_public", &self.is_public)
.finish()
}
}
/* Function */
#[derive(Debug)]
pub struct FunctionSymbol {
fqn: String,
declared_name: String,
@ -278,7 +260,7 @@ impl FunctionSymbol {
return_type: None,
}
}
pub fn with_parameters(self, parameters: Vec<ParameterSymbol>) -> Self {
Self {
fqn: self.fqn,
@ -286,11 +268,14 @@ impl FunctionSymbol {
is_public: self.is_public,
is_platform: self.is_platform,
definition: self.definition,
parameters: parameters.into_iter().map(|parameter| Rc::new(parameter)).collect(),
parameters: parameters
.into_iter()
.map(|parameter| Rc::new(parameter))
.collect(),
return_type: self.return_type,
}
}
pub fn with_return_type(self, return_type: TypeSymbol) -> Self {
Self {
fqn: self.fqn,
@ -326,19 +311,21 @@ impl SymbolInner for FunctionSymbol {
}
}
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
)
impl Debug for FunctionSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FunctionSymbol")
.field("fqn", &self.fqn)
.field("declared_name", &self.declared_name)
.field("is_public", &self.is_public)
.field("is_platform", &self.is_platform)
.field("parameters", &self.parameters)
.field("return_type", &self.return_type)
.finish()
}
}
/* Parameter */
#[derive(Debug)]
pub struct ParameterSymbol {
declared_name: String,
definition: Option<SourceDefinition>,
@ -363,15 +350,16 @@ impl SymbolInner for ParameterSymbol {
}
}
impl Display for ParameterSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "ParameterSymbol({})", self.declared_name)
impl Debug for ParameterSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParameterSymbol")
.field("declared_name", &self.declared_name)
.finish()
}
}
/* Variable */
#[derive(Debug)]
pub struct VariableSymbol {
declared_name: String,
is_mutable: bool,
@ -398,12 +386,11 @@ impl SymbolInner for VariableSymbol {
}
}
impl Display for VariableSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"VariableSymbol(name = {}, is_mutable = {})",
self.declared_name, self.is_mutable
)
impl Debug for VariableSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VariableSymbol")
.field("declared_name", &self.declared_name)
.field("is_mutable", &self.is_mutable)
.finish()
}
}

View File

@ -1,10 +1,10 @@
use std::cell::RefCell;
use crate::name_analysis::symbol::{
FunctionSymbol, ModuleSymbol, ParameterSymbol, Symbol, SymbolInner, TypeSymbol,
UseStatementSymbol, VariableSymbol,
};
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Display;
use std::rc::Rc;
@ -37,13 +37,34 @@ impl Scope {
}
fn get_any_symbol(&self, name: &str) -> Option<Symbol> {
self.variable_symbols.get(name)
self.variable_symbols
.get(name)
.map(|s| Symbol::Variable(s.clone()))
.or_else(|| self.parameter_symbols.get(name).map(|s| Symbol::Parameter(s.clone())))
.or_else(|| self.function_symbols.get(name).map(|s| Symbol::Function(s.clone())))
.or_else(|| self.type_symbols.get(name).map(|ts| Symbol::Type(ts.clone())))
.or_else(|| self.module_symbols.get(name).map(|ms| Symbol::Module(ms.clone())))
.or_else(|| self.use_statement_symbols.get(name).map(|us| Symbol::UseStatement(us.clone())))
.or_else(|| {
self.parameter_symbols
.get(name)
.map(|s| Symbol::Parameter(s.clone()))
})
.or_else(|| {
self.function_symbols
.get(name)
.map(|s| Symbol::Function(s.clone()))
})
.or_else(|| {
self.type_symbols
.get(name)
.map(|ts| Symbol::Type(ts.clone()))
})
.or_else(|| {
self.module_symbols
.get(name)
.map(|ms| Symbol::Module(ms.clone()))
})
.or_else(|| {
self.use_statement_symbols
.get(name)
.map(|us| Symbol::UseStatement(us.clone()))
})
}
fn get_module_symbol_by_declared_name(&self, name: &str) -> Option<Rc<ModuleSymbol>> {
@ -162,10 +183,9 @@ impl SymbolTable {
let declared_name = use_statement_symbol.declared_name().to_string();
let to_insert = Rc::new(RefCell::new(use_statement_symbol));
let to_return = to_insert.clone();
current_scope.use_statement_symbols.insert(
declared_name,
to_insert,
);
current_scope
.use_statement_symbols
.insert(declared_name, to_insert);
Ok(to_return)
}
}
@ -216,10 +236,9 @@ impl SymbolTable {
let declared_name = function_symbol.declared_name().to_string();
let to_insert = Rc::new(RefCell::new(function_symbol));
let to_return = to_insert.clone();
current_scope.function_symbols.insert(
declared_name,
to_insert
);
current_scope
.function_symbols
.insert(declared_name, to_insert);
Ok(to_return)
}
}
@ -236,10 +255,9 @@ impl SymbolTable {
} else {
let to_insert = Rc::new(parameter_symbol);
let to_return = to_insert.clone();
current_scope.parameter_symbols.insert(
to_insert.declared_name().to_string(),
to_insert,
);
current_scope
.parameter_symbols
.insert(to_insert.declared_name().to_string(), to_insert);
Ok(to_return)
}
}
@ -295,24 +313,24 @@ impl Display for SymbolTable {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?;
for (i, scope) in self.scopes.iter().enumerate() {
writeln!(f, "Scope {} {}", i, scope.debug_name)?;
for (name, symbol) in &scope.use_statement_symbols {
writeln!(f, " {}({})", name, symbol.borrow())?;
writeln!(f, "----Scope {} {}----", i, scope.debug_name)?;
for symbol in scope.use_statement_symbols.values() {
writeln!(f, "{:#?}", symbol.borrow())?;
}
for (name, symbol) in &scope.module_symbols {
writeln!(f, " {}({})", name, symbol)?;
for symbol in scope.module_symbols.values() {
writeln!(f, "{:#?}", symbol)?;
}
for (name, symbol) in &scope.type_symbols {
writeln!(f, " {}({})", name, symbol)?;
for symbol in scope.type_symbols.values() {
writeln!(f, "{:#?}", symbol)?;
}
for (name, symbol) in &scope.function_symbols {
writeln!(f, " {}({})", name, symbol.borrow())?;
for symbol in scope.function_symbols.values() {
writeln!(f, "{:#?}", symbol.borrow())?;
}
for (name, symbol) in &scope.parameter_symbols {
writeln!(f, " {}({})", name, symbol)?;
for symbol in scope.parameter_symbols.values() {
writeln!(f, "{:#?}", symbol)?;
}
for (name, symbol) in &scope.variable_symbols {
writeln!(f, " {}({})", name, symbol)?;
for symbol in scope.variable_symbols.values() {
writeln!(f, "{:#?}", symbol)?;
}
}
Ok(())

View File

@ -2,7 +2,7 @@
Ns = { "ns" }
TypeKw = { "type" }
Mod = { "mod" }
Int = { "int" }
IntKw = { "int" }
ClassKw = { "class" }
Platform = { "platform" }
Pub = { "pub" }
@ -15,7 +15,6 @@ Ref = { "ref" }
Def = { "def" }
Where = { "where" }
Infer = { "infer" }
Void = { "Void" }
Delegate = { "delegate" }
Let = { "let" }
Fn = { "fn" }
@ -32,12 +31,25 @@ True = { "true" }
False = { "false" }
Use = { "use" }
// Keywords: primitive types
Byte = { "Byte" }
Short = { "Short" }
Char = { "Char" }
Int = { "Int" }
Long = { "Long" }
Double = { "Double" }
Bool = { "Bool" }
String = { "String" }
Array = { "Array" }
Any = { "Any" }
Void = { "Void" }
// Keywords as a rule (for preventing identifiers with keywords, etc.)
Keyword = {
Ns
| TypeKw
| Mod
| Int
| IntKw
| ClassKw
| Platform
| Pub
@ -50,7 +62,6 @@ Keyword = {
| Def
| Where
| Infer
| Void
| Delegate
| Let
| Fn
@ -66,6 +77,17 @@ Keyword = {
| True
| False
| Use
| Byte
| Short
| Char
| Int
| Long
| Double
| Bool
| String
| Array
| Any
| Void
}
// Symbols
@ -180,12 +202,26 @@ ParenthesesOptionalTypeUseList = {
// Parameters = declaration
TypeUse = {
Void
PrimitiveType
| InterfaceOrClassTypeUse
| TupleTypeUse
| FunctionTypeUse
}
PrimitiveType = {
Byte
| Short
| Char
| Int
| Long
| Double
| Bool
| String
| Array ~ GenericArguments?
| Any
| Void
}
InterfaceOrClassTypeUse = {
Borrow*
~ Mut?
@ -335,7 +371,7 @@ Module = {
Interface = {
Pub?
~ Int
~ IntKw
~ Identifier
~ GenericParameters?
~ ImplementsList?

View File

@ -2,9 +2,6 @@ use crate::name_analysis::symbol::{FunctionSymbol, ParameterSymbol, TypeSymbol};
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> {
symbol_table.insert_type_symbol(TypeSymbol::new("std::core:Array", "Array", true, None))?;
// todo: make this primitive
symbol_table.insert_type_symbol(TypeSymbol::new("std::core::String", "String", true, None))?;
symbol_table.insert_function_symbol(
FunctionSymbol::new("std::core::println", "println", true, true, None)
.with_parameters(vec![ParameterSymbol::new("msg", None)]),