Skip to content

Commit

Permalink
Support function parameter groups.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Sep 2, 2024
1 parent 22b6b9d commit 5850e21
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 28 deletions.
6 changes: 2 additions & 4 deletions docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2005,7 +2005,7 @@ The `try catch` statement, `try else` and `try` expressions provide a way to cat
* [Closures.](#closures)
* [Function types.](#function-types)
* [`extern` functions.](#extern-functions)
* [Multiple parameters.](#multiple-parameters)
* [Parameter groups.](#parameter-groups)
* [Named parameters.](#named-parameters)
* [Variadic parameters.](#variadic-parameters)
</td><td valign="top">
Expand Down Expand Up @@ -2189,9 +2189,7 @@ func my_str_hash(s String) int:
var m = IntMap[String, my_str_hash]{}
```
## Multiple parameters.
> _Planned Feature_
## Parameter groups.
When multiple parameters share the same type they can be declared together in a sequence:
```cy
func sum(a, b, c int) int
Expand Down
54 changes: 38 additions & 16 deletions src/sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3643,6 +3643,15 @@ pub fn resolveFuncType(c: *cy.Chunk, func_type: *ast.FuncType) !FuncSigId {
return c.sema.ensureFuncSig(@ptrCast(c.typeStack.items[start..]), ret_t);
}

fn indexOfTypedParam(params: []const *ast.FuncParam, start: usize) ?usize {
for (params[start..], start..) |param, i| {
if (param.type != null) {
return i;
}
}
return null;
}

/// `skip_ct_params` is used when expanding a template.
fn resolveFuncSig(c: *cy.Chunk, func: *cy.Func, skip_ct_params: bool) !FuncSigId {
const func_n = func.decl.?.cast(.funcDecl);
Expand All @@ -3656,24 +3665,28 @@ fn resolveFuncSig(c: *cy.Chunk, func: *cy.Func, skip_ct_params: bool) !FuncSigId
return error.Unexpected;
}

for (func_n.params) |param| {
var param_group_t: cy.TypeId = cy.NullId;
var param_group_end: usize = undefined;
for (func_n.params, 0..) |param, i| {
const paramName = c.ast.nodeString(param.name_type);
if (std.mem.eql(u8, paramName, "self")) {
const self_t = func.parent.parent.?.getStaticType().?;
try c.typeStack.append(c.alloc, self_t);
} else {
if (sig_t == .func) {
if (param.type == null) {
return c.reportError("Expected parameter type.", @ptrCast(param));
var type_id: cy.TypeId = undefined;
if (param.type == null) {
if (param_group_t == cy.NullId or i > param_group_end) {
// Attempt to find group type.
param_group_end = indexOfTypedParam(func_n.params, i + 1) orelse {
return c.reportError("Expected parameter type.", @ptrCast(param));
};
param_group_t = try resolveTypeSpecNode(c, func_n.params[param_group_end].type);
}
type_id = param_group_t;
} else {
if (param.type) |type_spec| {
return c.reportError("Type specifier not allowed in `let` declaration. Declare typed functions with `func`.", type_spec);
}
type_id = try resolveTypeSpecNode(c, param.type);
}

const type_id = try resolveTypeSpecNode(c, param.type);

if (param.template) {
if (skip_ct_params) {
continue;
Expand All @@ -3695,19 +3708,28 @@ fn resolveFuncSig(c: *cy.Chunk, func: *cy.Func, skip_ct_params: bool) !FuncSigId
}

fn pushLambdaFuncParams(c: *cy.Chunk, n: *ast.LambdaExpr) !void {
for (n.params) |param| {
var param_group_t: cy.TypeId = cy.NullId;
var param_group_end: usize = undefined;
if (n.sig_t == .infer) {
return error.Unexpected;
}
for (n.params, 0..) |param, i| {
const paramName = c.ast.nodeString(param.name_type);
if (std.mem.eql(u8, paramName, "self")) {
return c.reportError("`self` is a reserved parameter for methods.", @ptrCast(param));
}
if (n.sig_t == .func) {
if (param.type == null) {
return c.reportError("Expected type specifier.", @ptrCast(param));
var type_id: cy.TypeId = undefined;
if (param.type == null) {
if (param_group_t == cy.NullId or i > param_group_end) {
// Attempt to find group type.
param_group_end = indexOfTypedParam(n.params, i + 1) orelse {
return c.reportError("Expected parameter type.", @ptrCast(param));
};
param_group_t = try resolveTypeSpecNode(c, n.params[param_group_end].type);
}
type_id = param_group_t;
} else {
if (param.type != null) {
return c.reportError("Type specifier not allowed. Declare typed lambdas with `func`.", @ptrCast(param));
}
type_id = try resolveTypeSpecNode(c, param.type);
}
const typeId = try resolveTypeSpecNode(c, param.type);
try c.typeStack.append(c.alloc, typeId);
Expand Down
16 changes: 8 additions & 8 deletions src/tools/cbindgen.cy
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ type State:
type StateType
data dyn

func visitor(cursor dyn, parent dyn, client_data dyn) dyn:
func visitor(cursor, parent, client_data dyn) dyn:
var state State = client_data.asObject()
switch state.type
case StateType.root:
Expand All @@ -198,7 +198,7 @@ func visitor(cursor dyn, parent dyn, client_data dyn) dyn:
else:
throw error.Unsupported

func rootVisitor(cursor dyn, parent dyn, state dyn) dyn:
func rootVisitor(cursor, parent, state dyn) dyn:
var cxName = clang.lib.clang_getCursorDisplayName(cursor)
var name = fromCXString(cxName)

Expand Down Expand Up @@ -354,7 +354,7 @@ func rootVisitor(cursor dyn, parent dyn, state dyn) dyn:

return clang.CXChildVisit_Continue

func structVisitor(cursor dyn, parent dyn, state dyn) dyn:
func structVisitor(cursor, parent, state dyn) dyn:
var cxName = clang.lib.clang_getCursorDisplayName(cursor)
var name = fromCXString(cxName)

Expand All @@ -374,7 +374,7 @@ func structVisitor(cursor dyn, parent dyn, state dyn) dyn:
print "unsupported $(cursor.kind) $(name)"
return clang.CXChildVisit_Continue

func enumVisitor(cursor dyn, parent dyn, state dyn) dyn:
func enumVisitor(cursor, parent, state dyn) dyn:
var cxName = clang.lib.clang_getCursorDisplayName(cursor)
var name = fromCXString(cxName)
var val = clang.lib.clang_getEnumConstantDeclValue(cursor)
Expand Down Expand Up @@ -405,7 +405,7 @@ func genMacros(headerPath String):
var cstate = clang.ffi.bindObjPtr(state)
clang.lib.clang_visitChildren(cursor, cvisitor.ptr(), cstate)

func initListExpr(cursor dyn, parent dyn, state dyn) dyn:
func initListExpr(cursor, parent, state dyn) dyn:
switch cursor.kind
case clang.CXCursor_IntegerLiteral:
var eval = clang.lib.clang_Cursor_Evaluate(cursor)
Expand All @@ -417,7 +417,7 @@ func initListExpr(cursor dyn, parent dyn, state dyn) dyn:

return clang.CXChildVisit_Continue

func initVarVisitor(cursor dyn, parent dyn, state dyn) dyn:
func initVarVisitor(cursor, parent, state dyn) dyn:
var cxName = clang.lib.clang_getCursorDisplayName(cursor)
var name = fromCXString(cxName)

Expand All @@ -437,7 +437,7 @@ func initVarVisitor(cursor dyn, parent dyn, state dyn) dyn:

return clang.CXChildVisit_Continue

func macrosRootVisitor(cursor dyn, parent dyn, state dyn) dyn:
func macrosRootVisitor(cursor, parent, state dyn) dyn:
var cxName = clang.lib.clang_getCursorDisplayName(cursor)
var name = fromCXString(cxName)

Expand Down Expand Up @@ -520,7 +520,7 @@ func fromCXString(cxStr any) String:
dyn cname = clang.lib.clang_getCString(cxStr)
return cname.fromCstr(0)

func toCyType(nameOrSym dyn, forRet dyn) dyn:
func toCyType(nameOrSym, forRet dyn) dyn:
if type(nameOrSym) == symbol:
switch nameOrSym
case symbol.voidPtr : return '*void'
Expand Down
1 change: 1 addition & 0 deletions test/behavior_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ test "Tests." {
run.case("syntax/comment_multiple.cy");
run.case("syntax/compact_block_error.cy");
run.case("syntax/func_missing_param_type_error.cy");
run.case("syntax/func_param_group.cy");
if (!aot) {
run.case("syntax/indentation.cy");
}
Expand Down
39 changes: 39 additions & 0 deletions test/syntax/func_param_group.cy
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use test

-- Functions.
func sum(a, b, c int) int:
return a + b + c

test.eq(sum(1, 2, 3), 6)

func compute(a, b int, c, d String) int:
return a + b + c.len() + d.len()

test.eq(compute(1, 2, 'abc', 'xyz'), 9)

-- Methods.
type T:
i int

func sum(self, a, b, c int) int:
return self.i + a + b + c

func compute(self, a, b int, c, d String) int:
return self.i + a + b + c.len() + d.len()

var o = T{i=10}
test.eq(o.sum(1, 2, 3), 16)
test.eq(o.compute(1, 2, 'abc', 'xyz'), 19)

-- Lambdas.
var sum_fn = func(a, b, c int) int:
return a + b + c

test.eq(sum_fn(1, 2, 3), 6)

var compute_fn = func(a, b int, c, d String) int:
return a + b + c.len() + d.len()

test.eq(compute_fn(1, 2, 'abc', 'xyz'), 9)

--cytest: pass

0 comments on commit 5850e21

Please sign in to comment.