Skip to content

Commit

Permalink
Finishing adding stdlib
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Jun 23, 2024
1 parent a1a4f83 commit 2522a6b
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 59 deletions.
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
}
60 changes: 54 additions & 6 deletions crates/rue-compiler/src/compiler/context.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
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},
Database, SymbolId,
};
Expand All @@ -25,14 +28,46 @@ pub fn setup_compiler(db: &mut Database) -> CompilerContext<'_> {
}
}

pub fn load_standard_library(ctx: &mut CompilerContext<'_>) {
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 = load_module(ctx, &root);

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!();
};
ctx.compiler.scope_stack.push(module.scope_id);

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 {
Expand All @@ -51,13 +86,26 @@ pub fn compile_modules(mut ctx: CompilerContext<'_>) -> SymbolTable {
pub fn build_graph(
db: &mut Database,
symbol_table: &SymbolTable,
entrypoint: SymbolId,
main_module_id: SymbolId,
library_module_ids: &[SymbolId],
) -> DependencyGraph {
let Symbol::Module(module) = db.symbol_mut(entrypoint).clone() else {
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());
}

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, &module);
symbol_table.calculate_unused(db, &graph, &ignored_symbols, &ignored_types);
graph
}

Expand Down
2 changes: 2 additions & 0 deletions crates/rue-compiler/src/compiler/expr/function_call_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ impl Compiler<'_> {

let expected = if let Type::Function(fun) = self.db.ty(callee.type_id) {
Some(fun.clone())
} else if let Type::Unknown = self.db.ty(callee.type_id) {
None
} else {
self.db.error(
ErrorKind::UncallableType(self.type_name(callee.type_id)),
Expand Down
11 changes: 9 additions & 2 deletions crates/rue-compiler/src/compiler/item/module_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,17 @@ impl Compiler<'_> {

/// Compile the root by lowering all items into scope.
pub fn compile_root(&mut self, root: &Root, module_id: SymbolId, declarations: Declarations) {
let Symbol::Module(Module { scope_id, .. }) = self.db.symbol_mut(module_id).clone() else {
let Symbol::Module(Module {
scope_id,
exported_symbols,
exported_types,
}) = self.db.symbol_mut(module_id)
else {
unreachable!();
};
self.scope_stack.push(scope_id);
exported_symbols.extend(declarations.exported_symbols.clone());
exported_types.extend(declarations.exported_types.clone());
self.scope_stack.push(*scope_id);
self.compile_items(&root.items(), declarations);
self.scope_stack.pop().unwrap();
}
Expand Down
13 changes: 5 additions & 8 deletions crates/rue-compiler/src/compiler/symbol_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ use std::collections::HashSet;
use indexmap::{IndexMap, IndexSet};

use crate::{
optimizer::DependencyGraph,
symbol::{Module, Symbol},
ty::Type,
Database, SymbolId, TypeId, WarningKind,
optimizer::DependencyGraph, symbol::Symbol, ty::Type, Database, SymbolId, TypeId, WarningKind,
};

#[derive(Debug, Default)]
Expand Down Expand Up @@ -47,7 +44,8 @@ impl SymbolTable {
&self,
db: &mut Database,
dependency_graph: &DependencyGraph,
module: &Module,
ignored_symbols: &HashSet<SymbolId>,
ignored_types: &HashSet<TypeId>,
) {
let mut type_ids = IndexSet::new();
let mut symbol_ids = IndexSet::new();
Expand All @@ -62,8 +60,7 @@ impl SymbolTable {
.flat_map(|scope_id| db.scope(scope_id).local_symbols())
.collect::<Vec<SymbolId>>()
{
if dependency_graph.symbol_usages(symbol_id) > 0
|| module.exported_symbols.contains(&symbol_id)
if dependency_graph.symbol_usages(symbol_id) > 0 || ignored_symbols.contains(&symbol_id)
{
used_symbols.insert(symbol_id);
continue;
Expand All @@ -90,7 +87,7 @@ impl SymbolTable {
}

for type_id in db.named_types() {
if used_types.contains(&type_id) || module.exported_types.contains(&type_id) {
if used_types.contains(&type_id) || ignored_types.contains(&type_id) {
continue;
}

Expand Down
18 changes: 14 additions & 4 deletions crates/rue-compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ pub fn analyze(root: &Root) -> Vec<Diagnostic> {
let mut db = Database::default();
let mut ctx = setup_compiler(&mut db);

load_standard_library(&mut ctx);
let stdlib = load_standard_library(&mut ctx);
let main_module_id = load_module(&mut ctx, root);
let symbol_table = compile_modules(ctx);

try_export_main(&mut db, main_module_id);
build_graph(&mut db, &symbol_table, main_module_id);
build_graph(
&mut db,
&symbol_table,
main_module_id,
&[main_module_id, stdlib],
);

db.diagnostics().to_vec()
}
Expand All @@ -53,12 +58,17 @@ pub fn compile(allocator: &mut Allocator, root: &Root, should_codegen: bool) ->
let mut db = Database::default();
let mut ctx = setup_compiler(&mut db);

load_standard_library(&mut ctx);
let stdlib = load_standard_library(&mut ctx);
let main_module_id = load_module(&mut ctx, root);
let symbol_table = compile_modules(ctx);

let main = try_export_main(&mut db, main_module_id).expect("missing main function");
let graph = build_graph(&mut db, &symbol_table, main_module_id);
let graph = build_graph(
&mut db,
&symbol_table,
main_module_id,
&[main_module_id, stdlib],
);

Output {
diagnostics: db.diagnostics().to_vec(),
Expand Down
14 changes: 11 additions & 3 deletions std/stdlib.rue
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
fun tree_hash(value: Any) -> Bytes32 {
export fun tree_hash(value: Any) -> Bytes32 {
if value is Bytes {
tree_hash_atom(value)
} else {
tree_hash_pair(tree_hash(value.first), tree_hash(value.rest))
}
}

inline fun tree_hash_atom(value: Bytes) -> Bytes32 {
export inline fun tree_hash_atom(value: Bytes) -> Bytes32 {
sha256(1 as Bytes + value)
}

inline fun tree_hash_pair(first: Bytes32, rest: Bytes32) -> Bytes32 {
export inline fun tree_hash_pair(first: Bytes32, rest: Bytes32) -> Bytes32 {
sha256(2 as Bytes + first + rest)
}

export fun another_something() -> Int {
42
}

fun something() -> Int {
42
}

0 comments on commit 2522a6b

Please sign in to comment.