"7+-167+521"
"1<3-55mod2"
"2+-2+4^4"
I need to actually execute these string as literal code and get a value and I am stuck trying to construct a macro that will do this.
To do this you'd need to make a macro that takes a static string and operates on it. I have no clue the requirements of what you're after, but I've written a very simple 'parser' that simply inserts spaces between operators where it makes sense then uses Nim's parseExpr to just get Nim to handle it(there are probably too many assumptions to make this valid for your use case though).
import std/[macros, strutils, math]
macro nimify(s: static string): untyped =
type ParserState = enum
inNothing, inOp, inNumber
var
myString = s
i = 0
parserState = inNothing
if s[i] notin {'+', '-'} + Digits:
error("Invalid string")
proc insertSpace() =
if i - 1 > 0 and myString[i - 1] notin WhiteSpace:
myString.insert(" ", i)
inc i
while i < myString.len:
case myString[i]
of Digits:
if parserState == inOp:
insertSpace()
parserState = inNumber
of WhiteSpace:
discard
of {'-', '+'}:
if parserState == inOp:
insertSpace()
parserState = inNumber
else:
insertSpace()
parserState = inOp
else:
if parserState != inOp:
insertSpace()
parserState = inOp
inc i
echo myString
parseExpr(myString)
echo nimify"10+3"
echo nimify"10-3"
echo nimify"7+-167+521"
echo nimify"1<3-55mod2"
echo nimify"10mod3^4*3div3"
One thing...I get this compile error when trying to run the code like so:
let x = "1+1"
echo nimify(x)
/home/xioren/Documents/coding/nim/burner.nim(190, 12) Error: type mismatch: got <string>
but expected one of:
macro nimify(s: static string): untyped
first type mismatch at position: 1
required type for s: static[string]
but expression 'x' is of type: string
expression: nimify(x)
Well, at least if it's only math expressions you need to evaluate, you may be in luck, as there's already a small expression evaluator by Yardanico:
The power of macros is exactly what you seem to perceive as a weakness. Most languages doesn't allow you to modify your own code on compile-time, some offer limited support. Nim is really one of the few languages which offers this level of compile-time modification of code, which is a really powerful feature. The fact that macros aren't available on runtime is simply because Nim code doesn't exist on runtime. When you compile Nim it first gets compiled down to C, then that gets further compiled down to machine instructions. So by the time you're executing your code the program isn't really Nim any longer. As someone else have mentioned, it is possible to use the Nim compiler as a library, either to create your own modified compiler, or to execute NimScript (the subset of the Nim language which is executed in macros and .nimble files during compilation) but this is a rather huge dependency just to do a little bit of math.
As other have mentioned if you want to do math on runtime from strings it's better to use a math evaluation library, Yardanico has one which is linked above, and I have written one which can be used for RPN expressed math.
Unfortunately it's more complex than that. Here is the rube goldberg code I need to convert to Nim. These are steps operating on an array. (youtubes anti-piracy measure)
try{try{4<c[28]&&(6<c[new Date("December 31 1969 20:00:01 EDT")/1E3]?(0,c[17])((((0,c[new Date("January 01 1970 08:30:40 +0830")/1E3])(c[103]),c[68])(c[16]),c[90])(c[98],c[61]),c[84],(0,c[84])(c[77],c[6]),c[54],c[new Date("December 31 1969 20:01:48 EDT")/1E3]):(0,c[79])((0,c[79])((0,c[Math.pow(4,1)+-18012+18084])(c[58],c[92]),c[56],(0,c[76])(c[28],c[4]),c[4]),
c[76],(0,c[30])(c[92],c[54],(0,c[8])()),c[45],c[4])),9>=c[62-Math.pow(3,3)%497]&&(c[33]>30*Math.pow(2,1)-53||((0,c[44])(c[0]),void 0))&&(0,c[56])(c[0]),1<c[57]&&(3<c[62]||((0,c[72])((0,c[76])(c[69],c[92]),(0,c[1])((0,c[78])(c[14],c[82]),c[30],c[92],c[19],(0,c[new Date("1969-12-31T20:00:08.000-04:00")/1E3])()),c[1],(0,c[44])(c[102]),c[76],c[64],c[0]),0))&&(0,c[47])((0,c[63])(c[23],c[82]),c[1],(0,c[new Date("12/31/1969 20:01:18 EDT")/1E3])(c[106],c[4]),(0,c[78])(c[42],c[92]),(0,c[63])(c[67],c[62]),
c[78],c[81],c[Math.pow(8,1)+-9576- -9660])}catch(d){((0,c[30])(c[4],c[36],(0,c[84])()),c[76])(c[31],c[102]),(0,c[30])(c[62],c[108],(0,c[84])())}finally{3<c[26]&&(0>=c[10]||((0,c[1])((0,c[76])(c[98],c[102]),c[30],c[new Date("31 December 1969 18:01:02 CST")/1E3],c[18],(0,c[51])()),NaN))&&(0,c[1])((0,c[78])(c[21],c[102]),c[61],c[40],c[70]),1<c[93]&&(0>=c[41]||((0,c[37])((0,c[37])((0,c[37])((0,c[14])(c[32],c[85]),c[89],c[25],c[9]),c[99],c[43],c[29]),c[99],c[91],c[40]),0))&&(0,c[0])((0,c[37])((0,c[99])(c[17],
c[29]),c[14],c[1],c[98]),c[66],(0,c[66])(c[15+Math.pow(new Date("Wednesday December 31 1969 20:00:04 EDT")/1E3,1)%23],c[48],(0,c[4])()),c[98],c[86],(0,c[8030-Math.pow(5,5)-4894])()),3<c[93]&&(4>=c[71]&&((0,c[37])((0,c[83])((0,c[0])((0,c[14])(c[28],c[98]),c[14],(0,c[37])((0,c[new Date("01 January 1970 02:16:06 +0215")/1E3])(c[40],c[82],(0,c[44])()),c[5],c[31],c[9]),c[14],c[84]),c[75],((0,c[80])(c[28],c[63]),(0,c[26])(c[104],c[16]),c[48])(c[37],c[68]),(0,c[65])(c[10],(0,c[48])(c[-1630175+97*Math.pow(7,
5)],c[0]),(0,c[94])(c[75],c[99]),(0,c[73])(c[17],c[47]),c[88],c[25]),(0,c[366%Math.pow(7,3)- -82])(c[14],c[109]),c[87],(0,c[52])(c[23]),c[105],c[new Date("01 January 1970 00:00:12 GMT")/1E3]),c[103],c[new Date("01/01/1970 00:00:01 UTC")/1E3],c[36]),"1")||((0,c[9])((0,c[52])(c[12]),c[38],c[70],c[25],(0,c[16])()),(((((0,c[96])(c[78],c[23]),c[9])((((0,c[64])(c[1]),c[71])(c[74],c[91]),c[64])(c[91]),c[87],c[11],c[57]),c[9])((0,c[87])(c[19],c[91]),c[Math.pow(6,4)+1120-2352],c[12]),c[7])(c[102],c[23]),(0,c[87])(c[84],
c[91]),c[96])(c[32],c[12]),c[82])((0,c[38])(c[70],c[2],(0,c[59])()),c[96],(0,c[7])(c[10],c[23]),c[45],c[1]))}try{4<c[76]&&(4<c[8]&&((0,c[9])((0,c[new Date("12/31/1969 16:00:52 -0800")/1E3])(c[12]),c[71],c[92],c[1]),",")||(0,c[9])((0,c[33])(c[70],c[51]),c[240*Math.pow(7,3)+-82287],c[57],c[46])),5<c[65]&&(0,c[9])((0,c[64])(c[12]),c[96],c[100],c[91]),1<c[76]&&(2>=c[34]&&((0,c[71-Math.pow(6,2)+38])((0,c[9])((0,c[33])(c[1],c[14]),c[7],c[0],c[23]),c[9],(0,c[52])(c[23]),c[38],c[23],c[6],(0,c[86])()),1)||
(((0,c[9])((0,c[96])(c[67],c[57]),c[33],c[57],c[47]),c[32])(c[42],c[68]),c[9])(c[79]))}catch(d){(0,c[94])(c[79],c[80],(0,c[31])()),(0,c[63])(c[28+376%Math.pow(3,3)],c[15]),(0,c[230*Math.pow(2,3)+-1777])(c[84],c[68])}}catch(d){return"enhanced_except_jpYB8en-_w8_"+a}return b.join("")};
It sounds like you're in for a world of pain and/or fun :) Writing an interpreter is no joke, and it looks like you may need to account for complex behavior that has already been done by someone else.
Might I suggest using an already made Javascript interpreter and see if that works for you? Duktape is a good one that's been around since 2013 and has some basic Nim bindings (but they might not work as is due to them being for an older version of duktape).