///|
priv struct TypePlan {
index : Int
kind : TypeExpr
symbol : String
dependencies : Array[Int]
}
///|
priv struct CallPlan {
function : Callable
symbol : String
inputs : Array[Int]
output : Int
bounded : Bool
}
///|
priv struct GenerationPlan {
project : Project
types : Array[TypePlan]
calls : Array[CallPlan]
}
///|
fn type_index(
types : Array[TypeExpr],
kind : TypeExpr,
) -> Int raise ConfigError {
match types.search_by(t => t == kind) {
Some(index) => index
None => raise Invalid("generation: unresolved type " + kind.moon_name())
}
}
///|
fn direct_children(
project : Project,
kind : TypeExpr,
) -> Array[TypeExpr] raise ConfigError {
match kind {
Scalar(_) => []
List(element) => [element]
Record(name) => project.record_def(name).fields.map(f => f.kind)
}
}
///|
fn make_generation_plan(project : Project) -> GenerationPlan raise ConfigError {
let kinds = project.reachable_types()
let types : Array[TypePlan] = []
let symbols : Map[String, Bool] = Map([])
symbols["moonohos_initialize"] = true
for index, kind in kinds {
let symbol = "moonohos_type_" + index.to_string()
types.push({
index,
kind,
symbol,
dependencies: direct_children(project, kind).map(k => type_index(kinds, k)),
})
let suffixes = match kind {
List(_) => ["new", "push", "length", "get"]
Record(name) => {
let suffixes = ["new"]
for field_index in 0.. []
}
for suffix in suffixes {
symbols[symbol + "_" + suffix] = true
symbols["moonohos_raw_type_" + index.to_string() + "_" + suffix] = true
}
}
let calls : Array[CallPlan] = []
for function in project.functions {
let symbol = "moonohos_" + function.name
if function.name.has_prefix("type_") ||
function.name == "initialize" ||
symbols.contains(symbol) ||
symbols.contains("moonohos_raw_" + function.name) {
raise Invalid(
"generation: reserved/colliding function symbol " + function.name,
)
}
symbols[symbol] = true
symbols["moonohos_raw_" + function.name] = true
let inputs = function.params.map(p => type_index(kinds, p.kind))
let output = type_index(kinds, function.result)
let bounded = function.params.any(p => {
match p.kind {
List(_) | Record(_) => true
_ => false
}
}) ||
(match function.result {
List(_) | Record(_) => true
_ => false
})
calls.push({ function, symbol, inputs, output, bounded, })
}
{ project, types, calls, }
}
///|
fn TypePlan::to_json(self : TypePlan) -> Json {
let reference = self.kind.is_reference()
{
"index": self.index,
"type": self.kind.moon_name(),
"symbol": self.symbol,
"cType": self.kind.c_name(),
"dependencies": self.dependencies.to_json(),
"argument": if reference {
"borrowed"
} else {
"value"
},
"result": if reference {
"owned"
} else {
"value"
},
}
}
///|
fn CallPlan::to_json(self : CallPlan) -> Json {
{
"name": self.function.name,
"signature": self.function.signature(),
"symbol": self.symbol,
"inputs": self.inputs.to_json(),
"output": self.output,
"boundedContainers": self.bounded,
"stages": ["read-arkts", "locked-runtime-call-and-copy", "create-arkts"].to_json(),
}
}
///|
pub fn Project::generation_plan(self : Project) -> Json raise ConfigError {
let plan = make_generation_plan(self)
{
"module": plan.project.native_module,
"types": plan.types.map(t => t.to_json()).to_json(),
"calls": plan.calls.map(c => c.to_json()).to_json(),
"limits": conversion_limits().to_json(),
}
}
///|
fn generated_parameters(fields : Array[FieldDef], moon~ : Bool) -> String {
fields
.map(f => {
f.name +
" : " +
(if moon { f.kind.wrapper_name() } else { f.kind.moon_name() })
})
.join(", ")
}
///|
fn c_parameters(fields : Array[FieldDef]) -> String {
if fields.is_empty() {
"void"
} else {
fields.mapi((i, f) => f.kind.c_name() + " arg" + i.to_string()).join(", ")
}
}
///|
fn raw_adapter(
name : String,
fields : Array[FieldDef],
result : TypeExpr,
) -> String {
let args = fields.mapi((i, _) => "arg" + i.to_string()).join(", ")
let expression = "moonohos_raw_" + name + "(" + args + ")"
let body = if result == Scalar(Void) {
"(void)" + expression + ";"
} else {
"return " + expression + ";"
}
result.c_name() +
" moonohos_" +
name +
"(" +
c_parameters(fields) +
") { " +
body +
" }\n"
}
///|
fn moon_export(
name : String,
fields : Array[FieldDef],
result : TypeExpr,
expression : String,
) -> String {
"///|\npub fn moonohos_raw_" +
name +
"(" +
generated_parameters(fields, moon=true) +
") -> " +
result.wrapper_name() +
" { " +
expression +
" }\n"
}
///|
/// Generates only business exports; container accessors are added by the backend.
pub fn Project::business_wrapper(self : Project) -> String raise ConfigError {
let plan = make_generation_plan(self)
let mut source = "///|\nfn main { () }\n"
for call in plan.calls {
source += moon_export(
call.function.name,
call.function.params,
call.function.result,
"@core." +
call.function.name +
"(" +
call.function.params.map(p => p.name).join(", ") +
")",
)
}
source
}
///|
pub fn Project::business_header(self : Project) -> String raise ConfigError {
let plan = make_generation_plan(self)
let mut source = "#pragma once\n#include \n#include \n#ifdef __cplusplus\nextern \"C\" {\n#endif\nvoid moonohos_initialize(void);\n"
for call in plan.calls {
source += call.function.result.c_name() +
" " +
call.symbol +
"(" +
c_parameters(call.function.params) +
");\n"
}
source + "#ifdef __cplusplus\n}\n#endif\n"
}
///|
pub fn Project::business_adapters(self : Project) -> String raise ConfigError {
let plan = make_generation_plan(self)
plan.calls
.map(c => raw_adapter(c.function.name, c.function.params, c.function.result))
.join("")
}