Skip to content

Commit

Permalink
Merge pull request #5 from Rigidity/stdlib-module-init
Browse files Browse the repository at this point in the history
Initial implementation of stdlib and modules
  • Loading branch information
Rigidity authored Jun 23, 2024
2 parents f03ce56 + aacbe4f commit 08816b4
Show file tree
Hide file tree
Showing 31 changed files with 956 additions and 338 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ trivial_casts = "deny"
trivial_numeric_casts = "deny"
unreachable_code = "warn"
unreachable_patterns = "deny"
dead_code = "deny"
dead_code = "warn"
deprecated = "deny"
deprecated_in_future = "deny"
missing_debug_implementations = "warn"
Expand Down
83 changes: 47 additions & 36 deletions crates/rue-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fs;

use clap::Parser;
use clvmr::{run_program, serde::node_to_bytes, Allocator, ChiaDialect, NodePtr};
use rue_compiler::{compile, DiagnosticKind};
use rue_compiler::{analyze, compile, Diagnostic, DiagnosticKind};
use rue_parser::{line_col, parse, LineCol};

/// The Rue language compiler and toolchain.
Expand All @@ -11,6 +11,10 @@ use rue_parser::{line_col, parse, LineCol};
struct Args {
/// The source file to compile.
file: String,

/// Whether to only analyze.
#[clap(long, short)]
analyze: bool,
}

fn main() {
Expand All @@ -27,46 +31,53 @@ fn main() {
eprintln!("{} at {line}:{col}", error.kind());
}

let mut allocator = Allocator::new();
let output = compile(&mut allocator, &ast, errors.is_empty());

if !output.diagnostics().is_empty() {
let mut has_error = false;
if args.analyze {
let diagnostics = analyze(&ast);
print_diagnostics(&source, &diagnostics);
} else {
let mut allocator = Allocator::new();
let output = compile(&mut allocator, &ast, errors.is_empty());

for error in output.diagnostics() {
let LineCol { line, col } = line_col(&source, error.span().start);
let line = line + 1;
let col = col + 1;

match error.kind() {
DiagnosticKind::Error(kind) => {
has_error = true;
eprintln!("Error: {kind} at {line}:{col}");
}
DiagnosticKind::Warning(kind) => {
eprintln!("Warning: {kind} at {line}:{col}");
}
}
if print_diagnostics(&source, output.diagnostics()) {
return;
}

if has_error {
return;
let bytes = node_to_bytes(&allocator, output.node_ptr()).unwrap();
println!("{}", hex::encode(bytes));
match run_program(
&mut allocator,
&ChiaDialect::new(0),
output.node_ptr(),
NodePtr::NIL,
0,
) {
Ok(output) => eprintln!(
"Serialized output: {}",
hex::encode(node_to_bytes(&allocator, output.1).unwrap())
),
Err(error) => eprintln!("Error: {error:?}"),
}
}
}

fn print_diagnostics(source: &str, diagnostics: &[Diagnostic]) -> bool {
let mut has_error = false;

let bytes = node_to_bytes(&allocator, output.node_ptr()).unwrap();
println!("{}", hex::encode(bytes));
match run_program(
&mut allocator,
&ChiaDialect::new(0),
output.node_ptr(),
NodePtr::NIL,
0,
) {
Ok(output) => eprintln!(
"Serialized output: {}",
hex::encode(node_to_bytes(&allocator, output.1).unwrap())
),
Err(error) => eprintln!("Error: {error:?}"),
for error in diagnostics {
let LineCol { line, col } = line_col(source, error.span().start);
let line = line + 1;
let col = col + 1;

match error.kind() {
DiagnosticKind::Error(kind) => {
has_error = true;
eprintln!("Error: {kind} at {line}:{col}");
}
DiagnosticKind::Warning(kind) => {
eprintln!("Warning: {kind} at {line}:{col}");
}
}
}

has_error
}
22 changes: 14 additions & 8 deletions crates/rue-compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::collections::HashMap;

pub(crate) use builtins::{builtins, Builtins};
pub(crate) use builtins::Builtins;
use indexmap::IndexSet;
use rowan::TextRange;
use symbol_table::SymbolTable;
Expand All @@ -17,12 +17,17 @@ use crate::{

mod block;
mod builtins;
mod context;
mod expr;
mod item;
mod path;
mod stmt;
mod symbol_table;
mod ty;
mod unused;

#[cfg(test)]
pub use builtins::*;
pub use context::*;

/// Responsible for lowering the AST into the HIR.
/// Performs name resolution and type checking.
Expand Down Expand Up @@ -54,14 +59,10 @@ pub struct Compiler<'a> {
}

impl<'a> Compiler<'a> {
pub fn new(db: &'a mut Database) -> Self {
let mut builtin_scope = Scope::default();
let builtins = builtins(db, &mut builtin_scope);
let builtins_id = db.alloc_scope(builtin_scope);

pub fn new(db: &'a mut Database, builtins: Builtins) -> Self {
Self {
db,
scope_stack: vec![builtins_id],
scope_stack: vec![builtins.scope_id],
symbol_stack: Vec::new(),
type_definition_stack: Vec::new(),
type_guard_stack: Vec::new(),
Expand Down Expand Up @@ -266,6 +267,11 @@ impl<'a> Compiler<'a> {
None
}

fn scope(&self) -> &Scope {
self.db
.scope(self.scope_stack.last().copied().expect("no scope found"))
}

fn scope_mut(&mut self) -> &mut Scope {
self.db
.scope_mut(self.scope_stack.last().copied().expect("no scope found"))
Expand Down
18 changes: 14 additions & 4 deletions crates/rue-compiler/src/compiler/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ use crate::{
scope::Scope,
symbol::{Function, Symbol},
ty::{FunctionType, Rest, Type},
Database, HirId, SymbolId, TypeId,
Database, HirId, ScopeId, SymbolId, TypeId,
};

/// These are the built-in types and most commonly used HIR nodes.
pub struct Builtins {
pub scope_id: ScopeId,
pub any: TypeId,
pub int: TypeId,
pub bool: TypeId,
Expand All @@ -21,7 +22,9 @@ pub struct Builtins {
}

/// Defines intrinsics that cannot be implemented in Rue.
pub fn builtins(db: &mut Database, scope: &mut Scope) -> Builtins {
pub fn builtins(db: &mut Database) -> Builtins {
let mut scope = Scope::default();

let int = db.alloc_type(Type::Int);
let bool = db.alloc_type(Type::Bool);
let bytes = db.alloc_type(Type::Bytes);
Expand All @@ -42,6 +45,7 @@ pub fn builtins(db: &mut Database, scope: &mut Scope) -> Builtins {
scope.define_type("Any".to_string(), any);

let builtins = Builtins {
scope_id: db.alloc_scope(scope),
any,
int,
bool,
Expand All @@ -54,8 +58,14 @@ pub fn builtins(db: &mut Database, scope: &mut Scope) -> Builtins {
unknown_hir,
};

scope.define_symbol("sha256".to_string(), sha256(db, &builtins));
scope.define_symbol("pubkey_for_exp".to_string(), pubkey_for_exp(db, &builtins));
let sha256 = sha256(db, &builtins);
let pubkey_for_exp = pubkey_for_exp(db, &builtins);

db.scope_mut(builtins.scope_id)
.define_symbol("sha256".to_string(), sha256);

db.scope_mut(builtins.scope_id)
.define_symbol("pubkey_for_exp".to_string(), pubkey_for_exp);

builtins
}
Expand Down
146 changes: 146 additions & 0 deletions crates/rue-compiler/src/compiler/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::collections::HashSet;

use clvmr::{Allocator, NodePtr};
use indexmap::IndexMap;
use rue_parser::{parse, Root};

use crate::{
codegen::Codegen,
optimizer::{DependencyGraph, Optimizer},
scope::Scope,
symbol::{Module, Symbol},
ty::Type,
Database, SymbolId,
};

use super::{builtins::builtins, item::Declarations, symbol_table::SymbolTable, Compiler};

pub struct CompilerContext<'a> {
compiler: Compiler<'a>,
roots: IndexMap<SymbolId, (Root, Declarations)>,
}

pub fn setup_compiler(db: &mut Database) -> CompilerContext<'_> {
let builtins = builtins(db);
let compiler = Compiler::new(db, builtins);
CompilerContext {
compiler,
roots: IndexMap::new(),
}
}

pub fn load_standard_library(ctx: &mut CompilerContext<'_>) -> SymbolId {
let (root, parser_errors) = parse(include_str!("../../../../std/stdlib.rue"));
assert_eq!(parser_errors, Vec::new());

let (module_id, declarations) = ctx.compiler.declare_root(&root);
ctx.compiler.compile_root(&root, module_id, declarations);

let Symbol::Module(module) = ctx.compiler.db.symbol_mut(module_id).clone() else {
unreachable!();
};

let mut scope = Scope::default();

for &symbol_id in &module.exported_symbols {
scope.define_symbol(
ctx.compiler
.db
.scope(module.scope_id)
.symbol_name(symbol_id)
.unwrap()
.to_string(),
symbol_id,
);
}

for &type_id in &module.exported_types {
scope.define_type(
ctx.compiler
.db
.scope(module.scope_id)
.type_name(type_id)
.unwrap()
.to_string(),
type_id,
);
}

let scope_id = ctx.compiler.db.alloc_scope(scope);
ctx.compiler.scope_stack.push(scope_id);
module_id
}

pub fn load_module(ctx: &mut CompilerContext<'_>, root: &Root) -> SymbolId {
let (module_id, declarations) = ctx.compiler.declare_root(root);
ctx.roots.insert(module_id, (root.clone(), declarations));
module_id
}

pub fn compile_modules(mut ctx: CompilerContext<'_>) -> SymbolTable {
for (module_id, (root, declarations)) in ctx.roots {
ctx.compiler.compile_root(&root, module_id, declarations);
}
ctx.compiler.finish()
}

pub fn build_graph(
db: &mut Database,
symbol_table: &SymbolTable,
main_module_id: SymbolId,
library_module_ids: &[SymbolId],
) -> DependencyGraph {
let mut ignored_symbols = HashSet::new();
let mut ignored_types = HashSet::new();

for &module_id in library_module_ids {
let Symbol::Module(module) = db.symbol_mut(module_id).clone() else {
unreachable!();
};
ignored_symbols.extend(module.exported_symbols.iter().copied());
ignored_types.extend(module.exported_types.iter().copied());
}

for type_id in ignored_types.clone() {
let Type::Enum(enum_type) = db.ty(type_id) else {
continue;
};
ignored_types.extend(enum_type.variants.values());
}

let Symbol::Module(module) = db.symbol_mut(main_module_id).clone() else {
unreachable!();
};

let graph = DependencyGraph::build(db, &module);
symbol_table.calculate_unused(db, &graph, &ignored_symbols, &ignored_types);
graph
}

pub fn codegen(
allocator: &mut Allocator,
db: &mut Database,
graph: DependencyGraph,
entrypoint: SymbolId,
) -> NodePtr {
let mut optimizer = Optimizer::new(db, graph);
let lir_id = optimizer.opt_main(entrypoint);
let mut codegen = Codegen::new(db, allocator);
codegen.gen_lir(lir_id)
}

pub fn try_export_main(db: &mut Database, main_module_id: SymbolId) -> Option<SymbolId> {
let Symbol::Module(Module { scope_id, .. }) = db.symbol_mut(main_module_id).clone() else {
unreachable!();
};

if let Some(main_symbol_id) = db.scope_mut(scope_id).symbol("main") {
let Symbol::Module(module) = db.symbol_mut(main_module_id) else {
unreachable!();
};
module.exported_symbols.insert(main_symbol_id);
Some(main_symbol_id)
} else {
None
}
}
Loading

0 comments on commit 08816b4

Please sign in to comment.