cli: print full traceback on exception in debug mode
Allow macro defs in `if` bodies, in local context
Fix subscript
Python-like language to Excel Formula compiler
tot = SUM(A1.A255)
if tot > 0:
f"Hai un positivo di {tot}"
elif tot == 0 and not B1 < 0:
"Sei in pari"
else:
"Sei sotto di brutto, zio."
compile to:
$ python -m formulap test.pyf
=IF(SUM(A1:A255)>0;CONCAT("Hai un positivo di ";SUM(A1:A255));IF(AND(SUM(A1:A255)=0;B1>=0);"Sei in pari";"Sei sotto di brutto, zio."))
https://kirgroup.net/~fabrixxm/formulap/
# string
# => "text"
"text"
# number
# => 2
2
# decimal numbers
# Note: formula with decimals could be wrong in your excel regional settigs
# => 2.5
2.5
# cell reference
# => A1
A1
# range referenfce
# => A1:A9
A1.A9
# fixed cell reference
# => $A$1
{A1}
# fixed range reference
# => $A$1:$A$9
{A1.A9}
# conditional
# 'else' is optional, 'elif' is supported
# => IF(cond;...;...)
# => IF(cond1;...;IF(cond2;...;...))
if cond:
...
else:
...
if cond1:
...
elif cond2:
...
else:
...
# Conditions
# => IF(A1=1;...)
# => IF(AND(A1>2;A1<=7);...)
# => IF(OR(A1<>B1;A1<>B2);...)
# => IF(NOT(A1=B1);...)
if A1 == 1:
...
if A1 > 2 and A1 <= 7:
...
if A1 != B1 or A1 != B2:
...
if not A1 == B1:
...
# Note: code like x < y < z is not supported
# Search in range
# => MATCH("val";B1.B100)
"val" in B1.B100
# Value in range
# => INDEX(A1:A10;5)
# => INDEX(A1:B10;5;2)
A1.A10[5]
A1.B10[5:2]
# function call
# => ABS(A1)
# => AVERAGE(A1;B1;A2:B2)
# => CEILING.MATH(A1;1)
ABS(A1)
AVERAGE(A1, B1, A2.B2)
CEILING.MATH(A1, 1)
# values concatenation
# => CONCAT("Total ";$A$1)
f"Total {[A1]}"
# Arithmetic operations
# => A1 + 2
# => A1 - 2
# => A1 * 2
# => A1 / 2
# => MOD(A1;2)
# => POWER(A1;2)
A1 + 2
A1 - 2
A1 * 2
A1 / 2
A1 % 2
A1 ** 2
# Pass
# `pass` is a no-op keyword
# => IF(A1;;"Is False")
if A1:
pass
else:
"Is False"
# Macros
# Macros are usefull to reduce code duplication.
# => IF(SUM(A1:A10)>0;CONCAT("Positive sum: ";SUM(A1:A10)))
tot = SUM(A1.A10)
if tot > 0:
f"Positive sum: {tot}"
# can be defined inside if block
# => IF(A1=1;CONCAT("Res: ";A1+1))
if A1 == 1:
b = A1 + 1
f"Res: {b}"
# name is vaild only inside the block
if A1 == 1:
b = A1 + 1
pass
else:
f"Res: {b}" # CompilerException: Name 'b' is not defined
NOTE there must be ONE expression in if / else code blocks
This code is invalid:
if A1 < 2:
A1 + 3
A2 + 1