Code Monkey home page Code Monkey logo

Comments (2)

andrewrk avatar andrewrk commented on May 18, 2024

When an if statement is analyzed, the condition is checked for constant expression evaluation. If the condition is available at compile time, then this if statement becomes a conditional compilation construct. Combine this with a compiler function which checks compile information, and we're already almost done:

fn f() {
    if (#compile_var("os") == "linux") {
        // ...
    } else {
        // ...
    }
}

#compile_var() can look up a string in a table of variables defined at compile time. A compile variable might be any type.

Usually, if an if condition's "then" expression or "else" expression is unreachable because the condition is constant, it will generate an "unreachable code" error. However, we can annotate the constant expression with a value indicating that it can differ depending on compile time variables. When this annotation is present, the "unreachable code" error is not generated.

So, conditional compilation is perfectly integrated into the language's syntax within a function. Let's look at outside a function:

const foo : i32 = if (#compile_var("release")) 1234 else 5678;

Global constants and variables can use full expression syntax for their initializers, so this works here too.

How about a global initialized list of things (example), of which the length of the list is dependent on compile time variables?

In C we have:

static const enum SoundIoBackend available_backends[] = {
#ifdef SOUNDIO_HAVE_JACK
    SoundIoBackendJack,
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
    SoundIoBackendPulseAudio,
#endif
#ifdef SOUNDIO_HAVE_ALSA
    SoundIoBackendAlsa,
#endif
#ifdef SOUNDIO_HAVE_COREAUDIO
    SoundIoBackendCoreAudio,
#endif
#ifdef SOUNDIO_HAVE_WASAPI
    SoundIoBackendWasapi,
#endif
    SoundIoBackendDummy,
};

In Zig we take advantage of void array elements being removed from the array:

const available_backends = [
    if (#compile_var("have_jack")) SoundIoBackend.Jack else void,
    if (#compile_var("have_pulse_audio")) SoundIoBackend.PulseAudio else void,
    if (#compile_var("have_alsa")) SoundIoBackend.Alsa else void,
    if (#compile_var("have_core_audio")) SoundIoBackend.CoreAudio else void,
    if (#compile_var("have_wasapi")) SoundIoBackend.Wasapi else void,
    SoundIoBackend.Dummy,
];

Note that technically the else void could be omitted since an if statement with no else defaults to else void. It may be that void is the wrong type for this, but this construct is powerful and so if void is the wrong type then we may introduce a "deleted array item" type.

Next problem. Anything that you can export, you might want to not export it. So, for any top level declaration for which export is valid - this currently includes functions, global variables, enums, and structs, we will also define a directive, let's call it #condition() which accepts a boolean expression which decides if the top level declaration is included in the compilation. If the top level declaration is not included, then calling it or otherwise depending upon it is a compile time error. Example:

#condition(#compile_var("os") == "win32")
export fn trace_win32() {
     const err = get_last_win32_error();
     print_win32_error(err);
}

fn f1() {
    if (#compile_var("os") == "win32") {
        trace_win32(); // OK, since const expression eval ensured this didn't actually run when trace_win32 is not exported
    }
    trace_win32(); // error when building with compile var "os" == "win32": trace_win32 symbol not defined
}

Finally the only problem left is the syntax that we use to import C .h files. We don't yet have a syntax for directly importing a C .h file, but it's planned. We would need to conditionally import some .h files and not others depending on compile variables. I'll defer figuring out how that will work until we actually have that construct. But I will mention that it's probably planned that the best use of the auto C .h file importing feature is to limit it to a single invocation that would declare the order in which preprocessor defines are defined and what their values are as well as the order of (virtual) #includes. So, one could associate preprocessor defines with expressions and #includes with boolean expressions.

from zig.

andrewrk avatar andrewrk commented on May 18, 2024

This all works now.

from zig.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.