-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* First step in making a more real transpiler: establish a subdirectory for all of the soon-to-be source files * Run cargo fmt, add support for exported conts, types, and functions, and switch to 'export fn main' as the entrypoint instead of 'on start' * Add logic to properly load the standard library from embedded strings in the compiler (and prove it by parsing the root scope on evey compilation, slowing the test suite down a bit) * Move the function generation to a separate file * Move the old root scope to an unused filename and create a new root scope with a single entry for now, then implement very basic type and function resolution and use it to generate the hello world app * Fix formatting * Update TODOs in the resolve functions to make it clearer which way they're going to evolve * Add super simple 'to-rs' sub-command to get the generated Rust code as a file. Good for debugging, at least. * Modify the scope to use a vector of function implementations per function name, to allow for multiple function implementations with different arguments, and then select the function by the arguments. Also update the root scope to specify the arguments. * Fix fmt * Update the license copyright * Rename 'exit' to 'return' because that's what it actually is * Microstatements are back, baby! * Remove no longer relevant TODO comment * Fix fmt
- Loading branch information
Showing
11 changed files
with
3,913 additions
and
3,563 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Builds a function and everything it needs, recursively. Given a read-only handle on it's own | ||
// scope and the program in case it needs to generate required text from somewhere else. | ||
|
||
use crate::lntors::typen; | ||
use crate::program::{Function, Microstatement, Program, Scope}; | ||
|
||
pub fn from_microstatement( | ||
microstatement: &Microstatement, | ||
scope: &Scope, | ||
program: &Program, | ||
) -> Result<String, Box<dyn std::error::Error>> { | ||
match microstatement { | ||
Microstatement::Assignment { name, value } => Ok(format!( | ||
"let {} = {}", | ||
name, | ||
from_microstatement(value, scope, program)? | ||
) | ||
.to_string()), | ||
Microstatement::Value { representation, .. } => Ok(representation.clone()), | ||
Microstatement::FnCall { function, args } => { | ||
// TODO: Add logic to get the type from the args array of microstatements. For the sake | ||
// of keeping the hello world test working for now, adding some magic knowledge that | ||
// should not be hardcoded until the microstatement generation adds the type | ||
// information needed. | ||
match program.resolve_function(scope, function, &vec!["String".to_string()]) { | ||
None => Err(format!("Function {} not found", function).into()), | ||
Some((f, _s)) => match &f.bind { | ||
None => Err("Inlining user-defined functions not yet supported".into()), | ||
Some(rustname) => { | ||
let mut argstrs = Vec::new(); | ||
for arg in args { | ||
let a = from_microstatement(arg, scope, program)?; | ||
argstrs.push(a); | ||
} | ||
Ok(format!("{}({})", rustname, argstrs.join(", ")).to_string()) | ||
} | ||
}, | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub fn generate( | ||
function: &Function, | ||
scope: &Scope, | ||
program: &Program, | ||
) -> Result<String, Box<dyn std::error::Error>> { | ||
let mut out = "".to_string(); | ||
// First make sure all of the function argument types are defined | ||
for arg in &function.args { | ||
match program.resolve_type(scope, &arg.1) { | ||
None => continue, | ||
Some((t, s)) => { | ||
out = format!("{}{}", out, typen::generate(t, s, program)?); | ||
} | ||
} | ||
} | ||
match &function.rettype { | ||
Some(rettype) => match program.resolve_type(scope, rettype) { | ||
None => {} | ||
Some((t, s)) => { | ||
out = format!("{}{}", out, typen::generate(t, s, program)?); | ||
} | ||
}, | ||
None => {} | ||
} | ||
// Start generating the function output. We can do this eagerly like this because, at least for | ||
// now, we inline all other function calls within an "entry" function (the main function, or | ||
// any function that's attached to an event, or any function that's part of an exported set in | ||
// a shared library). LLVM *probably* doesn't deduplicate this redundancy, so this will need to | ||
// be revisited, but it eliminates a whole host of generation problems that I can come back to | ||
// later. | ||
out = format!( | ||
"{}fn {}({}){} {{\n", | ||
out, | ||
function.name.clone(), | ||
function | ||
.args | ||
.iter() | ||
.map(|(argname, argtype)| format!("{}: {}", argname, argtype).to_string()) // TODO: Don't assume Rust and Alan types exactly match syntax | ||
.collect::<Vec<String>>() | ||
.join(", "), | ||
match &function.rettype { | ||
Some(rettype) => format!(" -> {}", rettype).to_string(), | ||
None => "".to_string(), | ||
}, | ||
) | ||
.to_string(); | ||
for microstatement in &function.microstatements { | ||
let stmt = from_microstatement(microstatement, scope, program)?; | ||
out = format!("{} {};\n", out, stmt); | ||
} | ||
out = format!("{}}}", out); | ||
Ok(out) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
use crate::lntors::function::generate; | ||
use crate::program::Program; | ||
|
||
mod function; | ||
mod typen; | ||
|
||
pub fn lntors(entry_file: String) -> Result<String, Box<dyn std::error::Error>> { | ||
let program = Program::new(entry_file)?; | ||
// Assuming a single scope for now | ||
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()); | ||
} | ||
}; | ||
// 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") { | ||
Some(_) => {} | ||
None => { | ||
return Err( | ||
"Entry file has no `main` function exported. This is not yet supported.".into(), | ||
); | ||
} | ||
}; | ||
// Getting here *should* guarantee that the `main` function exists, so let's grab it. | ||
let func = match scope.functions.get("main") { | ||
Some(f) => f, | ||
None => { | ||
return Err( | ||
"An export has been found without a definition. This should be impossible.".into(), | ||
); | ||
} | ||
}; | ||
// The `main` function takes no arguments, for now. It could have a return type, but we don't | ||
// support that, yet. Also assert that there is only a single `main` function, since *usually* | ||
// you're allowed to have multiple functions with the same name as long as they have different | ||
// arguments. | ||
assert_eq!(func.len(), 1); | ||
assert_eq!(func[0].args.len(), 0); | ||
// Assertion proven, start emitting the Rust `main` function | ||
Ok(generate(&func[0], &scope, &program)?) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// TODO: Everything in here | ||
|
||
use crate::program::{Program, Scope, Type}; | ||
|
||
pub fn generate( | ||
typen: &Type, | ||
scope: &Scope, | ||
program: &Program, | ||
) -> Result<String, Box<dyn std::error::Error>> { | ||
Ok("".to_string()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.