1use crate::types::{TypedProgram, TypedItem};
13use crate::error::{KainResult, KainError};
14use crate::ast::{
15 Type, Expr, Stmt, Block, BinaryOp, UnaryOp, Pattern, Function, Struct, Enum,
16 Field, Variant, VariantFields, Impl, Param, MatchArm, CallArg, ElseBranch,
17 VariantPatternFields, EnumVariantFields, Component, JSXNode, JSXAttribute, JSXAttrValue,
18};
19use crate::span::Span;
20
21pub fn generate(program: &TypedProgram) -> KainResult<String> {
23 let mut gen = JSGen::new();
24 Ok(gen.gen_program(program))
25}
26
27struct StringBuilder {
29 lines: Vec<String>,
30}
31
32impl StringBuilder {
33 fn new() -> Self {
34 Self { lines: Vec::new() }
35 }
36
37 fn push(&mut self, text: &str) {
38 self.lines.push(text.to_string());
39 }
40
41 fn push_line(&mut self, text: &str) {
42 self.lines.push(format!("{}\n", text));
43 }
44
45 fn build(&self) -> String {
46 self.lines.join("")
47 }
48}
49
50struct JSGen {
52 output: StringBuilder,
53 indent: usize,
54}
55
56impl JSGen {
57 fn new() -> Self {
58 Self {
59 output: StringBuilder::new(),
60 indent: 0,
61 }
62 }
63
64 fn indent(&mut self) {
65 self.indent += 1;
66 }
67
68 fn dedent(&mut self) {
69 if self.indent > 0 {
70 self.indent -= 1;
71 }
72 }
73
74 fn write(&mut self, text: &str) {
75 self.output.push(text);
76 }
77
78 fn writeln(&mut self, text: &str) {
79 let indent_str = " ".repeat(self.indent);
80 self.output.push_line(&format!("{}{}", indent_str, text));
81 }
82
83 fn gen_program(&mut self, program: &TypedProgram) -> String {
84 self.writeln("// Generated by KAIN compiler");
86 self.writeln("// Target: JavaScript (ES6+)");
87 self.writeln("");
88
89 for item in &program.items {
91 match item {
92 TypedItem::Function(f) => self.gen_function(&f.ast),
93 TypedItem::Struct(s) => self.gen_struct(&s.ast),
94 TypedItem::Enum(e) => self.gen_enum(&e.ast),
95 TypedItem::Component(c) => self.gen_component(&c.ast),
96 TypedItem::Const(c) => self.gen_const(&c.ast.name, &c.ast.value),
97 TypedItem::Impl(i) => self.gen_impl(&i.ast),
98 _ => {} }
100 self.writeln("");
101 }
102
103 self.output.build()
104 }
105
106 fn gen_function(&mut self, func: &Function) {
107 let params = func.params.iter()
109 .map(|p| p.name.clone())
110 .collect::<Vec<_>>()
111 .join(", ");
112
113 self.writeln(&format!("function {}({}) {{", func.name, params));
114 self.indent();
115
116 self.gen_block(&func.body);
118
119 self.dedent();
120 self.writeln("}");
121 }
122
123 fn gen_struct(&mut self, s: &Struct) {
124 self.writeln(&format!("class {} {{", s.name));
126 self.indent();
127
128 let params = s.fields.iter()
130 .map(|f| f.name.clone())
131 .collect::<Vec<_>>()
132 .join(", ");
133
134 self.writeln(&format!("constructor({}) {{", params));
135 self.indent();
136 for field in &s.fields {
137 self.writeln(&format!("this.{} = {};", field.name, field.name));
138 }
139 self.dedent();
140 self.writeln("}");
141
142 self.dedent();
143 self.writeln("}");
144 }
145
146 fn gen_enum(&mut self, e: &Enum) {
147 self.writeln(&format!("const {} = {{", e.name));
149 self.indent();
150
151 for variant in &e.variants {
152 match &variant.fields {
153 VariantFields::Unit => {
154 self.writeln(&format!("{}: {{ type: '{}', tag: '{}' }},",
155 variant.name, e.name, variant.name));
156 }
157 VariantFields::Tuple(types) => {
158 let params = (0..types.len())
159 .map(|i| format!("_{}", i))
160 .collect::<Vec<_>>()
161 .join(", ");
162
163 self.writeln(&format!("{}: ({}) => ({{", variant.name, params));
164 self.indent();
165 self.writeln(&format!("type: '{}',", e.name));
166 self.writeln(&format!("tag: '{}',", variant.name));
167 for i in 0..types.len() {
168 self.writeln(&format!("_{}: _{},", i, i));
169 }
170 self.dedent();
171 self.writeln("}),");
172 }
173 VariantFields::Struct(fields) => {
174 let params = fields.iter()
175 .map(|f| f.name.clone())
176 .collect::<Vec<_>>()
177 .join(", ");
178
179 self.writeln(&format!("{}: ({}) => ({{", variant.name, params));
180 self.indent();
181 self.writeln(&format!("type: '{}',", e.name));
182 self.writeln(&format!("tag: '{}',", variant.name));
183 for field in fields {
184 self.writeln(&format!("{},", field.name));
185 }
186 self.dedent();
187 self.writeln("}),");
188 }
189 }
190 }
191
192 self.dedent();
193 self.writeln("};");
194 }
195
196 fn gen_component(&mut self, comp: &Component) {
197 let params = comp.props.iter()
199 .map(|p| p.name.clone())
200 .collect::<Vec<_>>()
201 .join(", ");
202
203 self.writeln(&format!("function {}({}) {{", comp.name, params));
204 self.indent();
205
206 for state in &comp.state {
208 self.write(&format!("let {} = ", state.name));
209 self.gen_expr(&state.initial);
210 self.writeln(";");
211 }
212
213 for method in &comp.methods {
215 self.gen_function(method);
216 }
217
218 self.write("return ");
220 self.gen_jsx(&comp.body);
221 self.writeln(";");
222
223 self.dedent();
224 self.writeln("}");
225 }
226
227 fn gen_const(&mut self, name: &str, value: &Expr) {
228 self.write(&format!("const {} = ", name));
229 self.gen_expr(value);
230 self.writeln(";");
231 }
232
233 fn gen_impl(&mut self, impl_block: &Impl) {
234 if let Type::Named { name, .. } = &impl_block.target_type {
236 for method in &impl_block.methods {
237 let params = method.params.iter()
238 .skip(if method.params.first().map(|p| p.name == "self").unwrap_or(false) { 1 } else { 0 })
239 .map(|p| p.name.clone())
240 .collect::<Vec<_>>()
241 .join(", ");
242
243 let has_self = method.params.first().map(|p| p.name == "self").unwrap_or(false);
244
245 if has_self {
246 self.writeln(&format!("{}.prototype.{} = function({}) {{",
248 name, method.name, params));
249 } else {
250 self.writeln(&format!("{}.{} = function({}) {{",
252 name, method.name, params));
253 }
254
255 self.indent();
256 self.gen_block(&method.body);
257 self.dedent();
258 self.writeln("};");
259 }
260 }
261 }
262
263 fn gen_block(&mut self, block: &Block) {
264 for stmt in &block.stmts {
265 self.gen_stmt(stmt);
266 }
267 }
268
269 fn gen_stmt(&mut self, stmt: &Stmt) {
270 match stmt {
271 Stmt::Expr(expr) => {
272 self.gen_expr(expr);
273 self.writeln(";");
274 }
275 Stmt::Let { pattern, value, .. } => {
276 if let Pattern::Binding { name, .. } = pattern {
277 self.write(&format!("let {} = ", name));
278 if let Some(val) = value {
279 self.gen_expr(val);
280 } else {
281 self.write("null");
282 }
283 self.writeln(";");
284 }
285 }
286 Stmt::Return(expr, _) => {
287 self.write("return");
288 if let Some(e) = expr {
289 self.write(" ");
290 self.gen_expr(e);
291 }
292 self.writeln(";");
293 }
294 Stmt::For { binding, iter, body, .. } => {
295 if let Pattern::Binding { name, .. } = binding {
296 self.write(&format!("for (const {} of ", name));
297 self.gen_expr(iter);
298 self.writeln(") {");
299 self.indent();
300 self.gen_block(body);
301 self.dedent();
302 self.writeln("}");
303 }
304 }
305 Stmt::While { condition, body, .. } => {
306 self.write("while (");
307 self.gen_expr(condition);
308 self.writeln(") {");
309 self.indent();
310 self.gen_block(body);
311 self.dedent();
312 self.writeln("}");
313 }
314 Stmt::Loop { body, .. } => {
315 self.writeln("while (true) {");
316 self.indent();
317 self.gen_block(body);
318 self.dedent();
319 self.writeln("}");
320 }
321 Stmt::Break(expr, _) => {
322 if expr.is_some() {
323 self.writeln("// Note: break with value not supported in JS");
324 }
325 self.writeln("break;");
326 }
327 Stmt::Continue(_) => {
328 self.writeln("continue;");
329 }
330 _ => {
331 self.writeln("// Unsupported statement");
332 }
333 }
334 }
335
336 fn gen_expr(&mut self, expr: &Expr) {
337 match expr {
338 Expr::Int(n, _) => self.write(&n.to_string()),
339 Expr::Float(f, _) => self.write(&f.to_string()),
340 Expr::String(s, _) => self.write(&format!("\"{}\"", s.escape_default())),
341 Expr::Bool(b, _) => self.write(if *b { "true" } else { "false" }),
342 Expr::None(_) => self.write("null"),
343 Expr::Ident(name, _) => self.write(name),
344
345 Expr::Binary { left, op, right, .. } => {
346 self.write("(");
347 self.gen_expr(left);
348 self.write(&format!(" {} ", self.gen_binop(*op)));
349 self.gen_expr(right);
350 self.write(")");
351 }
352
353 Expr::Unary { op, operand, .. } => {
354 self.write(&format!("({}",
355 self.gen_unop(*op)));
356 self.gen_expr(operand);
357 self.write(")");
358 }
359
360 Expr::Call { callee, args, .. } => {
361 self.gen_expr(callee);
362 self.write("(");
363 for (i, arg) in args.iter().enumerate() {
364 if i > 0 {
365 self.write(", ");
366 }
367 self.gen_expr(&arg.value);
368 }
369 self.write(")");
370 }
371
372 Expr::Array(elements, _) => {
373 self.write("[");
374 for (i, elem) in elements.iter().enumerate() {
375 if i > 0 {
376 self.write(", ");
377 }
378 self.gen_expr(elem);
379 }
380 self.write("]");
381 }
382
383 Expr::Tuple(elements, _) => {
384 self.write("[");
386 for (i, elem) in elements.iter().enumerate() {
387 if i > 0 {
388 self.write(", ");
389 }
390 self.gen_expr(elem);
391 }
392 self.write("]");
393 }
394
395 Expr::Index { object, index, .. } => {
396 self.gen_expr(object);
397 self.write("[");
398 self.gen_expr(index);
399 self.write("]");
400 }
401
402 Expr::Field { object, field, .. } => {
403 self.gen_expr(object);
404 self.write(&format!(".{}", field));
405 }
406
407 Expr::MethodCall { receiver, method, args, .. } => {
408 self.gen_expr(receiver);
409 self.write(&format!(".{}(", method));
410 for (i, arg) in args.iter().enumerate() {
411 if i > 0 {
412 self.write(", ");
413 }
414 self.gen_expr(&arg.value);
415 }
416 self.write(")");
417 }
418
419 Expr::Struct { name, fields, .. } => {
420 self.write(&format!("new {}(", name));
421 for (i, (_, expr)) in fields.iter().enumerate() {
422 if i > 0 {
423 self.write(", ");
424 }
425 self.gen_expr(expr);
426 }
427 self.write(")");
428 }
429
430 Expr::If { condition, then_branch, else_branch, .. } => {
431 self.write("(");
432 self.gen_expr(condition);
433 self.write(" ? ");
434 self.gen_block_as_expr(then_branch);
435 self.write(" : ");
436 if let Some(else_br) = else_branch {
437 match else_br.as_ref() {
438 ElseBranch::Else(else_block) => self.gen_block_as_expr(else_block),
439 ElseBranch::ElseIf { .. } => {
440 self.write("/* else-if */null");
442 }
443 }
444 } else {
445 self.write("null");
446 }
447 self.write(")");
448 }
449
450 Expr::Match { scrutinee, arms, .. } => {
451 self.write("(() => {");
453 self.indent();
454 self.writeln("");
455 self.write("const __match = ");
456 self.gen_expr(scrutinee);
457 self.writeln(";");
458
459 for (i, arm) in arms.iter().enumerate() {
460 if i == 0 {
461 self.write("if (");
462 } else {
463 self.write("else if (");
464 }
465 self.gen_pattern_match("__match", &arm.pattern);
466 self.writeln(") {");
467 self.indent();
468 self.write("return ");
469 self.gen_expr(&arm.body);
470 self.writeln(";");
471 self.dedent();
472 self.write("} ");
473 }
474 self.writeln("");
475 self.writeln("throw new Error('Non-exhaustive match');");
476 self.dedent();
477 self.write("})()");
478 }
479
480 Expr::Lambda { params, body, .. } => {
481 let param_names = params.iter()
482 .map(|p| p.name.clone())
483 .collect::<Vec<_>>()
484 .join(", ");
485 self.write(&format!("({}) => ", param_names));
486 self.gen_expr(body);
487 }
488
489 Expr::Block(block, _) => {
490 self.write("(() => {");
491 self.indent();
492 self.writeln("");
493 self.gen_block(block);
494 self.dedent();
495 self.write("})()");
496 }
497
498 Expr::Assign { target, value, .. } => {
499 self.gen_expr(target);
500 self.write(" = ");
501 self.gen_expr(value);
502 }
503
504 Expr::FString(parts, _) => {
505 self.write("`");
506 for part in parts {
507 match part {
508 Expr::String(s, _) => self.write(s),
509 _ => {
510 self.write("${");
511 self.gen_expr(part);
512 self.write("}");
513 }
514 }
515 }
516 self.write("`");
517 }
518
519 Expr::JSX(node, _) => {
520 self.gen_jsx(node);
521 }
522
523 Expr::EnumVariant { enum_name, variant, fields, .. } => {
524 self.write(&format!("{}.{}(", enum_name, variant));
525 match fields {
526 EnumVariantFields::Unit => {}
527 EnumVariantFields::Tuple(exprs) => {
528 for (i, expr) in exprs.iter().enumerate() {
529 if i > 0 {
530 self.write(", ");
531 }
532 self.gen_expr(expr);
533 }
534 }
535 EnumVariantFields::Struct(named) => {
536 for (i, (_, expr)) in named.iter().enumerate() {
537 if i > 0 {
538 self.write(", ");
539 }
540 self.gen_expr(expr);
541 }
542 }
543 }
544 self.write(")");
545 }
546
547 _ => {
548 self.write("/* unsupported expr */");
549 }
550 }
551 }
552
553 fn gen_jsx(&mut self, node: &JSXNode) {
554 match node {
555 JSXNode::Element { tag, attributes, children, .. } => {
556 self.write(&format!("(() => {{"));
558 self.indent();
559 self.writeln("");
560 self.writeln(&format!("const __el = document.createElement('{}');", tag));
561
562 for attr in attributes {
564 match &attr.value {
565 JSXAttrValue::String(s) => {
566 if attr.name == "class" {
567 self.writeln(&format!("__el.className = '{}';", s));
568 } else {
569 self.writeln(&format!("__el.setAttribute('{}', '{}');", attr.name, s));
570 }
571 }
572 JSXAttrValue::Bool(b) => {
573 if *b {
574 self.writeln(&format!("__el.setAttribute('{}', '');", attr.name));
575 }
576 }
577 JSXAttrValue::Expr(expr) => {
578 if attr.name.starts_with("on_") {
579 let event = attr.name.trim_start_matches("on_");
581 self.write(&format!("__el.addEventListener('{}', ", event));
582 self.gen_expr(expr);
583 self.writeln(");");
584 } else if attr.name == "class" {
585 self.write("__el.className = ");
586 self.gen_expr(expr);
587 self.writeln(";");
588 } else {
589 self.write(&format!("__el.setAttribute('{}', ", attr.name));
590 self.gen_expr(expr);
591 self.writeln(");");
592 }
593 }
594 }
595 }
596
597 for child in children {
599 self.write("__el.appendChild(");
600 self.gen_jsx(child);
601 self.writeln(");");
602 }
603
604 self.writeln("return __el;");
605 self.dedent();
606 self.write("})()");
607 }
608
609 JSXNode::Text(text, _) => {
610 self.write(&format!("document.createTextNode('{}')", text.escape_default()));
611 }
612
613 JSXNode::Expression(expr) => {
614 self.write("(() => {");
615 self.indent();
616 self.writeln("");
617 self.write("const __val = ");
618 self.gen_expr(expr);
619 self.writeln(";");
620 self.writeln("if (typeof __val === 'string' || typeof __val === 'number') {");
621 self.indent();
622 self.writeln("return document.createTextNode(String(__val));");
623 self.dedent();
624 self.writeln("} else if (__val instanceof Node) {");
625 self.indent();
626 self.writeln("return __val;");
627 self.dedent();
628 self.writeln("} else {");
629 self.indent();
630 self.writeln("return document.createTextNode('');");
631 self.dedent();
632 self.writeln("}");
633 self.dedent();
634 self.write("})()");
635 }
636
637 JSXNode::ComponentCall { name, props, children, .. } => {
638 self.write(&format!("{}({{", name));
639 for (i, prop) in props.iter().enumerate() {
640 if i > 0 {
641 self.write(", ");
642 }
643 self.write(&format!("{}: ", prop.name));
644 match &prop.value {
645 JSXAttrValue::String(s) => self.write(&format!("'{}'", s)),
646 JSXAttrValue::Bool(b) => self.write(&b.to_string()),
647 JSXAttrValue::Expr(e) => self.gen_expr(e),
648 }
649 }
650 if !children.is_empty() {
651 if !props.is_empty() {
652 self.write(", ");
653 }
654 self.write("children: [");
655 for (i, child) in children.iter().enumerate() {
656 if i > 0 {
657 self.write(", ");
658 }
659 self.gen_jsx(child);
660 }
661 self.write("]");
662 }
663 self.write("})");
664 }
665
666 JSXNode::Fragment(children, _) => {
667 self.write("(() => {");
668 self.indent();
669 self.writeln("");
670 self.writeln("const __frag = document.createDocumentFragment();");
671 for child in children {
672 self.write("__frag.appendChild(");
673 self.gen_jsx(child);
674 self.writeln(");");
675 }
676 self.writeln("return __frag;");
677 self.dedent();
678 self.write("})()");
679 }
680
681 JSXNode::For { binding, iter, body, .. } => {
682 self.write("(() => {");
683 self.indent();
684 self.writeln("");
685 self.writeln("const __frag = document.createDocumentFragment();");
686 self.write(&format!("for (const {} of ", binding));
687 self.gen_expr(iter);
688 self.writeln(") {");
689 self.indent();
690 self.write("__frag.appendChild(");
691 self.gen_jsx(body);
692 self.writeln(");");
693 self.dedent();
694 self.writeln("}");
695 self.writeln("return __frag;");
696 self.dedent();
697 self.write("})()");
698 }
699
700 JSXNode::If { condition, then_branch, else_branch, .. } => {
701 self.write("(() => {");
702 self.indent();
703 self.writeln("");
704 self.write("if (");
705 self.gen_expr(condition);
706 self.writeln(") {");
707 self.indent();
708 self.write("return ");
709 self.gen_jsx(then_branch);
710 self.writeln(";");
711 self.dedent();
712 if let Some(else_node) = else_branch {
713 self.writeln("} else {");
714 self.indent();
715 self.write("return ");
716 self.gen_jsx(else_node);
717 self.writeln(";");
718 self.dedent();
719 }
720 self.writeln("}");
721 self.writeln("return document.createTextNode('');");
722 self.dedent();
723 self.write("})()");
724 }
725 }
726 }
727
728 fn gen_block_as_expr(&mut self, block: &Block) {
729 self.write("(() => {");
730 self.indent();
731 self.writeln("");
732 self.gen_block(block);
733 self.dedent();
734 self.write("})()");
735 }
736
737 fn gen_pattern_match(&mut self, scrutinee: &str, pattern: &Pattern) {
738 match pattern {
739 Pattern::Wildcard(_) => self.write("true"),
740 Pattern::Binding { .. } => self.write("true"),
741 Pattern::Literal(expr) => {
742 self.write(&format!("{} === ", scrutinee));
743 self.gen_expr(expr);
744 }
745 Pattern::Variant { enum_name, variant, fields, .. } => {
746 if let Some(enum_name) = enum_name {
747 self.write(&format!("{}.type === '{}' && {}.tag === '{}'",
748 scrutinee, enum_name, scrutinee, variant));
749 } else {
750 self.write(&format!("{}.tag === '{}'", scrutinee, variant));
751 }
752
753 match fields {
755 VariantPatternFields::Tuple(patterns) => {
756 for (i, _) in patterns.iter().enumerate() {
757 self.write(&format!(" && typeof {}._{} !== 'undefined'", scrutinee, i));
758 }
759 }
760 _ => {}
761 }
762 }
763 _ => self.write("false"),
764 }
765 }
766
767 fn gen_binop(&self, op: BinaryOp) -> &'static str {
768 match op {
769 BinaryOp::Add => "+",
770 BinaryOp::Sub => "-",
771 BinaryOp::Mul => "*",
772 BinaryOp::Div => "/",
773 BinaryOp::Mod => "%",
774 BinaryOp::Pow => "**",
775 BinaryOp::Eq => "===",
776 BinaryOp::Ne => "!==",
777 BinaryOp::Lt => "<",
778 BinaryOp::Le => "<=",
779 BinaryOp::Gt => ">",
780 BinaryOp::Ge => ">=",
781 BinaryOp::And => "&&",
782 BinaryOp::Or => "||",
783 BinaryOp::BitAnd => "&",
784 BinaryOp::BitOr => "|",
785 BinaryOp::BitXor => "^",
786 BinaryOp::Shl => "<<",
787 BinaryOp::Shr => ">>",
788 BinaryOp::Assign => "=",
789 BinaryOp::AddAssign => "+=",
790 BinaryOp::SubAssign => "-=",
791 BinaryOp::MulAssign => "*=",
792 BinaryOp::DivAssign => "/=",
793 BinaryOp::Range | BinaryOp::RangeInclusive => {
794 "/* range */"
796 }
797 }
798 }
799
800 fn gen_unop(&self, op: UnaryOp) -> &'static str {
801 match op {
802 UnaryOp::Neg => "-",
803 UnaryOp::Not => "!",
804 UnaryOp::BitNot => "~",
805 UnaryOp::Ref | UnaryOp::RefMut | UnaryOp::Deref => {
806 ""
808 }
809 }
810 }
811}