Skip to content

Commit

Permalink
Start prototyping a resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
DCNick3 committed Jul 6, 2023
1 parent ed26bb4 commit c6c203d
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 1 deletion.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions shin-asm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ shin-derive = { path = "../shin-derive" }

assert_matches = "1.5.0"

rustc-hash = "1.1.0"
smol_str = "0.2.0"
internment = { version = "0.7.0", features = ["arena"] }

unicode-xid = "0.2.4"
unic-emoji-char = "0.9.0"

Expand Down
60 changes: 60 additions & 0 deletions shin-asm/src/file_db/in_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::file_db::{FileDb, FileId};
use crate::syntax;
use either::Either;

/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
///
/// Typical usages are:
///
/// * `InFile<SyntaxNode>` -- syntax node in a file
/// * `InFile<ast::FnDef>` -- ast node in a file
/// * `InFile<TextSize>` -- offset in a file
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct InFile<T> {
pub file_id: FileId,
pub value: T,
}

impl<T> InFile<T> {
pub fn new(file_id: FileId, value: T) -> InFile<T> {
InFile { file_id, value }
}

pub fn with_value<U>(&self, value: U) -> InFile<U> {
InFile::new(self.file_id, value)
}

pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U> {
InFile::new(self.file_id, f(self.value))
}

pub fn as_ref(&self) -> InFile<&T> {
self.with_value(&self.value)
}

pub fn file_syntax(&self, db: &FileDb) -> syntax::Parse<syntax::SourceFile> {
db.parse(self.file_id)
}
}

impl<T: Clone> InFile<&T> {
pub fn cloned(&self) -> InFile<T> {
self.with_value(self.value.clone())
}
}

impl<T> InFile<Option<T>> {
pub fn transpose(self) -> Option<InFile<T>> {
let value = self.value?;
Some(InFile::new(self.file_id, value))
}
}

impl<L, R> InFile<Either<L, R>> {
pub fn transpose(self) -> Either<InFile<L>, InFile<R>> {
match self.value {
Either::Left(l) => Either::Left(InFile::new(self.file_id, l)),
Either::Right(r) => Either::Right(InFile::new(self.file_id, r)),
}
}
}
88 changes: 88 additions & 0 deletions shin-asm/src/file_db/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::syntax;
use rustc_hash::FxHashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::num::NonZeroU16;

mod in_file;

pub use in_file::InFile;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FileId(NonZeroU16);

pub struct File {
path: String,
contents: String,
}

impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// exclude contents from debug output
f.debug_struct("File").field("path", &self.path).finish()
}
}

impl fmt::Display for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "File@{}", self.path)
}
}

#[derive(Default)]
pub struct FileDb {
files: FxHashMap<FileId, File>,
files_by_path: FxHashMap<String, FileId>,
seq_id: u16,
}

impl FileDb {
pub fn new() -> Self {
FileDb {
files: FxHashMap::default(),
files_by_path: FxHashMap::default(),
seq_id: 0,
}
}

pub fn single_file(path: String, contents: String) -> Self {
let mut db = Self::new();
db.add_file(path, contents);
db
}

pub fn file(&self, id: FileId) -> &File {
self.files.get(&id).unwrap()
}

pub fn file_id_by_path(&self, path: &str) -> Option<FileId> {
self.files_by_path.get(path).copied()
}

pub fn files(&self) -> impl Iterator<Item = FileId> + '_ {
self.files.keys().copied()
}

pub fn parse(&self, file_id: FileId) -> syntax::Parse<syntax::SourceFile> {
let file = self.file(file_id);
// TODO: use salsa or smth
syntax::SourceFile::parse(&file.contents)
}

pub fn add_file(&mut self, path: String, contents: String) -> FileId {
self.seq_id = self.seq_id.checked_add(1).unwrap();
let id = FileId(NonZeroU16::new(self.seq_id).unwrap());
match self.files_by_path.entry(path.clone()) {
Entry::Occupied(_) => {
todo!("handle file already exists")
}
Entry::Vacant(entry) => {
entry.insert(id);

self.files.insert(id, File { path, contents });

id
}
}
}
}
2 changes: 2 additions & 0 deletions shin-asm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// macro hack
extern crate self as shin_asm;

pub mod file_db;
pub mod parser;
pub mod symbols;
pub mod syntax;
76 changes: 76 additions & 0 deletions shin-asm/src/symbols/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
mod resolve;

use crate::file_db::InFile;
use rustc_hash::FxHashMap;
use smol_str::SmolStr;
use std::fmt;
use std::sync::Arc;

/// Reference to a function or a label within a file
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum CodeRef {
Function {
/// Index of the function item
item_index: u32,
},
Label {
/// Index of the block or function item
item_index: u32,
/// Index of the label within the block or function item
///
/// it's `u16` to make the `CodeRef` fit into 64 bits
label_index: u16,
},
}

/// This is a compile-time check that `CodeRef` fits into 64 bits
const _: () = [(); 1][(core::mem::size_of::<CodeRef>() == 8) as usize ^ 1];

// this size is a little sad, but I don't know how to make it smaller
const _: () = [(); 1][(core::mem::size_of::<InFile<CodeRef>>() == 12) as usize ^ 1];

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum SymbolValue {
Number(i32),
CodeRef(InFile<CodeRef>),
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum RegisterName {
A(u16),
V(u16),
}

impl fmt::Display for RegisterName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (prefix, i) = match self {
RegisterName::A(i) => ("a", i),
RegisterName::V(i) => ("v", i),
};
write!(f, "${}{}", prefix, i)
}
}

pub struct Scope {
parent: Option<Arc<Scope>>,
symbols: FxHashMap<SmolStr, SymbolValue>,
registers: FxHashMap<SmolStr, RegisterName>,
}

impl Scope {
pub fn resolve_symbol(&self, name: &str) -> Option<SymbolValue> {
self.symbols.get(name).copied().or_else(|| {
self.parent
.as_ref()
.and_then(|parent| parent.resolve_symbol(name))
})
}

pub fn resolve_register(&self, name: &str) -> Option<RegisterName> {
self.registers.get(name).copied().or_else(|| {
self.parent
.as_ref()
.and_then(|parent| parent.resolve_register(name))
})
}
}
Loading

0 comments on commit c6c203d

Please sign in to comment.