refactor(starmelon): update v8 dependecy

This commit is contained in:
YetAnotherMinion 2023-01-19 17:23:38 +00:00 committed by nobody
commit 95e21129a8
Signed by: GrocerPublishAgent
GPG key ID: D460CD54A9E3AB86
9 changed files with 894 additions and 338 deletions

View file

@ -48,7 +48,6 @@ oneshot = "0.1.3"
# required for livetable derive macro
livetable-core = { path = "../../../infra/livetable/core" }
cargo-workspace-hack = { version = "0.1", path = "../../../infra/cargo-workspace-hack" }
[dev-dependencies]

24
elm.json Normal file
View file

@ -0,0 +1,24 @@
{
"type": "application",
"source-directories": [
"src/reactor/ui"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/time": "1.0.0"
},
"indirect": {
"elm/json": "1.1.3",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}

View file

@ -1,4 +1,4 @@
module Main exposing (view, view2, view3, view4, view5, view6, view7, view8, badReturnType, true)
module Main exposing (view, view2, view3, view4, view5, view6, view7, view8, badReturnType, true, main)
import Html exposing (Html, div, text)
import Svg exposing (Svg, svg)
@ -6,6 +6,8 @@ import Array exposing (Array)
import Bytes exposing (Bytes)
import Bytes.Decode
main = text "main"
type alias Model =
{ a : Int

187
src/derive/mod.rs Normal file
View file

@ -0,0 +1,187 @@
use crate::elm;
use crate::reporting::{CompilerError, Problem, TypeError};
use livetable_core::{ColumnDefinition, ColumnType};
use std::path::PathBuf;
use tracing::info_span;
pub(crate) fn derive_livetable(
file: PathBuf,
debug: bool,
_output: Option<PathBuf>,
verbosity: u64,
//sqlite_path: Option<PathBuf>,
) -> Result<(), Problem> {
// Our first elm make call is where we build the users program. There is a pretty good chance
// this won't work.
elm::make(&file, debug, verbosity)?;
// Step 2, find the elm.json and elm-stuff directory
let elm_project_dir =
elm::find_project_root("elm.json", "./").map_err(CompilerError::MissingElmJson)?;
let elm_cache_dir = elm_project_dir.join("elm-stuff").join("0.19.1");
if !elm_cache_dir.is_dir() {
return Err(CompilerError::MissingElmStuff(elm_cache_dir).into());
}
// step 2.5 get the module name out of the file.
let data = std::fs::read(&file)
.map_err(|io_err| CompilerError::ReadInputFailed(io_err, file.clone()))?;
let entrypoint = elmi::ModuleNameCanonical {
package: elmi::PackageName::new("author", "project"),
module: crate::elm::parse_module_name(&data)?,
};
// step 3 find all the filepaths in the elm-stuff/0.19.1/* folder
let interfaces = elm::load_interfaces(&elm_cache_dir)?;
// Step 5, check for the desired function
let span = info_span!("resolved target function");
let timing_guard = span.enter();
let mut targets = Vec::new();
match interfaces.get(&entrypoint) {
Some(interface) => {
// todo search over the interface.values for something that has the type of derive
// macro
for (_key, annotation) in interface.values.iter() {
let elmi::CannonicalAnnotation(free_vars, tipe) = annotation;
match tipe {
elmi::Type::TType(module_name, name, args)
if module_name == "author/project/LiveTable.Derive"
&& name == "DeriveEditor" =>
{
if args.len() != 1 {
// We probably have a version mismatch of the tool and library. But I
// don't have any way of telling right now.
panic!(
"todo I don't understand how to parse the LiveTable Derive library"
);
}
targets.push(resolve_table_argument(&args[0])?);
if !free_vars.is_empty() {
// We can't have free vars because that means we can't derive the serialize and
// deserialize functions without concreate types. The table editor component is
// not generic.
//panic!("todo we can't have free vars in livetable derive macro");
}
}
_ => (),
}
}
if targets.is_empty() {
return Err(CompilerError::MissingLiveTableDeriveMacroTarget(
file.clone(),
entrypoint.clone(),
)
.into());
};
//match interface.values.get(&entrypoint.1) {
//Some(annotation) => {
// let elmi::CannonicalAnnotation(_free_vars, tipe) = annotation;
// if is_astrid_pages_route(tipe) {
// ExecutionMode::AstridPagesRoute
// } else {
// let (input_type, output_type) = scripting::resolve_function_type(tipe)?;
// ExecutionMode::Scripting(input_type, output_type)
// }
//}
//None => return Err(CompilerError::BadImport(entrypoint).into()),
}
None => return Err(CompilerError::MissingModuleTypeInformation(entrypoint).into()),
}
drop(timing_guard);
Ok(())
}
fn resolve_table_argument(tipe: &elmi::Type) -> Result<i32, TypeError> {
let mut columns = Vec::new();
match tipe {
// The `fields` field of TAlias is empty if it aliasing a record.
elmi::Type::TAlias(_module_name, _type_name, _fields, ref alias) => match &**alias {
elmi::AliasType::Filled(elmi::Type::TRecord(fields, _name)) => {
//eprintln!("has field {} with type {:?}", field_name, field_type.tipe);
eprintln!("todo resolve this type");
// It seems the source_order is always 0. Not sure if there is a bug in my
// deserializing code or if Evan stopped saving this value but kept the file
// format.
for (field_name, field_type) in fields.iter() {
// check that column is acceptable
match &*field_type.tipe {
elmi::Type::TType(module_name, name, _args) => {
if module_name == "elm/core/Basics" && name == "Bool" {
columns.push(ColumnDefinition {
name: field_name.to_string(),
tipe: ColumnType::Bool,
sync_protocol_identifier: field_name.to_string(),
});
} else if module_name == "elm/core/Basics" && name == "Int" {
columns.push(ColumnDefinition {
name: field_name.to_string(),
tipe: ColumnType::BigInteger,
sync_protocol_identifier: field_name.to_string(),
});
} else if module_name == "elm/core/String" && name == "String" {
columns.push(ColumnDefinition {
name: field_name.to_string(),
tipe: ColumnType::String,
sync_protocol_identifier: field_name.to_string(),
});
} else if module_name == "author/project/LiveTable.Types"
&& name == "Email"
{
columns.push(ColumnDefinition {
name: field_name.to_string(),
tipe: ColumnType::Email,
sync_protocol_identifier: field_name.to_string(),
});
} else if module_name == "elm/bytes/Bytes" && name == "Bytes" {
} else if module_name == "author/project/LiveTable.Types"
&& name == "Attachment"
{
} else {
eprintln!("don't support field type yet {:?}\n\n", field_type.tipe);
//return Err(TypeError::OutputTypeNotSupported(tipe.clone()));
}
}
_ => {
eprintln!("don't support type yet {:?}\n\n", field_type.tipe);
//return Err(TypeError::CantEvalType(tipe.clone()))
}
}
}
Ok(3)
}
elmi::AliasType::Filled(_tipe) => {
// TODO correct error type
Err(TypeError::CantEvalHoleyAlias)
}
elmi::AliasType::Holey(_) => Err(TypeError::CantEvalHoleyAlias),
},
_ => Err(TypeError::OutputTypeNotSupported(tipe.clone())),
}
}
//ColumnType::MaybeBool => Maybe Bool,
//ColumnType::MaybeBigInteger => Maybe Int,
//ColumnType::MaybeString => Maybe String,
//ColumnType::Email => String,
//ColumnType::MaybeEmail => Maybe String,
//ColumnType::Url => String,
//ColumnType::MaybeUrl => Maybe String,
//ColumnType::Float => Float,
//ColumnType::MaybeFloat => Maybe Float,
//ColumnType::Double => Float,
//ColumnType::MaybeDouble => Maybe Float,
//ColumnType::Timestamp => #(posix_type.clone()),
//ColumnType::MaybeTimestamp => Maybe #(posix_type.clone()),
//ColumnType::ExactlyOneAttachment => LiveTable.Attachment,
//ColumnType::MaybeAttachment => Maybe LiveTable.Attachment,
//ColumnType::ListAttachment => List LiveTable.Attachment,

View file

@ -1,6 +1,6 @@
use crate::exec::astrid_pages::OutputType;
use genco_extra::elm::Tokens;
use genco::tokens::quoted;
use genco_extra::elm::Tokens;
use serde::{Deserialize, Serialize};
// I manually made this derived deserialize implementation match the elm json encoder output. The

View file

@ -205,26 +205,26 @@ mod runtime {
let options = WorkerOptions {
bootstrap: BootstrapOptions {
args: vec![],
apply_source_maps: false,
cpu_count: 1,
debug_flag: false,
enable_testing_features: false,
is_tty: false,
location: None,
no_color: false,
is_tty: false,
runtime_version: "0.50.0".to_string(),
ts_version: "2.0.0".to_string(),
unstable: false,
user_agent: "starmelon".to_string(),
},
extensions: extensions,
unsafely_ignore_certificate_errors: None,
root_cert_store: None,
user_agent: "hello_runtime".to_string(),
seed: None,
module_loader,
create_web_worker_cb,
web_worker_preload_module_cb,
js_error_create_fn: None,
format_js_error_fn: None,
source_map_getter: None,
maybe_inspector_server: None,
should_break_on_first_statement: false,
get_error_class_fn: Some(&get_error_class_name),
@ -233,6 +233,7 @@ mod runtime {
broadcast_channel: InMemoryBroadcastChannel::default(),
shared_array_buffer_store: None,
compiled_wasm_module_store: None,
stdio: deno_runtime::ops::io::Stdio::default(),
};
let main_module = deno_core::resolve_path(path_str)?;
@ -311,7 +312,7 @@ mod runtime {
//let code = if let Some((ref source, _)) = is_data_uri {
// source.to_string()
//} else {
let code = self.0.to_string();
let code: Box<[u8]> = self.0.as_bytes().into();
//};
async move {
//if is_data_uri.is_none() && module_specifier.to_string() != SPECIFIER {

36
src/reactor/ui/Router.elm Normal file
View file

@ -0,0 +1,36 @@
module Router exposing (fmain, Table)
import Html exposing (Html, text, div)
import Time exposing (Posix)
import Foo
fmain =
text "Hello world"
type alias Table =
{ target: String
, path: String
, start : Posix
, end : Posix
, status : Status
}
type Status
= Published
| Draft
-- You could write the type out for this, but it does not matter.
--deriveTableEditor =
-- DeriveTableEditor
-- { containerAttributes =
-- [ Livetable.Attributes.rename "foobar"
-- ]
-- , fieldAttributes =
-- { target = [ columnName "Page" ]
-- , path = [ columnName "Target"]
-- , start = [ columnName "Start" ]
-- , end = [ columnName "End" ]
-- , status = [ columnName "Status" ]
-- }
-- }

View file

@ -256,7 +256,8 @@ impl CompilerError {
vcat([to_message_bar(title, ""), Doc::text(""), message])
}
}
// Here is an example of an error message
// ```
// -- MODULE NAME MISMATCH ------------------------------ src/reactor/ui/Router.elm
//
// It looks like this module name is out of sync:
@ -272,6 +273,7 @@ impl CompilerError {
// easier to explore unfamiliar codebases! So if you want to keep the current
// module name, try renaming the file instead.
//
// ```
impl InterpreterError {
pub fn to_doc(&self) -> Doc {

View file

@ -137,105 +137,75 @@ pub fn transpile(
}
if let Some(node) = objects.get(&entrypoint) {
match node {
elmi::Node::Define(elmi::Expr::Function(ref parameters, ref body), deps) => {
for dep in deps {
println!("I depend on {}", dep);
}
let elmi::CannonicalAnnotation(elmi::FreeVars(free_variables), tipe) = signature;
// So I want a map of symbol to is function with arity or is value. I don't need a
// scope mechansim because elm prevents variable shadowing. So the map can
// overwrite values for sibling scopes. So everytime I visit an Expr I want to
// return the arity of that expression. One problem is I need to generate the
// arguments before serializing the body of the closure
let (parameter_types, return_type) =
extract_function_types(&tipe, parameters.len()).unwrap();
let xs = parameters
.into_iter()
.zip(parameter_types.into_iter())
.collect::<Vec<_>>();
// TODO add any TLambdas in the signature to the type parameters of the functions
// as where bounds
let mut tokens = rust::Tokens::new();
codegen_function(
lua_codegen::codegen(
&mut tokens,
&interfaces,
&mut symbol_table,
&entrypoint.1,
&free_variables,
&xs,
return_type,
body,
&entrypoint,
node,
);
println!("{}", tokens.to_file_string().unwrap());
}
_ => println!("I don't know how to transpile that node"),
}
}
println!("total symbols {}", objects.len());
//println!("total symbols {}", objects.len());
//let visited: HashSet<Global> = HashSet::new();
for (_key, node) in objects.iter() {
//println!("key {}", key);
match node {
elmi::Node::Define(_expr, deps) => {
//println!("key => {:?}", expr);
for dep in deps.iter() {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
break;
}
elmi::Node::DefineTailFunc(_, _, deps) => {
for dep in deps.iter() {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
}
elmi::Node::Ctor(_, _) => {}
elmi::Node::Enum(_) => {}
elmi::Node::Box => {}
elmi::Node::Link(dep) => {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
elmi::Node::Cycle(_, _, _, deps) => {
for dep in deps.iter() {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
}
elmi::Node::Manager(_) => (),
elmi::Node::Kernel(_, deps) => {
for dep in deps.iter() {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
}
elmi::Node::PortIncoming(_, deps) => {
for dep in deps.iter() {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
}
elmi::Node::PortOutgoing(_, deps) => {
for dep in deps.iter() {
if !objects.contains_key(&dep) {
println!("could not find dep {}", dep);
}
}
}
}
}
//for (_key, node) in objects.iter() {
// //println!("key {}", key);
// match node {
// elmi::Node::Define(_expr, deps) => {
// //println!("key => {:?}", expr);
// for dep in deps.iter() {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// break;
// }
// elmi::Node::DefineTailFunc(_, _, deps) => {
// for dep in deps.iter() {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// }
// elmi::Node::Ctor(_, _) => {}
// elmi::Node::Enum(_) => {}
// elmi::Node::Box => {}
// elmi::Node::Link(dep) => {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// elmi::Node::Cycle(_, _, _, deps) => {
// for dep in deps.iter() {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// }
// elmi::Node::Manager(_) => (),
// elmi::Node::Kernel(_, deps) => {
// for dep in deps.iter() {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// }
// elmi::Node::PortIncoming(_, deps) => {
// for dep in deps.iter() {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// }
// elmi::Node::PortOutgoing(_, deps) => {
// for dep in deps.iter() {
// if !objects.contains_key(&dep) {
// println!("could not find dep {}", dep);
// }
// }
// }
// }
//}
// step 6, start generating rust code using a tree visitor on each of the entry points.
// Accumulate the contents of each rust module in map.
@ -256,12 +226,12 @@ pub fn transpile(
type SymbolTable<'a> = HashMap<Symbol<'a>, SymbolKind<'a>>;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
enum Symbol<'a> {
pub(crate) enum Symbol<'a> {
Global(&'a elmi::Global),
Local(&'a elmi::Name),
}
enum SymbolKind<'a> {
pub(crate) enum SymbolKind<'a> {
Function { arity: usize, tipe: &'a elmi::Type },
Value { tipe: &'a elmi::Type },
}
@ -362,7 +332,67 @@ fn validate_output_type(tipe: &elmi::Type) -> Result<(), TypeError> {
}
}
fn codegen_function(
mod rust_codegen {
use super::*;
pub(crate) fn codegen(
tokens: &mut rust::Tokens,
interfaces: &HashMap<elmi::ModuleNameCanonical, elmi::Interface>,
symbol_table: &mut SymbolTable,
symbol: &elmi::Global,
node: &elmi::Node,
) {
match node {
elmi::Node::Define(elmi::Expr::Function(ref parameters, ref body), deps) => {
for dep in deps {
println!("I depend on {}", dep);
}
let signature = match interfaces.get(&symbol.0) {
Some(interface) => match interface.values.get(&symbol.1) {
Some(annotation) => {
let elmi::CannonicalAnnotation(_free_vars, ref tipe) = annotation;
annotation
}
None => return,
},
None => return,
};
let elmi::CannonicalAnnotation(elmi::FreeVars(free_variables), tipe) = signature;
// So I want a map of symbol to is function with arity or is value. I don't need a
// scope mechansim because elm prevents variable shadowing. So the map can
// overwrite values for sibling scopes. So everytime I visit an Expr I want to
// return the arity of that expression. One problem is I need to generate the
// arguments before serializing the body of the closure
let (parameter_types, return_type) =
extract_function_types(&tipe, parameters.len()).unwrap();
let xs = parameters
.into_iter()
.zip(parameter_types.into_iter())
.collect::<Vec<_>>();
// TODO add any TLambdas in the signature to the type parameters of the functions
// as where bounds
codegen_function(
tokens,
symbol_table,
&symbol.1,
&free_variables,
&xs,
return_type,
body,
);
println!("{}", tokens.to_file_string().unwrap());
}
_ => println!("I don't know how to transpile that node"),
}
}
fn codegen_function(
tokens: &mut rust::Tokens,
symbol_table: &mut SymbolTable,
name: &elmi::Name,
@ -370,7 +400,7 @@ fn codegen_function(
parameters: &[(&elmi::Name, elmi::Type)],
return_type: elmi::Type,
body: &elmi::Expr,
) {
) {
quote_in! { *tokens =>
fn #name#(if !type_variables.is_empty() =>
<#(for tvar in type_variables.iter() join (, ) =>
@ -382,9 +412,9 @@ fn codegen_function(
#(ref out { codegen_expr(out, symbol_table, body) })
}
}
}
}
fn codegen_type(tokens: &mut rust::Tokens, tipe: &elmi::Type) {
fn codegen_type(tokens: &mut rust::Tokens, tipe: &elmi::Type) {
quote_in! { *tokens =>
#(match tipe {
elmi::Type::TLambda(a, b) => {
@ -441,19 +471,19 @@ fn codegen_type(tokens: &mut rust::Tokens, tipe: &elmi::Type) {
//}
})
};
}
}
fn codegen_name_from_global(
fn codegen_name_from_global(
tokens: &mut rust::Tokens,
home: &elmi::ModuleNameCanonical,
name: &elmi::Name,
) {
) {
quote_in! { *tokens =>
#(ref out => codegen_home_to_builder(out, home) )__#name
}
}
}
fn codegen_home_to_builder(tokens: &mut rust::Tokens, global: &elmi::ModuleNameCanonical) {
fn codegen_home_to_builder(tokens: &mut rust::Tokens, global: &elmi::ModuleNameCanonical) {
let elmi::ModuleNameCanonical {
package: elmi::PackageName { author, project },
module: home,
@ -462,9 +492,9 @@ fn codegen_home_to_builder(tokens: &mut rust::Tokens, global: &elmi::ModuleNameC
quote_in! { *tokens =>
_#(author.replace("-", "_"))_#(project.replace("-", "_"))__#(home.0.replace(".", "_"))
}
}
}
fn codegen_expr(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, expr: &elmi::Expr) {
fn codegen_expr(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, expr: &elmi::Expr) {
match expr {
elmi::Expr::Bool(true) => quote_in! { *tokens => true },
elmi::Expr::Bool(false) => quote_in! { *tokens => false },
@ -513,10 +543,280 @@ fn codegen_expr(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, expr:
if args.len() < *arity {
let mut closure_args = Vec::new();
for i in 0..(*arity - args.len()) {
closure_args.push(elmi::Expr::VarLocal(elmi::Name(format!(
"_partial{}",
i
))));
closure_args.push(elmi::Expr::VarLocal(elmi::Name(
format!("_partial{}", i),
)));
}
quote_in! { *tokens =>
Box::new(| #(for arg in closure_args.iter() join (, ) => #(ref out => codegen_expr(out, symbol_table, arg))) | {
#(ref out => {
codegen_name_from_global(out, home, name)
})(
#(for arg in args.iter().chain(closure_args.iter()) join (,#<push>) => #(ref out =>
codegen_expr(out, symbol_table, arg) )
)
)
})
}
} else {
quote_in! { *tokens =>
#(ref out => {
codegen_name_from_global(out, home, name)
})(
#(for arg in args join (,#<push>) => #(ref out =>
codegen_expr(out, symbol_table, arg) )
)
)
}
}
//println!("found the function symbol {}, arity {}", global, arity);
}
Some(SymbolKind::Value { tipe: _ }) => {
panic!("tried to call a symbol we thought was a value: {}", global);
}
None => {
panic!("tried to call a symbol we don't know about: {}", global);
}
}
}
elmi::Expr::VarLocal(name) => {
quote_in! { *tokens =>
#name(
#(for arg in args join (,#<push>) => #(ref out =>
codegen_expr(out, symbol_table, arg) )
)
)
}
}
_ => {
println!("I was unable to call an expression");
// TODO write a function that can take an expression and return the arity using
// the symbol table from the bottom up.
quote_in! { *tokens =>
#(format!("{:?}", fexpr))
}
//panic!("calling an expression not yet supported");
}
};
}
//elmi::Expr::TailCall(Name, Vec<(Name, Expr)>),
elmi::Expr::If(branches, _final_branch) => {
quote_in! { *tokens =>
#(for (condition, expr) in branches join (#<push>#("} else")) =>
if #(ref out => codegen_expr(out, symbol_table, condition)) #("{")
#(ref out => codegen_expr(out, symbol_table, expr))
) #("} else {")
#(ref out => codegen_expr(out, symbol_table, expr))
#("}")
}
}
elmi::Expr::Let(def, expr) => {
quote_in! { *tokens =>
#(ref out => codegen_def(out, symbol_table, def))
#<push>
#(ref out => codegen_expr(out, symbol_table, expr))
}
}
//elmi::Expr::Destruct(Destructor, Box<Expr>),
//elmi::Expr::Case(Name, Name, Decider<Choice>, Vec<(i64, Expr)>) => {
elmi::Expr::Case(label, root, decider, jumps) => {
println!("jumps {:?}", jumps);
}
elmi::Expr::Accessor(name) => {
quote_in! { *tokens =>
Box::new(|_v| { _v.#name })
}
}
//elmi::Expr::Access(Box<Expr>, Name),
//elmi::Expr::Update(Box<Expr>, HashMap<Name, Expr>),
//elmi::Expr::Record(HashMap<Name, Expr>),
elmi::Expr::Unit => (),
elmi::Expr::Tuple(a, b, None) => {
quote_in! { *tokens =>
( #(ref out => codegen_expr(out, symbol_table, a) ), #(ref out => codegen_expr(out, symbol_table, b) ) )
}
}
elmi::Expr::Tuple(a, b, Some(c)) => {
quote_in! { *tokens =>
( #(ref out => codegen_expr(out, symbol_table, a) ), #(ref out => codegen_expr(out, symbol_table, b) ), #(ref out => codegen_expr(out, symbol_table, c) ) )
}
}
//elmi::Expr::Shader(ShaderSource, HashSet<Name>, HashSet<Name>),
_ => quote_in! { *tokens => #(format!("{:?}", expr)) },
}
}
fn codegen_def(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, def: &elmi::Def) {
match def {
elmi::Def::Def(name, expr) => {
quote_in! { *tokens =>
let #name = #(ref out => codegen_expr(out, symbol_table, expr) );
}
}
elmi::Def::TailDef(name, arg_names, expr) => {
quote_in! { *tokens =>
|#(for arg in arg_names join (, ) => mut #arg) | {
#("'")#name : loop {
#(ref out => codegen_expr(out, symbol_table, expr))
}
}
}
}
}
}
}
mod lua_codegen {
use super::*;
pub(crate) fn codegen(
tokens: &mut rust::Tokens,
interfaces: &HashMap<elmi::ModuleNameCanonical, elmi::Interface>,
symbol_table: &mut SymbolTable,
symbol: &elmi::Global,
node: &elmi::Node,
) {
match node {
elmi::Node::Define(elmi::Expr::Function(ref parameters, ref body), deps) => {
for dep in deps {
println!("I depend on {}", dep);
}
let signature = match interfaces.get(&symbol.0) {
Some(interface) => match interface.values.get(&symbol.1) {
Some(annotation) => {
let elmi::CannonicalAnnotation(_free_vars, ref tipe) = annotation;
annotation
}
None => return,
},
None => return,
};
let elmi::CannonicalAnnotation(elmi::FreeVars(free_variables), tipe) = signature;
// So I want a map of symbol to is function with arity or is value. I don't need a
// scope mechansim because elm prevents variable shadowing. So the map can
// overwrite values for sibling scopes. So everytime I visit an Expr I want to
// return the arity of that expression. One problem is I need to generate the
// arguments before serializing the body of the closure
let (parameter_types, return_type) =
extract_function_types(&tipe, parameters.len()).unwrap();
let xs = parameters
.into_iter()
.zip(parameter_types.into_iter())
.collect::<Vec<_>>();
// TODO add any TLambdas in the signature to the type parameters of the functions
// as where bounds
codegen_function(
tokens,
symbol_table,
&symbol.1,
&free_variables,
&xs,
return_type,
body,
);
println!("{}", tokens.to_file_string().unwrap());
}
_ => println!("I don't know how to transpile that node"),
}
}
fn codegen_function(
tokens: &mut rust::Tokens,
symbol_table: &mut SymbolTable,
name: &elmi::Name,
type_variables: &HashSet<elmi::Name>,
parameters: &[(&elmi::Name, elmi::Type)],
return_type: elmi::Type,
body: &elmi::Expr,
) {
quote_in! { *tokens =>
function #name(#(for (parameter, _tipe) in parameters.iter() join (, ) =>
#parameter
))
#(ref out { codegen_expr(out, symbol_table, body) })
end
}
}
fn codegen_name_from_global(
tokens: &mut rust::Tokens,
home: &elmi::ModuleNameCanonical,
name: &elmi::Name,
) {
quote_in! { *tokens =>
#(ref out => codegen_home_to_builder(out, home) )__#name
}
}
fn codegen_home_to_builder(tokens: &mut rust::Tokens, global: &elmi::ModuleNameCanonical) {
let elmi::ModuleNameCanonical {
package: elmi::PackageName { author, project },
module: home,
} = global;
quote_in! { *tokens =>
_#(author.replace("-", "_"))_#(project.replace("-", "_"))__#(home.0.replace(".", "_"))
}
}
fn codegen_expr(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, expr: &elmi::Expr) {
match expr {
elmi::Expr::Bool(true) => quote_in! { *tokens => true },
elmi::Expr::Bool(false) => quote_in! { *tokens => false },
elmi::Expr::Chr(c) => quote_in! { *tokens => #(quoted(c)) },
elmi::Expr::Str(s) => quote_in! { *tokens => #(quoted(s)) },
elmi::Expr::Int(x) => quote_in! { *tokens => #(x.to_string()) },
elmi::Expr::Float(x) => quote_in! { *tokens => #(x.to_string()) },
elmi::Expr::VarLocal(name) => {
quote_in! { *tokens =>
#name
}
}
elmi::Expr::VarGlobal(elmi::Global(home, name)) => {
quote_in! { *tokens =>
#(ref out => codegen_name_from_global(out, home, name))
}
}
//elmi::Expr::VarEnum(Global, IndexZeroBased),
//elmi::Expr::VarBox(Global),
//elmi::Expr::VarCycle(ModuleNameCanonical, Name),
//elmi::Expr::VarDebug(Name, ModuleNameCanonical, AnnotationRegion, Option<Name>),
//elmi::Expr::VarKernel(Name, Name),
elmi::Expr::List(xs) => {
if xs.is_empty() {
quote_in! { *tokens => &[] }
} else {
quote_in! { *tokens =>
&[
#(for x in xs join (,#<push>) => #(ref out => codegen_expr(out, symbol_table, x) ) )
]
}
}
}
elmi::Expr::Function(_parameters, _body) => {
quote_in! { *tokens =>
"i don't know how to code gen a function expression"
//#(for elmi::Name(ref parameter) in parameters.iter() join (, ) =>
//)
}
}
elmi::Expr::Call(ref fexpr, args) => {
match &**fexpr {
elmi::Expr::VarGlobal(global @ elmi::Global(home, name)) => {
match symbol_table.get(&Symbol::Global(global)) {
Some(SymbolKind::Function { arity, tipe: _ }) => {
if args.len() < *arity {
let mut closure_args = Vec::new();
for i in 0..(*arity - args.len()) {
closure_args.push(elmi::Expr::VarLocal(elmi::Name(
format!("_partial{}", i),
)));
}
quote_in! { *tokens =>
Box::new(| #(for arg in closure_args.iter() join (, ) => #(ref out => codegen_expr(out, symbol_table, arg))) | {
@ -590,6 +890,10 @@ fn codegen_expr(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, expr:
}
//elmi::Expr::Destruct(Destructor, Box<Expr>),
//elmi::Expr::Case(Name, Name, Decider<Choice>, Vec<(i64, Expr)>),
elmi::Expr::Case(label, root, decider, jumps) => {
println!("decider {:#?}", decider);
println!("jumps {:?}", jumps);
}
elmi::Expr::Accessor(name) => {
quote_in! { *tokens =>
Box::new(|_v| { _v.#name })
@ -612,13 +916,13 @@ fn codegen_expr(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, expr:
//elmi::Expr::Shader(ShaderSource, HashSet<Name>, HashSet<Name>),
_ => quote_in! { *tokens => #(format!("{:?}", expr)) },
}
}
}
fn codegen_def(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, def: &elmi::Def) {
fn codegen_def(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, def: &elmi::Def) {
match def {
elmi::Def::Def(name, expr) => {
quote_in! { *tokens =>
let #name = #(ref out => codegen_expr(out, symbol_table, expr) );
local #name = #(ref out => codegen_expr(out, symbol_table, expr) )
}
}
elmi::Def::TailDef(name, arg_names, expr) => {
@ -631,6 +935,7 @@ fn codegen_def(tokens: &mut rust::Tokens, symbol_table: &mut SymbolTable, def: &
}
}
}
}
}
fn extract_function_types(