Arc Forumnew | comments | leaders | submitlogin
1 point by Pauan 5130 days ago | link | parent

I tokenize the input stream (which is probably a string) one step at a time, and when I see a "(" I then keep parsing until I find a closing ")" Now, it's available as a list, so I check if the car is a macro, and if so I then call it with the remaining arguments, and return that.

However, I ran into a bit of a problem while parsing arc.arc, so I'll likely be refactoring that system. For instance, I may want it to only expand macros one level, rather than doing them all. The problem is, let's say you have this:

  (mac foo () "something")
  (mac bar () (foo))
If you use macex in Arc, you would get this:

  ... (fn nil "something") ...
  ... (fn nil (foo)) ...
But in PyArc, you would get this:

  ... (fn () "something") ...
  ... (fn () "something") ...
Oops! Note how it expanded the (foo) call, whereas Arc didn't. In other words, PyArc is a little bit too greedy about expanding macros.

In any case, the whole tokenize/parse/transform/macro expand stage is handled at the same time, so once that part's done, it can just use eval on the rest.

---

As for handling argument-only ssyntax, I've been wondering about that myself. But here's my current idea: when eval sees an (fn) form, it then creates and returns a (Python) function, which it can then execute later. Arguments and closures are handled when the function is created, so I should be able to do ssyntax expansion then.

And since macros are just annotated functions, I figure that approach will work with macros too. Thus, global ssyntax expands at read time, but argument ssyntax expands when the function is created, but before it's actually run.



1 point by rocketnia 5130 days ago | link

Ah, was afraid of just that gotcha. It means if you say (afn ((= b c)) ...), you'll end up expanding the = macro before even realizing it's an argument list. o.o; (Right?)

There's another approach I thought you might have taken, and it's free of that trouble. You mentioned looking for (fn) forms, and it's probably the same general idea: When you encounter a left paren, read the next expression after that, and use it to determine what happens next (like a reader macro). If it's a symbol, look it up and see if it's bound to a macro, and let the macro (somehow) take care of reading its body and finding the right paren. Otherwise, read elements until you get a right paren, and treat the expreaaions as a function call.

Unfortunately, I don't know how to polish up that idea to make syntax like "a.(b c).d" work out correctly, especially in cases like "catch.(b throw).d" where 'catch determines the meaning of 'throw. Actually, I could figure something out for that too, but it would be a bit arbitrary, and you may already know you're not headed this way. :-p

-----

1 point by Pauan 5130 days ago | link

Yes. I'll need to do some thinking on how to fix macro expansion.

---

Actually, I've been thinking about looking into reader macros, and seeing if I could use something similar to implement customizable ssyntax. That would have the benefit of potentially allowing for more powerful syntax.

-----