added #defined()
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 3 Jul 2021 19:50:40 +0000 (14:50 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 3 Jul 2021 19:50:40 +0000 (14:50 -0500)
bin/onyx
include/onyxastnodes.h
src/onyxastnodes.c
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
tests/defined_test [new file with mode: 0644]
tests/defined_test.onyx [new file with mode: 0644]

index 077a57cb477594c03c49e70e4f1cd9148fd6c960..f41b835425d4090e34dcb0f6ecf5d16456176e2e 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index e6fbfed6fed35a900e402e2bcebb797726b9a3a1..0b0d006768d558db31604aef3dc1af4d8b604191 100644 (file)
@@ -34,6 +34,7 @@
     NODE(DirectiveAddOverload) \
     NODE(DirectiveOperator)    \
     NODE(DirectiveExport)      \
+    NODE(DirectiveDefined)     \
                                \
     NODE(Return)               \
     NODE(Jump)                 \
@@ -180,6 +181,7 @@ typedef enum AstKind {
     Ast_Kind_Directive_Add_Overload,
     Ast_Kind_Directive_Operator,
     Ast_Kind_Directive_Export,
+    Ast_Kind_Directive_Defined,
     Ast_Kind_Call_Site,
 
     Ast_Kind_Note,
@@ -968,6 +970,13 @@ struct AstDirectiveExport {
     AstTyped* export;
 };
 
+struct AstDirectiveDefined {
+    AstTyped_base;
+    AstTyped *expr;
+
+    b32 is_defined: 1;
+};
+
 struct AstNote {
     AstNode_base;
 };
@@ -1245,6 +1254,7 @@ i64 get_expression_integer_value(AstTyped* node);
 b32 cast_is_legal(Type* from_, Type* to_, char** err_msg);
 char* get_function_name(AstFunction* func);
 
+AstNumLit*       make_bool_literal(bh_allocator, b32 b);
 AstNumLit*       make_int_literal(bh_allocator a, i64 value);
 AstNumLit*       make_float_literal(bh_allocator a, f64 value);
 AstRangeLiteral* make_range_literal(bh_allocator a, AstTyped* low, AstTyped* high);
index d7d9831c006946349fe344fca53b4ced669df14e..0571e989339e755168f9cef070cea74c6cae523e 100644 (file)
@@ -83,6 +83,8 @@ static const char* ast_node_names[] = {
     "ADD OVERLOAD",
     "OPERATOR OVERLOAD",
     "EXPORT",
+    "DEFINED",
+    "CALL SITE",
 
     "NOTE",
 
@@ -719,7 +721,14 @@ char* get_function_name(AstFunction* func) {
     return "<anonymous procedure>";
 }
 
+AstNumLit* make_bool_literal(bh_allocator a, b32 b) {
+    AstNumLit* bl = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit);
+    bl->flags |= Ast_Flag_Comptime;
+    bl->type_node = (AstType *) &basic_type_bool;
 
+    bl->value.i = b ? 1 : 0;
+    return bl;
+}
 
 AstNumLit* make_int_literal(bh_allocator a, i64 i) {
     AstNumLit* num = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit);
index d5ee283768dec572ee0277b5f78777d44d7b986a..b7c13d2f60ac92709c046d41d90fb16fb1fa50a0 100644 (file)
@@ -1610,6 +1610,11 @@ CheckStatus check_expression(AstTyped** pexpr) {
             *pexpr = (AstTyped *) ((AstDirectiveSolidify *) expr)->resolved_proc;
             break;
 
+        case Ast_Kind_Directive_Defined:
+            *pexpr = (AstTyped *) make_bool_literal(context.ast_alloc, ((AstDirectiveDefined *) expr)->is_defined);
+            fill_in_type(*pexpr);
+            break;
+
         case Ast_Kind_Compound:
             CHECK(compound, (AstCompound *) expr);
             break;
index b5c7d61f3d6d98552c634f5bc8895f8ff793fecb..e80c64b48f175ef4f87f609c3064a4b0d786c9e2 100644 (file)
@@ -560,6 +560,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             }
             else if (parse_possible_directive(parser, "solidify")) {
                 AstDirectiveSolidify* solid = make_node(AstDirectiveSolidify, Ast_Kind_Directive_Solidify);
+                // :LinearTokenDependent
                 solid->token = parser->curr - 1;
 
                 solid->poly_proc = (AstPolyProc *) parse_factor(parser);
@@ -591,6 +592,19 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 retval = (AstTyped *) solid;
                 break;
             }
+            else if (parse_possible_directive(parser, "defined")) {
+                AstDirectiveDefined* defined = make_node(AstDirectiveDefined, Ast_Kind_Directive_Defined);
+                // :LinearTokenDependent
+                defined->token = parser->curr - 1;
+                defined->type_node = (AstType *) &basic_type_bool;
+
+                expect_token(parser, '(');
+                defined->expr = parse_expression(parser, 0);
+                expect_token(parser, ')');
+
+                retval = (AstTyped *) defined;
+                break;
+            }
 
             onyx_report_error(parser->curr->pos, "Invalid directive in expression.");
             return NULL;
index eb0911139d6dad0aa12ebae2aef5ffc8ed64febe..0c416376caced7261235078ea2d8355314c2af48 100644 (file)
@@ -43,6 +43,7 @@ static SymresStatus symres_for(AstFor* fornode);
 static SymresStatus symres_switch(AstSwitch* switchnode);
 static SymresStatus symres_use(AstUse* use);
 static SymresStatus symres_directive_solidify(AstDirectiveSolidify** psolid);
+static SymresStatus symres_directive_defined(AstDirectiveDefined** pdefined);
 static SymresStatus symres_statement_chain(AstNode** walker);
 static SymresStatus symres_statement(AstNode** stmt, b32 *remove);
 static SymresStatus symres_block(AstBlock* block);
@@ -449,6 +450,10 @@ static SymresStatus symres_expression(AstTyped** expr) {
             SYMRES(directive_solidify, (AstDirectiveSolidify **) expr);
             break;
 
+        case Ast_Kind_Directive_Defined:
+            SYMRES(directive_defined, (AstDirectiveDefined **) expr);
+            break;
+
         case Ast_Kind_Compound:
             SYMRES(compound, (AstCompound *) *expr);
             break;
@@ -709,6 +714,31 @@ static SymresStatus symres_directive_solidify(AstDirectiveSolidify** psolid) {
     return Symres_Success;
 }
 
+static SymresStatus symres_directive_defined(AstDirectiveDefined** pdefined) {
+    AstDirectiveDefined* defined = *pdefined;
+
+    b32 old_report_unresolved_symbols = report_unresolved_symbols;
+    report_unresolved_symbols = 0;
+
+    SymresStatus ss = symres_expression(&defined->expr);
+    if (old_report_unresolved_symbols && ss != Symres_Success) {
+        // The symbol definitely was not found and there is no chance that it could be found.
+        defined->is_defined = 0;
+
+    } else {
+        if (ss == Symres_Success) {
+            defined->is_defined = 1;
+
+        } else {
+            report_unresolved_symbols = old_report_unresolved_symbols;
+            return Symres_Yield_Macro;
+        }
+    }
+
+    report_unresolved_symbols = old_report_unresolved_symbols;
+    return Symres_Success;
+}
+
 static SymresStatus symres_statement(AstNode** stmt, b32 *remove) {
     if (remove) *remove = 0;
 
diff --git a/tests/defined_test b/tests/defined_test
new file mode 100644 (file)
index 0000000..87f8d93
--- /dev/null
@@ -0,0 +1,3 @@
+true
+false
+true
diff --git a/tests/defined_test.onyx b/tests/defined_test.onyx
new file mode 100644 (file)
index 0000000..3cc44f5
--- /dev/null
@@ -0,0 +1,9 @@
+#load "core/std"
+
+use package core
+
+main :: (args: [] cstr) {
+    println(#defined(stdio));
+    println(#defined(foobar));
+    println(#defined(array.Untyped_Array.foo));
+}