feat: add method call support and analyzeFull

- Add analyzeFull() to return Sema context with method table
- Improve method call desugaring: obj.method() → Type_method(obj)
- Search methodTable by method name when type inference fails
- Add methods.bux example demonstrating struct with extend blocks
- Use analyzeFull in cli.nim for proper method resolution
This commit is contained in:
2026-05-30 23:22:33 +03:00
parent 52608d5601
commit b59e852330
5 changed files with 61 additions and 12 deletions
+38
View File
@@ -0,0 +1,38 @@
// Methods - Struct with methods using extend
extern func Std_Io_PrintLine(s: String);
extern func Std_Io_PrintInt(n: int);
struct Rectangle {
width: int;
height: int;
}
extend Rectangle {
func Area(self: Rectangle) -> int {
return self.width * self.height;
}
func Perimeter(self: Rectangle) -> int {
return 2 * (self.width + self.height);
}
}
func Main() -> int {
let rect: Rectangle = Rectangle { width: 10, height: 5 };
Std_Io_PrintLine("Rectangle:");
Std_Io_PrintLine("Width = ");
Std_Io_PrintInt(rect.width);
Std_Io_PrintLine("");
Std_Io_PrintLine("Height = ");
Std_Io_PrintInt(rect.height);
Std_Io_PrintLine("");
Std_Io_PrintLine("Area = ");
Std_Io_PrintInt(rect.Area());
Std_Io_PrintLine("");
Std_Io_PrintLine("Perimeter = ");
Std_Io_PrintInt(rect.Perimeter());
Std_Io_PrintLine("");
return 0;
}
+2 -4
View File
@@ -226,7 +226,7 @@ proc cmdBuild*(args: seq[string], opts: GlobalOptions): int =
for d in parseRes.diagnostics:
echo &"error: {d.message} at {d.loc}"
return 1
let semaRes = analyze(parseRes.module)
let (semaRes, semaCtx) = analyzeFull(parseRes.module)
if semaRes.hasErrors:
printError(&"type errors in {path}", useColor)
for d in semaRes.diagnostics:
@@ -235,9 +235,7 @@ proc cmdBuild*(args: seq[string], opts: GlobalOptions): int =
return 1
# Lower to HIR
var s = Sema(module: parseRes.module, globalScope: newScope())
s.collectGlobals()
let hirModule = lowerModule(parseRes.module, s)
let hirModule = lowerModule(parseRes.module, semaCtx)
# Generate C code
var cbe = initCBackend()
+13 -8
View File
@@ -148,22 +148,27 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
of ekCall:
# Method call desugaring: obj.method(args) → Type_method(obj, args)
if expr.exprCallCallee.kind == ekField:
let recvType = ctx.resolveExprType(expr.exprCallCallee.exprFieldObj)
let methodName = expr.exprCallCallee.exprFieldName
var typeName = ""
if recvType.kind == tkNamed: typeName = recvType.name
elif recvType.isPointer and recvType.inner.len > 0 and recvType.inner[0].kind == tkNamed:
typeName = recvType.inner[0].name
if typeName != "" and ctx.methodTable.hasKey(typeName):
for minfo in ctx.methodTable[typeName]:
# Try to find the method in methodTable
for typeName, methods in ctx.methodTable:
for minfo in methods:
if minfo.name == methodName:
# Desugar: obj.method(args) → Type_method(&obj, args)
# Found the method - desugar to Type_method(receiver, args)
let mangledName = typeName & "_" & methodName
var args: seq[HirNode] = @[]
args.add(ctx.lowerExpr(expr.exprCallCallee.exprFieldObj))
for arg in expr.exprCallArgs:
args.add(ctx.lowerExpr(arg))
return hirCall(mangledName, args, typ, loc)
# Not a method call - treat as field access + call (function pointer)
let callee = ctx.lowerExpr(expr.exprCallCallee)
var args: seq[HirNode] = @[]
for arg in expr.exprCallArgs:
args.add(ctx.lowerExpr(arg))
return HirNode(kind: hCallIndirect, callIndirectCallee: callee,
callIndirectArgs: args, typ: typ, loc: loc)
# Regular function call
var calleeName = ""
+8
View File
@@ -573,3 +573,11 @@ proc analyze*(modu: Module): SemaResult =
sema.collectGlobals()
sema.checkBodies()
result = SemaResult(diagnostics: sema.diagnostics)
proc analyzeFull*(modu: Module): tuple[result: SemaResult, sema: Sema] =
## Analyze module and return both result and full Sema context
## Use this when you need the Sema for lowering (method table, etc.)
var sema = Sema(module: modu, globalScope: newScope())
sema.collectGlobals()
sema.checkBodies()
result = (SemaResult(diagnostics: sema.diagnostics), sema)
BIN
View File
Binary file not shown.