Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the Program type to be used as a singleton #945

Merged
merged 2 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
run: cargo build --verbose
- if: ${{ github.ref_name == 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1 --include-ignored
run: cargo test --verbose -- --include-ignored
- if: ${{ github.ref_name != 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1
run: cargo test --verbose

test-windows:
runs-on: [self-hosted, windows]
Expand All @@ -33,10 +33,10 @@ jobs:
run: cargo build --verbose
- if: ${{ github.ref_name == 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1 --include-ignored
run: cargo test --verbose -- --include-ignored
- if: ${{ github.ref_name != 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1
run: cargo test --verbose

test-macos:
runs-on: [self-hosted, macOS]
Expand All @@ -46,10 +46,10 @@ jobs:
run: cargo build --verbose
- if: ${{ github.ref_name == 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1 --include-ignored
run: cargo test --verbose -- --include-ignored
- if: ${{ github.ref_name != 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1
run: cargo test --verbose

test-arm-linux:
runs-on: [self-hosted, linux, ARM64]
Expand All @@ -59,7 +59,7 @@ jobs:
run: cargo build --verbose
- if: ${{ github.ref_name == 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1 --include-ignored
run: cargo test --verbose -- --include-ignored
- if: ${{ github.ref_name != 'main' }}
name: Run tests
run: cargo test --verbose -- --test-threads=1
run: cargo test --verbose
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ This will create a file with the name `<source>` that you can run (or error if i
If you wish to contribute to Alan, you'll need a development environment to build Alan locally:

* git (any recent version should work)
* Rust >=1.76.0
* Rust >=1.80.0
* Node.js >=22.0.0
* A complete C toolchain (gcc, clang, msvc)

Once those are installed, simply follow the install instructions above, replacing `cargo install --path .` with a simple `cargo build` to compile and `cargo test` to run the test suite.
Expand Down
41 changes: 30 additions & 11 deletions alan/src/compile/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ macro_rules! test {
mod $rule {
#[test]
fn $rule() -> Result<(), Box<dyn std::error::Error>> {
crate::program::Program::set_target_lang_rs();
let filename = format!("{}.ln", stringify!($rule));
match std::fs::write(&filename, $code) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
return Err(format!("Unable to write {} to disk. {:?}", filename, e).into());
}
};
std::env::set_var("ALAN_TARGET", "test");
std::env::set_var("ALAN_OUTPUT_LANG", "rs");
{
let mut program = crate::program::Program::get_program().lock().unwrap();
program.env.insert("ALAN_TARGET".to_string(), "test".to_string());
}
match crate::compile::build(filename.to_string()) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
Expand Down Expand Up @@ -53,15 +56,18 @@ macro_rules! test_full {
mod $rule {
#[test]
fn $rule() -> Result<(), Box<dyn std::error::Error>> {
crate::program::Program::set_target_lang_rs();
let filename = format!("{}.ln", stringify!($rule));
match std::fs::write(&filename, $code) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
return Err(format!("Unable to write {} to disk. {:?}", filename, e).into());
}
};
std::env::set_var("ALAN_TARGET", "test");
std::env::set_var("ALAN_OUTPUT_LANG", "rs");
{
let mut program = crate::program::Program::get_program().lock().unwrap();
program.env.insert("ALAN_TARGET".to_string(), "test".to_string());
}
match crate::compile::build(filename.to_string()) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
Expand All @@ -83,7 +89,11 @@ macro_rules! test_full {
Ok(a) => Ok(a),
Err(e) => Err(format!("Could not remove the test binary {:?}", e)),
}?;
std::env::set_var("ALAN_OUTPUT_LANG", "js");
crate::program::Program::set_target_lang_js();
{
let mut program = crate::program::Program::get_program().lock().unwrap();
program.env.insert("ALAN_TARGET".to_string(), "test".to_string());
}
match crate::compile::web(filename.to_string()) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
Expand Down Expand Up @@ -117,15 +127,18 @@ macro_rules! test_gpgpu {
mod $rule {
#[test]
fn $rule() -> Result<(), Box<dyn std::error::Error>> {
crate::program::Program::set_target_lang_rs();
let filename = format!("{}.ln", stringify!($rule));
match std::fs::write(&filename, $code) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
return Err(format!("Unable to write {} to disk. {:?}", filename, e).into());
}
};
std::env::set_var("ALAN_TARGET", "test");
std::env::set_var("ALAN_OUTPUT_LANG", "rs");
{
let mut program = crate::program::Program::get_program().lock().unwrap();
program.env.insert("ALAN_TARGET".to_string(), "test".to_string());
}
match crate::compile::build(filename.to_string()) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
Expand Down Expand Up @@ -153,8 +166,12 @@ macro_rules! test_gpgpu {
// My playwright scripts only work on Linux and MacOS, though, so that reduces it
// to just MacOS to test this on.
// if cfg!(windows) || cfg!(macos) {
if cfg!(macos) {
std::env::set_var("ALAN_OUTPUT_LANG", "js");
if cfg!(target_os = "macos") {
crate::program::Program::set_target_lang_js();
{
let mut program = crate::program::Program::get_program().lock().unwrap();
program.env.insert("ALAN_TARGET".to_string(), "test".to_string());
}
match crate::compile::web(filename.to_string()) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
Expand Down Expand Up @@ -241,8 +258,10 @@ macro_rules! test_ignore {
return Err(format!("Unable to write {} to disk. {:?}", filename, e).into());
}
};
std::env::set_var("ALAN_TARGET", "test");
std::env::set_var("ALAN_OUTPUT_LANG", "rs");
{
let mut program = crate::program::Program::get_program().lock().unwrap();
program.env.insert("ALAN_TARGET".to_string(), "test".to_string());
}
match crate::compile::build(filename.to_string()) {
Ok(_) => { /* Do nothing */ }
Err(e) => {
Expand Down
48 changes: 33 additions & 15 deletions alan/src/compile/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::env::{current_dir, set_var, var};
use std::env::current_dir;
use std::fs::{create_dir_all, remove_file, write, File};
use std::io::Read;
use std::path::PathBuf;
Expand All @@ -10,6 +10,7 @@ use fs2::FileExt;

use crate::lntojs::lntojs;
use crate::lntors::lntors;
use crate::program::Program;

mod integration_tests;

Expand Down Expand Up @@ -377,10 +378,13 @@ edition = "2021"
/// mode and exits, printing the time it took to run on success.
pub fn compile(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
let start_time = Instant::now();
if var("ALAN_TARGET").is_err() {
set_var("ALAN_TARGET", "release");
Program::set_target_lang_rs();
{
let mut program = Program::get_program().lock().unwrap();
program
.env
.insert("ALAN_TARGET".to_string(), "release".to_string());
}
set_var("ALAN_OUTPUT_LANG", "rs");
build(source_file)?;
println!("Done! Took {:.2}sec", start_time.elapsed().as_secs_f32());
Ok(())
Expand All @@ -389,8 +393,13 @@ pub fn compile(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
/// The `test` function is a thin wrapper on top of `compile` that compiles the specified file in
/// test mode, then immediately invokes it, and deletes the binary when done.
pub fn test(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
set_var("ALAN_TARGET", "test");
set_var("ALAN_OUTPUT_LANG", "rs");
Program::set_target_lang_rs();
{
let mut program = Program::get_program().lock().unwrap();
program
.env
.insert("ALAN_TARGET".to_string(), "test".to_string());
}
let binary = build(source_file)?;
let mut run = Command::new(format!("./{}", binary))
.current_dir(current_dir()?)
Expand Down Expand Up @@ -685,10 +694,13 @@ pub fn web(source_file: String) -> Result<String, Box<dyn std::error::Error>> {
/// mode and exits, printing the time it took to run on success.
pub fn bundle(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
let start_time = Instant::now();
if var("ALAN_TARGET").is_err() {
set_var("ALAN_TARGET", "release");
Program::set_target_lang_js();
{
let mut program = Program::get_program().lock().unwrap();
program
.env
.insert("ALAN_TARGET".to_string(), "release".to_string());
}
set_var("ALAN_OUTPUT_LANG", "js");
web(source_file)?;
println!("Done! Took {:.2}sec", start_time.elapsed().as_secs_f32());
Ok(())
Expand All @@ -697,10 +709,13 @@ pub fn bundle(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
/// The `to_rs` function is an thin wrapper on top of `lntors` that shoves the output into a `.rs`
/// file.
pub fn to_rs(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
if var("ALAN_TARGET").is_err() {
set_var("ALAN_TARGET", "release");
Program::set_target_lang_rs();
{
let mut program = Program::get_program().lock().unwrap();
program
.env
.insert("ALAN_TARGET".to_string(), "release".to_string());
}
set_var("ALAN_OUTPUT_LANG", "rs");
// Generate the rust code to compile
let (rs_str, deps) = lntors(source_file.clone())?;
// Shove it into a temp file for rustc
Expand Down Expand Up @@ -737,10 +752,13 @@ pub fn to_rs(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
/// The `to_js` function is an thin wrapper on top of `lntojs` that shoves the output into a `.js`
/// file.
pub fn to_js(source_file: String) -> Result<(), Box<dyn std::error::Error>> {
if var("ALAN_TARGET").is_err() {
set_var("ALAN_TARGET", "release");
Program::set_target_lang_js();
{
let mut program = Program::get_program().lock().unwrap();
program
.env
.insert("ALAN_TARGET".to_string(), "release".to_string());
}
set_var("ALAN_OUTPUT_LANG", "js");
// Generate the rust code to compile
let (js_str, deps) = lntojs(source_file.clone())?;
// Shove it into a temp file for rustc
Expand Down
12 changes: 4 additions & 8 deletions alan/src/lntojs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ mod typen;
pub fn lntojs(
entry_file: String,
) -> Result<(String, OrderedHashMap<String, String>), Box<dyn std::error::Error>> {
let program = Program::new(entry_file)?;
// Getting the entry scope, where the `main` function is expected
let scope = match program.scopes_by_file.get(&program.entry_file.clone()) {
Some((_, _, s)) => s,
None => {
return Err("Somehow didn't find a scope for the entry file!?".into());
}
};
Program::set_target_lang_js();
Program::load(entry_file.clone())?;
let program = Program::get_program().lock().unwrap();
let scope = program.scope_by_file(&entry_file)?;
// Without support for building shared libs yet, assume there is an `export fn main` in the
// entry file or fail otherwise
match scope.exports.get("main") {
Expand Down
12 changes: 4 additions & 8 deletions alan/src/lntors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ mod typen;
pub fn lntors(
entry_file: String,
) -> Result<(String, OrderedHashMap<String, String>), Box<dyn std::error::Error>> {
let program = Program::new(entry_file)?;
// Getting the entry scope, where the `main` function is expected
let scope = match program.scopes_by_file.get(&program.entry_file.clone()) {
Some((_, _, s)) => s,
None => {
return Err("Somehow didn't find a scope for the entry file!?".into());
}
};
Program::set_target_lang_rs();
Program::load(entry_file.clone())?;
let program = Program::get_program().lock().unwrap();
let scope = program.scope_by_file(&entry_file)?;
// Without support for building shared libs yet, assume there is an `export fn main` in the
// entry file or fail otherwise
match scope.exports.get("main") {
Expand Down
6 changes: 2 additions & 4 deletions alan/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::compile::{bundle, compile, test, to_js, to_rs};
use crate::program::Program;
use clap::{Parser, Subcommand};

mod compile;
Expand Down Expand Up @@ -78,9 +77,8 @@

fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Cli::parse();
if let Some(file) = args.file {
let program = Program::new(file)?;
println!("{:?}", program);
if let Some(_) = args.file {
Fixed Show fixed Hide fixed
println!("TODO: Interpreter mode someday");
Ok(())
} else {
match &args.commands {
Expand Down
Loading
Loading