diff --git a/src/codegen/expressions/method-calls/string-dispatch.ts b/src/codegen/expressions/method-calls/string-dispatch.ts index 95a338a3..a8d4847c 100644 --- a/src/codegen/expressions/method-calls/string-dispatch.ts +++ b/src/codegen/expressions/method-calls/string-dispatch.ts @@ -30,7 +30,7 @@ import { handleMatch, } from "./string-methods.js"; -export function dispatchStringMethod( +function dispatchStringBasicOps( ctx: MethodCallGeneratorContext, method: string, expr: MethodCallNode, @@ -46,14 +46,60 @@ export function dispatchStringMethod( ) return handleConcat(ctx, expr, params); if (method === "repeat") return handleRepeat(ctx, expr, params); + return null; +} + +function dispatchStringPadSplit( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { if (method === "padStart") return handlePadStart(ctx, expr, params); if (method === "padEnd") return handlePadEnd(ctx, expr, params); if (method === "split") return handleSplit(ctx, expr, params); if (method === "startsWith") return handleStartsWith(ctx, expr, params); + return null; +} + +function dispatchStringTrimOps( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { if (method === "endsWith") return handleEndsWith(ctx, expr, params); if (method === "trim") return handleTrim(ctx, expr, params); if (method === "trimStart") return handleTrimStart(ctx, expr, params); if (method === "trimEnd") return handleTrimEnd(ctx, expr, params); + return null; +} + +function dispatchStringReplaceCase( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { + if (method === "replace") return handleReplace(ctx, expr, params); + if (method === "replaceAll") return handleReplaceAll(ctx, expr, params); + if (method === "charAt") return handleCharAt(ctx, expr, params); + if (method === "charCodeAt") return handleCharCodeAt(ctx, expr, params); + return null; +} + +export function dispatchStringMethod( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { + const basic = dispatchStringBasicOps(ctx, method, expr, params); + if (basic) return basic; + const padSplit = dispatchStringPadSplit(ctx, method, expr, params); + if (padSplit) return padSplit; + const trim = dispatchStringTrimOps(ctx, method, expr, params); + if (trim) return trim; if (method === "indexOf") { if (ctx.isStringArrayExpression(expr.object)) return handleStringArrayIndexOf(ctx, expr, params); @@ -74,10 +120,8 @@ export function dispatchStringMethod( !ctx.isObjectArrayExpression(expr.object) ) return handleSlice(ctx, expr, params); - if (method === "replace") return handleReplace(ctx, expr, params); - if (method === "replaceAll") return handleReplaceAll(ctx, expr, params); - if (method === "charAt") return handleCharAt(ctx, expr, params); - if (method === "charCodeAt") return handleCharCodeAt(ctx, expr, params); + const replaceCase = dispatchStringReplaceCase(ctx, method, expr, params); + if (replaceCase) return replaceCase; if (method === "toUpperCase") return handleToUpperCase(ctx, expr, params); if (method === "toLowerCase") return handleToLowerCase(ctx, expr, params); if (method === "toString") { @@ -97,7 +141,7 @@ export function dispatchStringMethod( return null; } -export function dispatchArrayMethod( +function dispatchArrayMutators( ctx: MethodCallGeneratorContext, method: string, expr: MethodCallNode, @@ -113,6 +157,57 @@ export function dispatchArrayMethod( return ctx.arrayGen.generateStringArrayMap(expr, params); return ctx.arrayGen.generateArrayMap(expr, params); } + return null; +} + +function dispatchArrayIterators( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { + if (method === "find") return ctx.arrayGen.generateArrayFind(expr, params); + if (method === "some") return ctx.arrayGen.generateArraySome(expr, params); + if (method === "every") return ctx.arrayGen.generateArrayEvery(expr, params); + if (method === "filter") return ctx.arrayGen.generateArrayFilter(expr, params); + return null; +} + +function dispatchArrayTransforms( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { + if (method === "forEach") return ctx.arrayGen.generateArrayForEach(expr, params); + if (method === "reduce") return ctx.arrayGen.generateArrayReduce(expr, params); + if (method === "reverse") return ctx.arrayGen.generateArrayReverse(expr, params); + if (method === "shift") return ctx.arrayGen.generateArrayShift(expr, params); + return null; +} + +function dispatchArrayReorder( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], +): string | null { + if (method === "unshift") return ctx.arrayGen.generateArrayUnshift(expr, params); + if (method === "findIndex") return ctx.arrayGen.generateArrayFindIndex(expr, params); + if (method === "sort") return ctx.arrayGen.generateArraySort(expr, params); + if (method === "splice") return ctx.arrayGen.generateArraySplice(expr, params); + return null; +} + +export function dispatchArrayMethod( + ctx: MethodCallGeneratorContext, + method: string, + expr: MethodCallNode, + params: string[], + isClassInstance: boolean, +): string | null { + const mutator = dispatchArrayMutators(ctx, method, expr, params, isClassInstance); + if (mutator) return mutator; if ( method === "join" && (ctx.isStringArrayExpression(expr.object) || @@ -120,12 +215,10 @@ export function dispatchArrayMethod( ctx.isObjectArrayExpression(expr.object)) ) return ctx.arrayGen.generateArrayJoin(expr, params); - if (method === "find") return ctx.arrayGen.generateArrayFind(expr, params); - if (method === "some") return ctx.arrayGen.generateArraySome(expr, params); - if (method === "every") return ctx.arrayGen.generateArrayEvery(expr, params); - if (method === "filter") return ctx.arrayGen.generateArrayFilter(expr, params); - if (method === "forEach") return ctx.arrayGen.generateArrayForEach(expr, params); - if (method === "reduce") return ctx.arrayGen.generateArrayReduce(expr, params); + const iterator = dispatchArrayIterators(ctx, method, expr, params); + if (iterator) return iterator; + const transform = dispatchArrayTransforms(ctx, method, expr, params); + if (transform) return transform; if ( method === "slice" && (ctx.isArrayExpression(expr.object) || @@ -140,11 +233,7 @@ export function dispatchArrayMethod( ctx.isObjectArrayExpression(expr.object)) ) return ctx.arrayGen.generateArrayConcat(expr, params); - if (method === "reverse") return ctx.arrayGen.generateArrayReverse(expr, params); - if (method === "shift") return ctx.arrayGen.generateArrayShift(expr, params); - if (method === "unshift") return ctx.arrayGen.generateArrayUnshift(expr, params); - if (method === "findIndex") return ctx.arrayGen.generateArrayFindIndex(expr, params); - if (method === "sort") return ctx.arrayGen.generateArraySort(expr, params); - if (method === "splice") return ctx.arrayGen.generateArraySplice(expr, params); + const reorder = dispatchArrayReorder(ctx, method, expr, params); + if (reorder) return reorder; return null; } diff --git a/src/codegen/infrastructure/type-system.ts b/src/codegen/infrastructure/type-system.ts index eb734a68..176ef1c4 100644 --- a/src/codegen/infrastructure/type-system.ts +++ b/src/codegen/infrastructure/type-system.ts @@ -145,6 +145,45 @@ export function resolvedTypeToLlvm(rt: ResolvedType): string { export type TypeMappingMode = "default" | "param" | "return" | "struct_field" | "json"; +function ffiTypeToLlvm1(tsType: string): string | null { + if (tsType === "i8") return "i8"; + if (tsType === "i16") return "i16"; + if (tsType === "i32") return "i32"; + if (tsType === "i64") return "i64"; + return null; +} + +function ffiTypeToLlvm2(tsType: string): string | null { + if (tsType === "u8") return "i8"; + if (tsType === "u16") return "i16"; + if (tsType === "u32") return "i32"; + if (tsType === "u64") return "i64"; + return null; +} + +function ffiTypeToLlvm3(tsType: string): string | null { + if (tsType === "f32") return "float"; + if (tsType === "f64") return "double"; + if (tsType === "i8_ptr" || tsType === "ptr") return "i8*"; + return null; +} + +function basicTypeToLlvm(tsType: string): string | null { + if (tsType === "string") return "i8*"; + if (tsType === "number" || tsType === "boolean") return "double"; + if (tsType === "void") return "void"; + if (tsType === "string[]") return "%StringArray*"; + return null; +} + +function collectionTypeToLlvm(tsType: string): string | null { + if (tsType === "number[]" || tsType === "boolean[]") return "%Array*"; + if (tsType === "Uint8Array") return "%Uint8Array*"; + if (tsType.endsWith("[]")) return "%ObjectArray*"; + if (tsType.startsWith("Set<")) return "%StringSet*"; + return null; +} + export function canonicalTypeToLlvm( tsType: string, mode: string, @@ -153,26 +192,16 @@ export function canonicalTypeToLlvm( fieldName: string, ): string { if (tsType === null || tsType === undefined || tsType === "") { - // Empty/null type: callers should provide a valid type. These defaults are - // intentional language semantics — untyped returns are double (number), - // untyped params/fields are i8* (pointer, the safer default). if (mode === "return") return "double"; return "i8*"; } - // FFI type passthrough — zero-cost: maps directly to LLVM types with no - // double conversion. Used in `declare function` for calling C code. - if (tsType === "i8") return "i8"; - if (tsType === "i16") return "i16"; - if (tsType === "i32") return "i32"; - if (tsType === "i64") return "i64"; - if (tsType === "u8") return "i8"; - if (tsType === "u16") return "i16"; - if (tsType === "u32") return "i32"; - if (tsType === "u64") return "i64"; - if (tsType === "f32") return "float"; - if (tsType === "f64") return "double"; - if (tsType === "i8_ptr" || tsType === "ptr") return "i8*"; + const ffi1 = ffiTypeToLlvm1(tsType); + if (ffi1) return ffi1; + const ffi2 = ffiTypeToLlvm2(tsType); + if (ffi2) return ffi2; + const ffi3 = ffiTypeToLlvm3(tsType); + if (ffi3) return ffi3; if (fieldName === "nodePtr" || fieldName === "treePtr") return "i8*"; @@ -186,14 +215,10 @@ export function canonicalTypeToLlvm( if (isEnum) return "double"; - if (tsType === "string") return "i8*"; - if (tsType === "number" || tsType === "boolean") return "double"; - if (tsType === "void") return "void"; - if (tsType === "string[]") return "%StringArray*"; - if (tsType === "number[]" || tsType === "boolean[]") return "%Array*"; - if (tsType === "Uint8Array") return "%Uint8Array*"; - if (tsType.endsWith("[]")) return "%ObjectArray*"; - if (tsType.startsWith("Set<")) return "%StringSet*"; + const basic = basicTypeToLlvm(tsType); + if (basic) return basic; + const coll = collectionTypeToLlvm(tsType); + if (coll) return coll; if (tsType.startsWith("Map<")) return "%StringMap*"; if (tsType.startsWith("'") || tsType.startsWith('"')) return "i8*";