From d2ced70a8eb883e5710f66e80491d5e8cd8bf17f Mon Sep 17 00:00:00 2001 From: cs01 Date: Mon, 2 Mar 2026 11:25:48 -0800 Subject: [PATCH 1/2] allow inline arrow functions as httpServe handler arg --- examples/http-server.ts | 6 +-- src/codegen/llvm-generator.ts | 84 +++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/examples/http-server.ts b/examples/http-server.ts index a488c82e..f4b96e5a 100644 --- a/examples/http-server.ts +++ b/examples/http-server.ts @@ -79,8 +79,4 @@ console.log(" curl -X POST -d 'hello' http://localhost:" + port + "/echo"); console.log(" curl -H 'Authorization: Bearer token' http://localhost:" + port + "/headers"); console.log(""); -function handleRequest(req: HttpRequest): HttpResponse { - return app.handle(req); -} - -httpServe(port, handleRequest); +httpServe(port, (req: HttpRequest) => app.handle(req)); diff --git a/src/codegen/llvm-generator.ts b/src/codegen/llvm-generator.ts index 87a7c285..d6b78503 100644 --- a/src/codegen/llvm-generator.ts +++ b/src/codegen/llvm-generator.ts @@ -2449,22 +2449,42 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { let hasHeaders = false; let hasBodyLen = false; const handlerName = this.httpHandlers[0]; + let handlerReturnType: string | null = null; for (let fi = 0; fi < this.ast.functions.length; fi++) { const func = this.ast.functions[fi]; if (func && func.name === handlerName && func.returnType) { - const retIface = this.getInterfaceFromAST(func.returnType); - if (retIface) { - const fields = (retIface as { fields: { name: string }[] }).fields; - for (let fj = 0; fj < fields.length; fj++) { - if (fields[fj].name === "headers") { - hasHeaders = true; - } - if (fields[fj].name === "bodyLen") { - hasBodyLen = true; - } + handlerReturnType = func.returnType; + break; + } + } + if (!handlerReturnType) { + const liftedFuncs = this.exprGen.arrowFunctionGen.getLiftedFunctions(); + for (let fi = 0; fi < liftedFuncs.length; fi++) { + const func = liftedFuncs[fi]; + const lf = func as { + name: string; + params: string[]; + body: BlockStatement; + returnType?: string; + }; + if (lf.name === handlerName && lf.returnType) { + handlerReturnType = lf.returnType; + break; + } + } + } + if (handlerReturnType) { + const retIface = this.getInterfaceFromAST(handlerReturnType); + if (retIface) { + const fields = (retIface as { fields: { name: string }[] }).fields; + for (let fj = 0; fj < fields.length; fj++) { + if (fields[fj].name === "headers") { + hasHeaders = true; + } + if (fields[fj].name === "bodyLen") { + hasBodyLen = true; } } - break; } } @@ -3558,6 +3578,30 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { return ir; } + private inferArrowHandlerReturnType(arrow: ArrowFunctionNode): string | null { + const body = arrow.body as { type: string }; + let expr: { type: string } | null = null; + if (body.type === "block") { + const stmts = (arrow.body as { statements: { type: string; value?: { type: string } }[] }) + .statements; + for (let i = 0; i < stmts.length; i++) { + if (stmts[i].type === "return" && stmts[i].value) { + expr = stmts[i].value!; + break; + } + } + } else { + expr = body; + } + if (!expr || expr.type !== "method_call") return null; + const mc = expr as { type: string; object: Expression; method: string }; + if ((mc.object as { type: string }).type !== "variable") return null; + const varName = (mc.object as VariableNode).name; + const className = this.symbolTable.getConcreteClass(varName); + if (!className) return null; + return this.getMethodReturnType(className, mc.method); + } + // Generate HTTP server - creates a TCP server that parses HTTP and calls handler public generateHttpServe(expr: CallNode, params: string[]): string { if (expr.args.length < 2) { @@ -3569,10 +3613,22 @@ export class LLVMGenerator extends BaseGenerator implements IGeneratorContext { const portValue = this.generateExpression(expr.args[0], params); const handlerArg = expr.args[1]; - if (handlerArg.type !== "variable") { - return this.emitError("httpServe() handler must be a function reference", expr.loc); + let handlerName: string; + if (handlerArg.type === "variable") { + handlerName = (handlerArg as VariableNode).name; + } else if (handlerArg.type === "arrow_function") { + const arrowExpr = handlerArg as ArrowFunctionNode; + const returnTypeName = this.inferArrowHandlerReturnType(arrowExpr); + handlerName = this.exprGen.arrowFunctionGen.generateArrowFunction(arrowExpr, params, { + paramTypes: ["i8*"], + returnType: returnTypeName || "i8*", + }); + } else { + return this.emitError( + "httpServe() handler must be a function reference or arrow function", + expr.loc, + ); } - const handlerName = (handlerArg as VariableNode).name; // Track handler for http server event handler generation this.httpHandlers.push(handlerName); From ae184015f5aff528da5b2a405c69ad6963fd5671 Mon Sep 17 00:00:00 2001 From: cs01 Date: Mon, 2 Mar 2026 11:32:14 -0800 Subject: [PATCH 2/2] add declare module blocks for chadscript/* stdlib modules --- chadscript.d.ts | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/chadscript.d.ts b/chadscript.d.ts index 01b82ebc..296afe4d 100644 --- a/chadscript.d.ts +++ b/chadscript.d.ts @@ -318,3 +318,56 @@ interface MultipartPart { data: string; dataLen: number; } + +// ============================================================================ +// stdlib modules (import { ... } from "chadscript/*") +// ============================================================================ + +declare module "chadscript/argparse" { + export class ArgumentParser { + constructor(programName: string, description: string); + addFlag(name: string, shortFlag: string, help: string): void; + addOption(name: string, shortFlag: string, help: string, defaultVal: string): void; + parse(argv: string[]): number; + getFlag(name: string): boolean; + getOption(name: string): string; + } +} + +declare module "chadscript/router" { + export class RouterRequest { + method: string; + path: string; + body: string; + contentType: string; + headers: string; + param(name: string): string; + header(name: string): string; + } + + export class Context { + req: RouterRequest; + status(code: number): Context; + header(name: string, value: string): Context; + text(body: string): HttpResponse; + json(data: string): HttpResponse; + html(body: string): HttpResponse; + redirect(url: string): HttpResponse; + } + + export class Router { + get(pattern: string, handler: (c: Context) => HttpResponse): void; + post(pattern: string, handler: (c: Context) => HttpResponse): void; + put(pattern: string, handler: (c: Context) => HttpResponse): void; + delete(pattern: string, handler: (c: Context) => HttpResponse): void; + all(pattern: string, handler: (c: Context) => HttpResponse): void; + notFound(handler: (c: Context) => HttpResponse): void; + handle(req: HttpRequest): HttpResponse; + } +} + +declare module "chadscript/http-utils" { + export function getHeader(headersRaw: string, name: string): string; + export function parseQueryString(qs: string): Map; + export function parseCookies(cookieHeader: string): Map; +}