Codegen works (only through tests right now though)
This commit is contained in:
parent
caedb752b7
commit
2ecea1e653
12 changed files with 493 additions and 5 deletions
67
Cargo.lock
generated
67
Cargo.lock
generated
|
@ -131,6 +131,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cogs_ast",
|
"cogs_ast",
|
||||||
"eyre",
|
"eyre",
|
||||||
|
"intern-arc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -142,6 +143,10 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cogs_runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color-eyre"
|
name = "color-eyre"
|
||||||
version = "0.6.3"
|
version = "0.6.3"
|
||||||
|
@ -267,6 +272,17 @@ dependencies = [
|
||||||
"similar",
|
"similar",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "intern-arc"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "328e5c9569f7aa3ee795c58e1e7da8875c1eb506fba10341e912d892e6d0a193"
|
||||||
|
dependencies = [
|
||||||
|
"loom",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -297,6 +313,16 @@ version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
|
@ -390,6 +416,9 @@ name = "once_cell"
|
||||||
version = "1.20.2"
|
version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
dependencies = [
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
|
@ -403,6 +432,29 @@ version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -501,6 +553,15 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
@ -588,6 +649,12 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"crates/ast",
|
"crates/ast", "crates/runtime",
|
||||||
"crates/codegen",
|
"crates/codegen",
|
||||||
"crates/parser",
|
"crates/parser",
|
||||||
"integrations/axum"
|
"integrations/axum"
|
||||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cogs_ast = { path = "../ast" }
|
cogs_ast = { path = "../ast" }
|
||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
|
intern-arc = "0.6.1"
|
||||||
|
|
177
crates/codegen/src/generate.rs
Normal file
177
crates/codegen/src/generate.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct Generator {
|
||||||
|
pub trees: Vec<Tree>,
|
||||||
|
pub intern_str: StrInterner,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! push {
|
||||||
|
(@noquote $cx:expr, $fmt:expr, $($arg:expr),+$(,)?) => {{
|
||||||
|
$cx.format.push_str($fmt);
|
||||||
|
$cx.arguments.extend([$($arg),+]);
|
||||||
|
}};
|
||||||
|
($cx:expr, $fmt:expr, $($arg:expr),+$(,)?) => {{
|
||||||
|
$cx.format.push_str($fmt);
|
||||||
|
$cx.arguments.extend([$(quoted(&$arg)),+]);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AppendContext {
|
||||||
|
pre: String,
|
||||||
|
format: String,
|
||||||
|
arguments: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppendContext {
|
||||||
|
#[inline]
|
||||||
|
fn push(&mut self, format: &str) {
|
||||||
|
self.format.push_str(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn push_arg(&mut self, value: String) {
|
||||||
|
self.push("{}");
|
||||||
|
self.arguments.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quoted(s: &str) -> String {
|
||||||
|
format!("r#\"{}\"#", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
fn append(&self, cx: &mut AppendContext) {
|
||||||
|
match self {
|
||||||
|
Expression::Literal(literal) => push!(cx, "\"{}\"", literal),
|
||||||
|
Expression::Code(code) => cx.push_arg(code.trim().to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HtmlTag {
|
||||||
|
fn append(&self, cx: &mut AppendContext) {
|
||||||
|
push!(
|
||||||
|
cx,
|
||||||
|
// add space after, if there are attributes
|
||||||
|
if self.attributes.is_empty() {
|
||||||
|
"<{}"
|
||||||
|
} else {
|
||||||
|
"<{} "
|
||||||
|
},
|
||||||
|
self.tag,
|
||||||
|
);
|
||||||
|
|
||||||
|
for attr in &self.attributes {
|
||||||
|
push!(
|
||||||
|
cx,
|
||||||
|
if attr.value.is_some() { "{}=" } else { "{}" },
|
||||||
|
attr.name
|
||||||
|
);
|
||||||
|
if let Some(value) = &attr.value {
|
||||||
|
value.append(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.content.is_empty() {
|
||||||
|
cx.push("/>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.push(">");
|
||||||
|
|
||||||
|
for tree in &self.content {
|
||||||
|
tree.append(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
push!(cx, "</{}>", self.tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeTree {
|
||||||
|
fn append(&self, cx: &mut AppendContext) {
|
||||||
|
match self {
|
||||||
|
CodeTree::Code(code) => {
|
||||||
|
let trimmed = code.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cx.pre.push_str(code.trim());
|
||||||
|
}
|
||||||
|
CodeTree::HtmlTag(html_tag) => html_tag.append(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeBlock {
|
||||||
|
fn append(&self, cx: &mut AppendContext) {
|
||||||
|
let mut my_cx = AppendContext {
|
||||||
|
pre: String::new(),
|
||||||
|
format: String::new(),
|
||||||
|
arguments: Vec::new(),
|
||||||
|
};
|
||||||
|
for code in self.content.iter() {
|
||||||
|
code.append(&mut my_cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
let fmt = if my_cx.format.is_empty() {
|
||||||
|
my_cx.pre
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
r##"{{{pre}
|
||||||
|
format!(r#"{format}"#, {arguments})
|
||||||
|
}}"##,
|
||||||
|
pre = my_cx.pre,
|
||||||
|
format = my_cx.format,
|
||||||
|
arguments = my_cx.arguments.join(","),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
push!(@noquote cx, "{}", fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tree {
|
||||||
|
fn append(&self, cx: &mut AppendContext) {
|
||||||
|
match self {
|
||||||
|
Tree::HtmlText(text) => {
|
||||||
|
// this adds {} to the format string and adds "{text}" to the args
|
||||||
|
cx.push_arg(quoted(text.trim()));
|
||||||
|
}
|
||||||
|
Tree::HtmlTag(html_tag) => html_tag.append(cx),
|
||||||
|
Tree::CodeBlock(code_block) => code_block.append(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Generator {
|
||||||
|
pub fn to_format(&self) -> String {
|
||||||
|
let mut cx = AppendContext {
|
||||||
|
pre: String::new(),
|
||||||
|
format: String::new(),
|
||||||
|
arguments: Vec::new(),
|
||||||
|
};
|
||||||
|
for tree in self.trees.iter() {
|
||||||
|
if let Tree::CodeBlock(code_block) = tree {
|
||||||
|
if !code_block.has_html {
|
||||||
|
for code in code_block.content.iter() {
|
||||||
|
let CodeTree::Code(code) = code else {
|
||||||
|
panic!("has_html = false, but got CodeTree::HtmlTag")
|
||||||
|
};
|
||||||
|
let trimmed = code.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cx.pre.push_str(code.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tree.append(&mut cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format!(
|
||||||
|
"{pre}let __rendered = format!(r#\"{format}\"#, {arguments});",
|
||||||
|
pre = cx.pre,
|
||||||
|
format = cx.format,
|
||||||
|
arguments = cx.arguments.join(","),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
122
crates/codegen/src/ir.rs
Normal file
122
crates/codegen/src/ir.rs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub enum Expression {
|
||||||
|
Literal(InternedStr),
|
||||||
|
Code(InternedStr),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HtmlAttribute {
|
||||||
|
pub name: InternedStr,
|
||||||
|
pub value: Option<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HtmlTag {
|
||||||
|
pub tag: InternedStr,
|
||||||
|
pub attributes: Vec<HtmlAttribute>,
|
||||||
|
pub content: Vec<Tree>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum CodeTree {
|
||||||
|
HtmlTag(HtmlTag),
|
||||||
|
Code(InternedStr),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeBlock {
|
||||||
|
pub has_html: bool,
|
||||||
|
pub content: Vec<CodeTree>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Tree {
|
||||||
|
HtmlText(InternedStr),
|
||||||
|
HtmlTag(HtmlTag),
|
||||||
|
CodeBlock(CodeBlock),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tree {
|
||||||
|
pub fn from_ast(value: &ast::Element, intern: &StrInterner) -> Self {
|
||||||
|
match value {
|
||||||
|
ast::Element::Text(text) => Tree::HtmlText(intern.intern_ref(text)),
|
||||||
|
ast::Element::Html(html) => Tree::HtmlTag(HtmlTag::from_ast(html, intern)),
|
||||||
|
ast::Element::Block(block) => Tree::CodeBlock(CodeBlock::from_ast(block, intern)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HtmlTag {
|
||||||
|
pub fn from_ast(value: &ast::HtmlTag, intern: &StrInterner) -> Self {
|
||||||
|
let tag = intern.intern_ref(&value.tag);
|
||||||
|
let attributes = value
|
||||||
|
.attributes
|
||||||
|
.iter()
|
||||||
|
.map(|attr| HtmlAttribute::from_ast(attr, intern))
|
||||||
|
.collect();
|
||||||
|
let content = value
|
||||||
|
.content
|
||||||
|
.iter()
|
||||||
|
.map(|elem| Tree::from_ast(elem, intern))
|
||||||
|
.collect();
|
||||||
|
HtmlTag {
|
||||||
|
tag,
|
||||||
|
attributes,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HtmlAttribute {
|
||||||
|
pub fn from_ast(value: &ast::Attribute, intern: &StrInterner) -> Self {
|
||||||
|
let ast::Element::Text(name) = &value.name else {
|
||||||
|
panic!("attribute name should be a string")
|
||||||
|
};
|
||||||
|
let name = intern.intern_ref(name);
|
||||||
|
let value = value
|
||||||
|
.value
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| Expression::from_ast(v, intern));
|
||||||
|
HtmlAttribute { name, value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeBlock {
|
||||||
|
pub fn from_ast(value: &ast::CodeBlock, intern: &StrInterner) -> Self {
|
||||||
|
let mut has_html = false;
|
||||||
|
let content = value
|
||||||
|
.content
|
||||||
|
.iter()
|
||||||
|
.map(|elem| {
|
||||||
|
if matches!(elem, ast::Element::Html(_)) {
|
||||||
|
has_html = true
|
||||||
|
};
|
||||||
|
CodeTree::from_ast(elem, intern)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
CodeBlock { content, has_html }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
pub fn from_ast(value: &ast::Element, intern: &StrInterner) -> Self {
|
||||||
|
// TODO expression in parser
|
||||||
|
match value {
|
||||||
|
ast::Element::Text(text) => Expression::Literal(intern.intern_ref(text)),
|
||||||
|
ast::Element::Html(_html) => {
|
||||||
|
panic!("ast::Element::Html should not be used as attribute value")
|
||||||
|
} // this is the only case where expression is used so we can mention that in the panic message
|
||||||
|
ast::Element::Block(_block) => {
|
||||||
|
todo!("code blocks are not supported as attribute values until Expression is implemented in the parser")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeTree {
|
||||||
|
pub fn from_ast(value: &ast::Element, intern: &StrInterner) -> Self {
|
||||||
|
match value {
|
||||||
|
ast::Element::Text(text) => CodeTree::Code(intern.intern_ref(text)),
|
||||||
|
ast::Element::Html(html) => CodeTree::HtmlTag(HtmlTag::from_ast(html, intern)),
|
||||||
|
ast::Element::Block(_) => {
|
||||||
|
panic!("nested code block detected (how the hell did the parser do this?)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,43 @@
|
||||||
extern crate cogs_ast as ast;
|
extern crate cogs_ast as ast;
|
||||||
|
|
||||||
|
mod generate;
|
||||||
|
use generate::*;
|
||||||
|
mod ir;
|
||||||
|
use ir::*;
|
||||||
|
|
||||||
|
// type aliases for:
|
||||||
|
// 1. convenience
|
||||||
|
// 2. easy swapping to InternedOrd if i ever find it better
|
||||||
|
type InternedStr = intern_arc::InternedHash<str>;
|
||||||
|
type StrInterner = intern_arc::HashInterner<str>;
|
||||||
|
|
||||||
pub fn generate(ast: &ast::Component) -> eyre::Result<String> {
|
pub fn generate(ast: &ast::Component) -> eyre::Result<String> {
|
||||||
Ok(format!("not yet implemented"))
|
let mut generator = Generator {
|
||||||
|
trees: Vec::new(),
|
||||||
|
intern_str: StrInterner::new(),
|
||||||
|
};
|
||||||
|
let mut elements = ast.elements.iter();
|
||||||
|
for element in elements {
|
||||||
|
generator
|
||||||
|
.trees
|
||||||
|
.push(Tree::from_ast(element, &generator.intern_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
let render = generator.to_format();
|
||||||
|
Ok(format!(
|
||||||
|
r#"
|
||||||
|
pub struct Cog;
|
||||||
|
|
||||||
|
impl cogs_runtime::Component for Cog {{
|
||||||
|
type Props = ();
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
fn render(&self, props: Self::Props) -> impl core::future::Future<Output = Result<String, Self::Error>> + core::marker::Send + '_ {{
|
||||||
|
async move {{
|
||||||
|
{render}
|
||||||
|
Ok(__rendered)
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"#
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ fn parse_inside_code_block(input: &str) -> IResult<&str, Vec<Element>> {
|
||||||
debug!("Attempting inside code block {input}");
|
debug!("Attempting inside code block {input}");
|
||||||
let (input, elems) = parse_consecutive_proper_elements(input)?;
|
let (input, elems) = parse_consecutive_proper_elements(input)?;
|
||||||
|
|
||||||
dbg!(&elems);
|
debug!(?elems, "parsed inside code block");
|
||||||
Ok((input, elems))
|
Ok((input, elems))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
crates/runtime/Cargo.toml
Normal file
6
crates/runtime/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "cogs_runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
43
crates/runtime/src/lib.rs
Normal file
43
crates/runtime/src/lib.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use core::fmt;
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
pub trait Component {
|
||||||
|
type Props;
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
fn render<'a>(&'a self, props: Self::Props) -> impl Future<Output = Result<String, Self::Error>> + Send + 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Render {
|
||||||
|
fn render(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for () {
|
||||||
|
fn render(&self) -> String {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for &str {
|
||||||
|
fn render(&self) -> String {
|
||||||
|
format!("{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for String {
|
||||||
|
fn render(&self) -> String {
|
||||||
|
format!("{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Render> Render for &T {
|
||||||
|
fn render(&self) -> String {
|
||||||
|
(**self).render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Render> Render for Box<T> {
|
||||||
|
fn render(&self) -> String {
|
||||||
|
(**self).render()
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,17 @@ source: src/tests.rs
|
||||||
expression: "cogs_codegen::generate(&ast).unwrap()"
|
expression: "cogs_codegen::generate(&ast).unwrap()"
|
||||||
snapshot_kind: text
|
snapshot_kind: text
|
||||||
---
|
---
|
||||||
not yet implemented
|
pub struct Cog;
|
||||||
|
|
||||||
|
impl cogs_runtime::Component for Cog {
|
||||||
|
type Props = ();
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
fn render(&self, props: Self::Props) -> impl core::future::Future<Output = Result<String, Self::Error>> + core::marker::Send + '_ {
|
||||||
|
async move {
|
||||||
|
let x = 1;let __rendered = format!(r#"<{}><{}>{}</{}><{} {}="{}">{}{}</{}>{}{}</{}>{}"#, r#"body"#,r#"h1"#,r#"Yo."#,r#"h1"#,r#"a"#,r#"src"#,r#"https://www.youtube.com/watch?v=dQw4w9WgXcQ"#,r#"Click this"#,x,r#"a"#,{println!("test");
|
||||||
|
format!(r#"<{}>{}</{}>"#, r#"p"#,r#"More Html"#,r#"p"#)
|
||||||
|
},r#""#,r#"body"#,r#""#);
|
||||||
|
Ok(__rendered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,15 @@ snapshot_kind: text
|
||||||
---
|
---
|
||||||
Component {
|
Component {
|
||||||
elements: [
|
elements: [
|
||||||
|
Block(
|
||||||
|
CodeBlock {
|
||||||
|
content: [
|
||||||
|
Text(
|
||||||
|
"let x = 1;\n",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
Html(
|
Html(
|
||||||
HtmlTag {
|
HtmlTag {
|
||||||
tag: "body",
|
tag: "body",
|
||||||
|
@ -40,6 +49,15 @@ Component {
|
||||||
Text(
|
Text(
|
||||||
"Click this",
|
"Click this",
|
||||||
),
|
),
|
||||||
|
Block(
|
||||||
|
CodeBlock {
|
||||||
|
content: [
|
||||||
|
Text(
|
||||||
|
"x",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
{
|
||||||
|
let x = 1;
|
||||||
|
}
|
||||||
<body>
|
<body>
|
||||||
<h1>Yo.</h1>
|
<h1>Yo.</h1>
|
||||||
<a src="https://www.youtube.com/watch?v=dQw4w9WgXcQ">Click this</a>
|
<a src="https://www.youtube.com/watch?v=dQw4w9WgXcQ">Click this {x}</a>
|
||||||
{
|
{
|
||||||
println!("test");
|
println!("test");
|
||||||
<p>More Html</p>
|
<p>More Html</p>
|
||||||
|
|
Loading…
Reference in a new issue