Reuh / candran

a Lua dialect and simple preprocessor
MIT License
28 stars 2 forks source link

macros #3

Closed splitice closed 3 years ago

splitice commented 3 years ago

Any plans to add macro support?

Something that would make syntax like this possible:

#ifdef _DEBUG
#define log(self, ...) self:log(...)
#else
#define log(self, ...) -- ...
#endif

I feel that would be alot more powerful than conditionals alone

Reuh commented 3 years ago

I don't use the preprocessor a lot myself, so yeah there's probably a lot more that could be done.

I think something like that can be added:

#if _DEBUG
#define("log(self, ...)", "self:log(...)")
#else
#-- ....
#end

and that would then replace every call to log with this, correctly replacing arguments, e.g. log(a, "test") with a:log("test")

If the identifier is already defined, I guess it would make sense for the macro to take priority?

local val = 5
#define("val", "10")
print(val) -- 10

Is that what you're looking for? I should be able to get a working version relatively quickly if so

splitice commented 3 years ago

I would suggest something that allows for statements to conditionally compiled out and conditionally extended.

The preprocessor is what led me to evaluate this project.

Reuh commented 3 years ago
#if _DEBUG
#define("log(self, ...)", "self:log(...)")
#else
#define("log(self, ...)", "")
#end

which would replace log(self, ...) with self:log(...) if _DEBUG was set, if it is not, log(self, ...) is removed from the compiled code

splitice commented 3 years ago

Yes I think that syntax could work :)

Personally I'd prefer to not have the quotes (more C like) but I understand why you would want them.

Reuh commented 3 years ago

The preprocessor is based on Candran/Lua syntax so I can't remove those quotes, or this will create some syntax errors.

I have pushed a working version of this on the macros branch. It seems to work pretty well, so unless there's something missing or I find an issue with this, I'll merge it into master soon.

splitice commented 3 years ago

A few more suggestions.

  1. Also support [[ string ]]
  2. support a strizing macro (i.e __STR__()) - great for assertions
  3. This one probably deserves it's own issue but support for doing the token replacement with lua functions dynamically.

Ideally the language should be good enough that 3 is not required but it opens the door to many interesting options.

Some use cases I can think of.

  1. Constant expression folding (or perhaps this would be a useful feature on its own)
  2. Metaprogramming
Reuh commented 3 years ago
  1. Should already be supported. If I wasn't clear, the preprocessor is run as normal Lua code, so every Lua and Candran feature is already supported.
  2. I'm not familiar with __STR__, do you mean something like # in C macros, which create a string with the argument? Like
    #define test(a) print(#a)
    test(42) // expands to print("42")
  3. This would indeed be pretty interesting. An easy way to add that would be to expect the replacement function to return the replacement code as a string, e.g.
    #define("logcondition(condition, str)", function(condition, str)
    #    return "if "..condition.." then self:log("..str..")"
    #end)
    logcondition(true, "bla") -- expands to if true then self:log("bla") end

    This could be use to define a constant(expr) macro which would calculate the expression at compile-time (the macro would execute the expression and serialize the result to Lua code): This would be a pretty flexible way to do this but not necessarily super elegant.

splitice commented 3 years ago
  1. Sounds good
  2. A=constexpr(1+1) (as a macro) or const A=1+1 (as a native feature) would be my idea of a syntax.
  3. Yes #define("assert(what)", "_assert(what, __STR__(what))") was what I was thinking of
Reuh commented 3 years ago

I have added the macro replacement as I described to the macros branch, as well as __STR__ and constexpr as built-in macros, which works as we described as well.

For now these macros are always automatically defined. I want Candran to be fully compatible with unmodified Lua code by default, so these should not be enabled by default (in case some Lua code define functions with the same name as the built-in macros). I can think of two ways to enable those macros: 1) a compiler option, for example -builtinmacros 2) or you have to include a file to load the macros in each file where you use them, for example #import("candran.macros")

If the user want to define their own macros, they would import them using something like #import("usermacros") as well, so 2) would be more consistent. But I don't have a huge preference.

splitice commented 3 years ago

perhaps constexpr should be __CONSTEXPR__ then __*__ could be informally reserved for internal?

From a users point of view being able to express things from the command line makes tooling much simpler. Although simply allowing any import e.g -e import candran.macros would be sufficient where -e is the preoprocessor evaluator.

Reuh commented 3 years ago

Yes, reserving __*__ for internal macros seems reasonable. Pushed this onto the macros branch.

Reuh commented 3 years ago

Merged and released with Candran 1.0.0.