M ast/ast.ha => ast/ast.ha +2 -2
@@ 41,8 41,8 @@ export type method_kind = enum {
// A capability input or output.
export type capability = struct {
name: str,
- // Empty string for none
- iface: str,
+ // Empty for none
+ iface: ident,
variadic: bool,
};
M gen/client.ha => gen/client.ha +3 -0
@@ 64,6 64,9 @@ fn c_meth(
iface: *ast::interface,
meth: *ast::method,
) (void | io::error) = {
+ assert(len(meth.caps_in) == 0); // TODO
+ assert(len(meth.caps_out) == 0); // TODO
+
const id: ast::ident = [meth.name];
const name = gen_name_upper(&id);
defer free(name);
M parse/interface.ha => parse/interface.ha +47 -1
@@ 58,7 58,7 @@ fn method(lex: *lex::lexer) (ast::method | error) = {
};
if (try(lex, ltok::LBRACE)? is lex::token) {
- abort(); // TODO: Capability list
+ capabilities(lex, &meth)?;
};
want(lex, ltok::LPAREN)?;
@@ 97,3 97,49 @@ fn method(lex: *lex::lexer) (ast::method | error) = {
want(lex, ltok::SEMICOLON)?;
return meth;
};
+
+fn capabilities(lex: *lex::lexer, meth: *ast::method) (void | error) = {
+ let caps = &meth.caps_in;
+ for (true) {
+ if (try(lex, ltok::RBRACE)? is lex::token) {
+ break;
+ };
+
+ const name = strings::dup(want(lex, ltok::WORD)?.1 as str);
+ let iface: ast::ident = [];
+ if (try(lex, ltok::COLON)? is lex::token) {
+ iface = ident(lex)?;
+ };
+ if (try(lex, ltok::ELLIPSIS) is lex::token) {
+ abort(); // TODO: Variadic caps
+ };
+
+ append(caps, ast::capability {
+ name = name,
+ iface = iface,
+ variadic = false,
+ });
+
+ const next = match (try(lex, ltok::COMMA, ltok::SEMICOLON)?) {
+ case let tok: lex::token =>
+ yield tok;
+ case void =>
+ want(lex, ltok::RBRACE)?;
+ break;
+ };
+
+ switch (next.0) {
+ case ltok::COMMA =>
+ yield;
+ case ltok::SEMICOLON =>
+ if (caps == &meth.caps_in) {
+ return mksyntaxerr(lex, [
+ ltok::COMMA,
+ ltok::RBRACE,
+ ], next);
+ };
+ caps = &meth.caps_out;
+ yield;
+ };
+ };
+};