// or a Set out of a type, you need to declare a match option for hash.to_u32
// and define '==' for the type. This is kind of probablimatic and doesn't
// make for great self explanatory or maintainable code. Also I don't like
-// #add_match at all, as it feels like a complete and utter hack.
+// #match at all, as it feels like a complete and utter hack.
//
+
+// Ignore everything that is said below. It all sounded like a good idea
+// at one point, until I started implementing it when I realized that not
+// only is it WAY too complicated and adds too much complexity in the compiler
+// but it doesn't feel like a natural extention to Onyx.
+//
+// Instead, 'interfaces' are going to be much much simpler, but to write
+// and for the compiler to deal with. Effectively, they are compile time checks
+// that assert that a particular set of expressions is valid, and optionally
+// return the correct type. They are offered as an extension to overloaded functions
+// and polymorphic functions, instead of being a replacement for them. To remedy
+// the "#add_match" syntax, some work has gone into the parser to make the following
+// legal syntax:
+
+#match hash.to_u32 (x: Vec2) -> u32 { /* .. */ }
+
+// This feels a lot nicer to write and doesn't have the weird line noise of the
+// _ and the ,.
+
+
+
+ValidKey :: interface (T: type_expr) {
+ hash.to_u32(T);
+ T == T;
+}
+
+
+
// To remedy all of this, I think Onyx should have interfaces (or constraints,
// I'm not sure what I want to call them yet). The idea is much like
// an type class in Haskell where you must define a set of procedure types
// that the implementer must define in order to provide the interface.
-// With these interfaces, I would get rid of #add_match and only provide
+// With these interfaces, I would get rid of #match and only provide
// locally overloaded procedures (like print right now), as these are still
// useful.
//
// type knowledge at runtime. To rectify this, let's add a new case that makes
// this work for any type:
-#add_match print_type, #precedence 10 (x: $T) {
+#match print_type #precedence 10 (x: $T) {
printf("Fallback case: called with a {} ({})\n", T, x);
}
-// There are a couple things going on here. The #add_match directive takes two "parameters" separated
-// by a comma: the overloaded procedure to add a match option to, and the option itself. The other
+// There are a couple things going on here. The #match directive takes two "parameters": the overloaded procedure to add a match option to, and the option itself. The other
// thing to notice is the "#precedence 10" specification. Onyx tries to match the arguments you provided
// with each of the options. The first one that matches perfectly, is the one that is used. The order in
// which it does this process is important, and that is why you can control it with the #precedence
// directive. The #precedence directive is allowed in two places: right before the option in the original
-// #match directive, or in front of the option in an #add_match directive, as seen above. Currently,
+// #match directive, or in front of the option in an #match directive, as seen above. Currently,
// the options are sorted in ascending order according to the precedence. I feel like this is backwards,
// so that may change in the future. Either way, setting the precedence allows you to place the options
// in the correct order so something like (x: $T), which will match ANY single argument, is placed last
Person :: struct { name: str; age: i32; }
// The overload option for hashing a person:
-#add_match (package core).hash.to_u32, (use p: Person) -> u32 {
+#match (package core).hash.to_u32 (use p: Person) -> u32 {
return hash.to_u32(name) * 16239563 + age;
}
bh_arr(AstFlags) scope_flags;
b32 hit_unexpected_token : 1;
+
+ // If this is 1, then things that look like calls with immediately be parsed as calls.
+ // However, if this is 0 then things that look like procedure definitions after expressions,
+ // will be parsed as procedure definitions.
+ b32 greedily_consume_calls : 1;
} OnyxParser;
const char* onyx_ast_node_kind_string(AstKind kind);
// This is disabled because I would prefer to have a compile time error for an unsupported type,
// as opposed to a error to check programatically.
//
- // // Inserted after any of the #add_match directives
+ // // Inserted after any of the #match directives
// #precedence 1000 (w: ^io.Writer, v: $T) -> Encoding_Error {
// return .Unsupported_Type;
// }
x, y: f32;
}
-#add_match json.encode, (w: ^io.Writer, v: Vector2) -> json.Encoding_Error {
+#match json.encode (w: ^io.Writer, v: Vector2) -> json.Encoding_Error {
io.write_format(w, "{{\"x\":{},\"y\":{}}}", v.x, v.y);
return .None;
-}
\ No newline at end of file
+}
return a.x == b.x && a.y == b.y;
}
-#add_match io.write, vector2_write
+#match io.write vector2_write
vector2_write :: (writer: ^io.Writer, v: Vector2($T)) {
io.write(writer, "Vector2(");
io.write(writer, v.x);
DataCount :: 0x0c;
}
-#add_match hash.to_u32, macro (w: WasmSection) -> u32 {
+#match hash.to_u32 macro (w: WasmSection) -> u32 {
return hash.to_u32(cast(u32) w);
}
static AstType* parse_type(OnyxParser* parser);
static AstTypeOf* parse_typeof(OnyxParser* parser);
static AstStructType* parse_struct(OnyxParser* parser);
+static AstInterface* parse_interface(OnyxParser* parser);
static void parse_function_params(OnyxParser* parser, AstFunction* func);
static b32 parse_possible_directive(OnyxParser* parser, const char* dir);
+static b32 parse_possible_function_definition_no_consume(OnyxParser* parser);
static b32 parse_possible_function_definition(OnyxParser* parser, AstTyped** ret);
+static b32 parse_possible_quick_function_definition_no_consume(OnyxParser* parser);
static b32 parse_possible_quick_function_definition(OnyxParser* parser, AstTyped** ret);
static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* token);
static AstTyped* parse_global_declaration(OnyxParser* parser);
}
case '(': {
+ if (!parser->greedily_consume_calls) {
+ if (parse_possible_function_definition_no_consume(parser)) goto factor_parsed;
+ if (parse_possible_quick_function_definition_no_consume(parser)) goto factor_parsed;
+ }
+
AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
call_node->token = expect_token(parser, '(');
call_node->callee = retval;
}
}
-static b32 parse_possible_function_definition(OnyxParser* parser, AstTyped** ret) {
+static b32 parse_possible_function_definition_no_consume(OnyxParser* parser) {
if (parser->curr->type == '(') {
OnyxToken* matching_paren = find_matching_paren(parser->curr);
if (matching_paren == NULL) return 0;
if (!is_params) return 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+static b32 parse_possible_function_definition(OnyxParser* parser, AstTyped** ret) {
+ if (parse_possible_function_definition_no_consume(parser)) {
OnyxToken* proc_token = parser->curr;
AstFunction* func_node = parse_function_definition(parser, proc_token);
*ret = (AstTyped *) func_node;
+
return 1;
}
b32 is_baked;
} QuickParam;
-static b32 parse_possible_quick_function_definition(OnyxParser* parser, AstTyped** ret) {
+static b32 parse_possible_quick_function_definition_no_consume(OnyxParser* parser) {
if (parser->curr->type != '(') return 0;
OnyxToken* matching_paren = find_matching_paren(parser->curr);
if (token_after_paren->type != '=' || (token_after_paren + 1)->type != '>')
return 0;
+ return 1;
+}
+
+static b32 parse_possible_quick_function_definition(OnyxParser* parser, AstTyped** ret) {
+ if (!parse_possible_quick_function_definition_no_consume(parser)) return 0;
+
OnyxToken* proc_token = expect_token(parser, '(');
bh_arr(QuickParam) params=NULL;
ENTITY_SUBMIT(operator);
return;
}
- else if (parse_possible_directive(parser, "add_overload") || parse_possible_directive(parser, "add_match")) {
+ else if (parse_possible_directive(parser, "match")) {
AstDirectiveAddOverload *add_overload = make_node(AstDirectiveAddOverload, Ast_Kind_Directive_Add_Overload);
add_overload->token = dir_token;
- add_overload->overloaded_function = (AstNode *) parse_expression(parser, 0);
- expect_token(parser, ',');
+ parser->greedily_consume_calls = 0;
+ add_overload->overloaded_function = (AstNode *) parse_expression(parser, 0);
+ parser->greedily_consume_calls = 1;
if (parse_possible_directive(parser, "precedence")) {
AstNumLit* pre = parse_int_literal(parser);
parser.alternate_entity_placement_stack = NULL;
parser.current_symbol_stack = NULL;
parser.scope_flags = NULL;
+ parser.greedily_consume_calls = 1;
parser.polymorph_context = (PolymorphicContext) {
.root_node = NULL,
}
solid->resolved_proc = polymorphic_proc_try_solidify(solid->poly_proc, solid->known_polyvars, solid->token);
- if (solid->resolved_proc == (AstTyped *) &node_that_signals_a_yield) {
+ if (solid->resolved_proc == (AstNode *) &node_that_signals_a_yield) {
solid->resolved_proc = NULL;
return Symres_Yield_Macro;
}
next := false;
}
-#add_match hash.to_u32, (c: CubePos) -> u32 {
+#match hash.to_u32 (c: CubePos) -> u32 {
return 17 * c.x + 13 * c.y + 11 * c.z + 19 * c.w;
}
y: i32 = 0;
}
-#add_match hash.to_u32, (v: Vec2) -> u32 {
+#match hash.to_u32 (v: Vec2) -> u32 {
return v.x * 11 + v.y * 17;
}
Vec2 :: struct { x: i32; y: i32; }
// Overload print() to print Vec2's.
-#add_match io.write, (use writer: ^io.Writer, use v: Vec2) {
+#match io.write (use writer: ^io.Writer, use v: Vec2) {
io.write_format(writer, "Vec2({}, {})", x, y);
}
Point :: struct { x, y: i32; }
-#add_match hash.to_u32, macro (p: Point) -> #auto do return p.x * 1000 + p.y;
+#match hash.to_u32 macro (p: Point) -> #auto do return p.x * 1000 + p.y;
#operator == macro (p1: Point, p2: Point) -> #auto {
return p1.x == p2.x && p1.y == p2.y;
S << Point.{ 1, 2 };
set.has(^S, Point.{ 1, 2 }) |> println();
-}
\ No newline at end of file
+}
overloaded(z=10);
}
-#add_match overloaded, #precedence 3 (q: i32) { println("Option Q"); }
-#add_match overloaded, #precedence 2 (r: i32) { println("Option R"); }
-#add_match overloaded, #precedence 1 (m: i32) { println("Option M"); }
+#match overloaded #precedence 3 (q: i32) { println("Option Q"); }
+#match overloaded #precedence 2 (r: i32) { println("Option R"); }
+#match overloaded #precedence 1 (m: i32) { println("Option M"); }