Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-stage programming (macro) system #492

Open
mtshiba opened this issue Feb 19, 2024 · 1 comment
Open

Add multi-stage programming (macro) system #492

mtshiba opened this issue Feb 19, 2024 · 1 comment
Labels
enhancement New feature or request RFC New specifications of Erg syntax

Comments

@mtshiba
Copy link
Member

mtshiba commented Feb 19, 2024

Here I propose to add a multi-stage programming (macro) system to Erg.

Motivation

Erg is compatible with Python's API. In other words, Erg is an alt Python.
However, Erg's syntax is far different from Python's. Whereas Python has statements, almost everything in Erg is expressions. if and for are also implemented as functions rather than statements.
This makes Erg code look very different from Python code.

if! True:
    do!:
        print! "True"
    do!:
        print! "False"

for! [1, 2, 3], i =>
    print! i

If you try to write an else clause in if, you will need two indentations. for! has the opposite order of i and iterable compared to Python's for i in iterable: ..., which is confusing. I admit that Python's syntax is simpler.
However, I feel reluctant to bring the concept of statements into Erg. I want to minimize basic grammar.

Draft plan

Therefore, I will introduce a hygienic macro system to Erg. It is heavily inspired by Scala and defines macros as functions that receive syntax elements and return syntax elements.

Macro = Class *Expr -> Expr 

To introduce macros, two syntaxes will be added: ${} and '{}.

${ x } takes an expression x of type T and returns Expr T.
'{ x } takes an expression of type Expr T and returns T.

{Expr; Name} = import "macro/ast"
# Name[Int] <: Expr[Int]

i: Int = 1
expr: Name Int = '{ i }
# expr + 1 # ERROR

i2: Int = ${ expr }
# ${ expr + 1 } # ERROR
# ${ expr } + 1 # OK

assert i == i2

Use these to implement if, for!, import.
Note that if this proposal is implemented, the current if function etc. will be moved to the control module instead of built-in.

control = __import__ "control"

@Macro
if|T, U, V|(cond: Expr[Bool], block: Block[T], *'elif' elif: Option[Block[V]] := None, 'else' else: Option[Block[U]] := None:): Expr[T or U or V] =
    ...

@Macro
for!|T|(i: Name[T], 'in' iterable: Expr[Iterable[T]], block: Block[NoneType], 'else' else: Option[Block[NoneType]] := None) -> NoneType =
    if else != None:
        '{
exec = !False
control.for! $iterable, $i =>
    $block
    exec.set! True
if not exec:
    $else
        }
    else:
        '{
control.for! $iterable, $i =>
    $block
        }

@Macro
import(x: Name) = '{ $x = control.import ${ x.as_str() } }

Then we can use them:

if True:
    ...
else:
    ...

for! i in 0..10:
    ...

import control
@mtshiba mtshiba added enhancement New feature or request RFC New specifications of Erg syntax labels Feb 19, 2024
@mtshiba
Copy link
Member Author

mtshiba commented Feb 19, 2024

It may be difficult to tell which is which with the syntax ${} and '{}, so it may be better to use the notations quote{} and embed{}.

@mtshiba mtshiba changed the title Add macro system Add multi-stage compilation system Mar 6, 2024
@mtshiba mtshiba changed the title Add multi-stage compilation system Add multi-stage programming (macro) system Mar 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request RFC New specifications of Erg syntax
Projects
None yet
Development

No branches or pull requests

1 participant