Add misses-rt crate, component example, README, and fix codegen for non-keyword literal tokens

- misses-rt: add Buffer/Markup HTML helpers, name/type helpers, parse_sections/parse_kv, and template AST
- codegen: add is_syn_keyword() — non-keyword idents in patterns now generate parse+compare instead of syn::Token![…]
- parser: split punct vs ident chars in literal pattern tokens so `props:` becomes two tokens
- examples: add component.mrs/.rs demonstrating named literal tokens and tt capture
- README: comprehensive guide covering .mrs syntax, running the compiler, misses-rt helpers, and examples

https://claude.ai/code/session_01Tppkab4eLsL21asHGjQJoF
This commit is contained in:
Claude
2026-03-07 19:23:53 +00:00
parent f90953a3bb
commit e8d835e196
11 changed files with 1156 additions and 21 deletions
+28 -5
View File
@@ -170,13 +170,20 @@ fn codegen_parser_stmts(pattern: &Pattern) -> Vec<String> {
} else if tok == "}" {
// already consumed by braced!
in_brace = false;
} else if tok.chars().all(|c| c.is_alphanumeric() || c == '_') {
stmts.push(format!(
"_input.parse::<syn::Token![{tok}]>()?;",
tok = tok
));
} else if tok == "," {
stmts.push("_input.parse::<syn::Token![,]>()?;".to_string());
} else if tok.chars().all(|c| c.is_alphanumeric() || c == '_') {
if is_syn_keyword(tok) {
stmts.push(format!(
"_input.parse::<syn::Token![{tok}]>()?;",
tok = tok
));
} else {
stmts.push(format!(
r#"{{ let __lit: syn::Ident = _input.parse()?; if __lit != "{tok}" {{ return Err(syn::Error::new(__lit.span(), concat!("expected `", "{tok}", "`"))); }} }}"#,
tok = tok
));
}
}
}
PatternItem::Binding { name, kind } => {
@@ -213,6 +220,22 @@ fn codegen_parser_stmts(pattern: &Pattern) -> Vec<String> {
stmts
}
/// Returns true if `tok` is a valid operand for `syn::Token![...]`.
/// This covers Rust keywords and built-in punctuation recognized by syn.
fn is_syn_keyword(tok: &str) -> bool {
matches!(
tok,
"as" | "async" | "await" | "break" | "const" | "continue" | "crate"
| "dyn" | "else" | "enum" | "extern" | "false" | "fn" | "for"
| "if" | "impl" | "in" | "let" | "loop" | "match" | "mod"
| "move" | "mut" | "pub" | "ref" | "return" | "self" | "Self"
| "static" | "struct" | "super" | "trait" | "true" | "type"
| "union" | "unsafe" | "use" | "where" | "while" | "abstract"
| "become" | "box" | "do" | "final" | "macro" | "override"
| "priv" | "try" | "typeof" | "unsized" | "virtual" | "yield"
)
}
/// Generate code for the output body
fn codegen_output_body(body: &OutputBody) -> String {
let mut out = String::new();