Skip to content

Commit

Permalink
starting to flesh out rust codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
timbod7 committed Mar 21, 2023
1 parent 1b59a31 commit 82eb63f
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 115 deletions.
115 changes: 0 additions & 115 deletions rust/compiler/src/cli/rust.rs

This file was deleted.

112 changes: 112 additions & 0 deletions rust/compiler/src/cli/rust/generate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use super::RustOpts;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;


use crate::adlgen::sys::adlast2::{self as adlast, PrimitiveType};
use crate::processing::resolver::{Module1, Resolver, TypeExpr1};
use crate::processing::writer::TreeWriter;

use crate::cli::rust::rsfile::RSFile;
use crate::fmtln;


/// Generate the tree of mod.rs files that link together the generated code
pub fn gen_rs_mod_files(opts: &RustOpts, resolver: &Resolver, writer: &mut TreeWriter) -> anyhow::Result<()> {

// build a map of parent rust modules and their children
let mut modfiles: HashMap<Vec<String>,HashSet<String>> = HashMap::new();
for m in resolver.get_module_names() {
let msplit: Vec<&str> = m.split(".").collect();
for i in 0..msplit.len() {
let rsmod = msplit.get(i).unwrap();
let parent = &msplit[0..i];
let parent: Vec<String> = parent.iter().map(|m| m.to_string()).collect();
let e = modfiles.entry(parent).or_default();
e.insert(rsmod.to_string());
}
}

for (rsmod,children) in modfiles {
let mut path = PathBuf::new();
path.push(opts.module.clone());
for el in rsmod {
path.push(el);
}
path.push("mod.rs");
let lines: Vec<String> = children
.iter()
.map( |m| format!("pub mod {};", m))
.collect();
writer.write(&path, lines.join("\n"))?
};
Ok(())
}

pub fn gen_module(m: &Module1) -> anyhow::Result<String> {
let mut out = RSFile::new();

for d in m.decls.iter() {
match &d.r#type {
adlast::DeclType::Struct(s) => gen_struct(m, d, &s, &mut out)?,
_ => {}
}
}
Ok(out.to_string())
}


fn gen_struct(
_m: &Module1,
d: &adlast::Decl<TypeExpr1>,
s: &adlast::Struct<TypeExpr1>,
out: &mut RSFile,
) -> anyhow::Result<()> {
fmtln!(out, "pub struct {} {{", d.name);
for f in &s.fields {
fmtln!(out, " {}: {};", f.name, gen_type_expr(&f.type_expr));
}
fmtln!(out, "}}");
fmtln!(out, "");
fmtln!(out, "impl {} {{", d.name);
fmtln!(out, " pub fn new() -> {} {{", d.name);
fmtln!(out, " {} {{", d.name);
fmtln!(out, " }}");
fmtln!(out, " }}");
fmtln!(out, "}}");
fmtln!(out, "");
Ok(())
}

fn gen_type_expr(te: &TypeExpr1) -> String {
match &te.type_ref {
adlast::TypeRef::LocalName(_ln) => "UNIMP.LOCAL_NAME".to_owned(),
adlast::TypeRef::ScopedName(_sn) => "UNIMP.SCOPED_NAME".to_owned(),
adlast::TypeRef::Primitive(p) => gen_primitive_type_expr(p, &te.parameters),
adlast::TypeRef::TypeParam(_t) => "UNIMP.TYPE_PARAM".to_owned(),
}
}

fn gen_primitive_type_expr(p: &PrimitiveType, _params: &[TypeExpr1]) -> String {
match p {
PrimitiveType::Void => "()".to_owned(),
PrimitiveType::Bool => "bool".to_owned(),
PrimitiveType::Int8 => "i8".to_owned(),
PrimitiveType::Int16 => "i16".to_owned(),
PrimitiveType::Int32 => "i32".to_owned(),
PrimitiveType::Int64 => "i64".to_owned(),
PrimitiveType::Word8 => "u8".to_owned(),
PrimitiveType::Word16 => "u16".to_owned(),
PrimitiveType::Word32 => "u32".to_owned(),
PrimitiveType::Word64 => "u64".to_owned(),
PrimitiveType::Float => "f32".to_owned(),
PrimitiveType::Double => "f64".to_owned(),
PrimitiveType::Json => "UNIMP_JSON".to_owned(),
PrimitiveType::ByteVector => "Vec<u8>".to_owned(),
PrimitiveType::String => "String".to_owned(),
PrimitiveType::Vector => "UNIMP_VECTOR".to_owned(),
PrimitiveType::StringMap => "UNIMP_STRINGMAP".to_owned(),
PrimitiveType::Nullable => "UNIMP_NULLABLE".to_owned(),
PrimitiveType::TypeToken => "UNIMP_TYPETOKEN".to_owned(),
}
}
56 changes: 56 additions & 0 deletions rust/compiler/src/cli/rust/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::RustOpts;
use std::path::PathBuf;

use anyhow::anyhow;

use crate::adlgen::sys::adlast2::{self as adlast};
use crate::processing::loader::loader_from_search_paths;
use crate::processing::resolver::{Module1, Resolver};
use crate::processing::writer::TreeWriter;

use generate::{gen_module, gen_rs_mod_files};

mod rsfile;
mod generate;

pub fn rust(opts: &RustOpts) -> anyhow::Result<()> {
let loader = loader_from_search_paths(&opts.search.path);
let mut resolver = Resolver::new(loader);
for m in &opts.modules {
let r = resolver.add_module(m);
match r {
Ok(()) => (),
Err(e) => return Err(anyhow!("Failed to load module {}: {:?}", m, e)),
}
}
let modules: Vec<&Module1> = resolver
.get_module_names()
.into_iter()
.map(|mn| resolver.get_module(&mn).unwrap())
.collect();

let mut writer = TreeWriter::new(
opts.output.outdir.clone(),
opts.output.manifest.clone(),
)?;

for m in modules {
let path = path_from_module_name(opts, m.name.to_owned());
let code = gen_module(m).unwrap();
writer.write(path.as_path(), code)?;
}

gen_rs_mod_files(opts, &resolver, &mut writer)?;

Ok(())
}

fn path_from_module_name(opts: &RustOpts, mname: adlast::ModuleName) -> PathBuf {
let mut path = PathBuf::new();
path.push(opts.module.clone());
for el in mname.split(".") {
path.push(el);
}
path.set_extension("rs");
return path;
}
28 changes: 28 additions & 0 deletions rust/compiler/src/cli/rust/rsfile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

/// In memory representation of a rust file during codegen
pub struct RSFile {
lines: Vec<String>,
}

impl RSFile {
pub fn new() -> Self {
RSFile{
lines: Vec::new(),
}
}

pub fn pushln(&mut self, text: String ) {
self.lines.push(text);
}

pub fn to_string(&self) -> String {
self.lines.join("\n")
}
}

#[macro_export]
macro_rules! fmtln {
($dst:expr, $($arg:tt)*) => {
$dst.pushln(format!($($arg)*))
};
}

0 comments on commit 82eb63f

Please sign in to comment.