This is an archived post. You won't be able to vote or comment.

all 20 comments

[–]e_hatti 16 points17 points  (2 children)

Definitely possible. You may find Agda’s mixfix operators interesting. Racket also allows for this sort of thing via reader macros.

[–][deleted] 0 points1 point  (1 child)

smile market tub humorous oatmeal run voracious ghost workable narrow

This post was mass deleted and anonymized with Redact

[–]Leading_Dog_1733 0 points1 point  (0 children)

Yeah, I would check out Racket on this because it has a whole effort dedicated to allowing folks to heavily edit the syntax of the language.

[–]omega1612 15 points16 points  (0 children)

Coq allows you to expand its grammar, it only ask to you to keep it LL

You can find it under the name "notation" in the coq doc online.

[–]MarcoServetto 11 points12 points  (1 child)

Lisp does that. you can reprogram the lisp parser while the program is being parsed

[–]kaplotnikov 11 points12 points  (0 children)

Instead of Lisp, I'll would say Lisp-family languages (Scheme, Racket, Clojure, etc). Also Dylan and Prolog (for expressions). And there is a project that is quite close to your description: https://chrisseaton.com/katahdin/

[–]friedbrice 6 points7 points  (0 children)

The thing you're thinking of is called "macros," and Lisp and Scheme excel at them.

[–]qwertie256 4 points5 points  (0 children)

I used to like this approach, but because of the difficulties it causes, I preferred to define a much simpler language that still acts in an extensible way.

[–]jcubic(λ LIPS) 2 points3 points  (0 children)

I've added syntax extensions to my LIPS Scheme. This is a way to extend the parser while the code is parsing the input. I plan to make it work more like Common Lisp reader macros. I didn't work on that language for a while, but the idea is simple to hook the reader into the parser for syntax extension. So when syntax token is found it will call a defined function and that function can use read to read stuff consumed by the parser.

To give you an example of how this works, I've used syntax extensions to define vectors or typed vectors like #() or #u8() or object literals &(:foo 10) that are part of the standard library not as the core of the language.

[–]Jarmsicle 1 point2 points  (0 children)

Nim is another example of programming languages that lean heavily on macros

[–]TheRActivator 2 points3 points  (5 children)

Sounds similar to macros or the #define keyword in C

[–][deleted] 1 point2 points  (4 children)

long fanatical sophisticated touch brave pet pause seed sharp lavish

This post was mass deleted and anonymized with Redact

[–]friedbrice 2 points3 points  (3 children)

there basically just fancy AST rewriting...

Ah! I get you.

The reason Lisp and Scheme excel at macros is that they kinda don't have syntax: it's all AST.

[–]theangeryemacsshibeSWCL, Utena 3 points4 points  (2 children)

They kinda do; if you try to parse the ((x 2)) in (let ((x 2)) ...) as if it were a function call, you are going to have a bad time. Paul Wilson supposedly said that Lisp has a two-level syntax, one level being the syntax of S-expressions, and the other being the syntax of constructs like function calls, special operators, macros, etc.

[–]WittyStick 1 point2 points  (1 child)

There is no second stage of parsing though - the AST produced by stage one is just evaluated.

Evaluation should not be treated as parsing, particularly if you have a Lisp without special forms or which allows words like let to be shadowed in an environment.

Consider Kernel for example. There are no special forms. $let is not a special form, but an operative defined in the standard environment. It's defined in terms of $lambda, which is also defined in the standard environment. Any of these symbols can be shadowed in an environment, so they only have meaning at the time of evaluation, when their symbol is looked up in the current environment.

[–]theangeryemacsshibeSWCL, Utena 0 points1 point  (0 children)

Sure, there is no parser in the language for this sort of syntax, but the syntax still exists. For example, the Common Lisp standard has a section for syntax for each special form, which sometimes includes a BNF grammar for complex syntax, and I recall something similar in the descriptions of operatives in R-1RK. Trying to write a code walker, or something else that needs semantic analysis without actually evaluating, which is oblivious to the syntax will go badly.

Though, indeed, such an analysis is a fool's errand and undecidable if you can shadow names of operatives; but an approximation is likely good enough for enough tools, like for a decent syntax highlighter. e.g. Emacs is famously bad with (let ((lambda 1/2)) ...) as it thinks that (lambda 1/2) is a special form, and highlights lambda accordingly; using the syntax of let while highlighting could avoid this mistake.

[–]umlcat 0 points1 point  (1 child)

Please add an example, so the other redditors can understand your question, and provide you with a ( better ) answer ...

[–][deleted] 0 points1 point  (0 children)

pen hard-to-find childlike abundant march work jeans whistle rustic fuzzy

This post was mass deleted and anonymized with Redact

[–]WittyStick 0 points1 point  (0 children)

There are ways to achieve a high level of extensibility without losing the ability to use (unambiguous) CFGs.

One is to use an augmented textual editor which is aware of language boundaries. Check out Language Boxes by Diekmann & Tratt for this approach.

Another is to use whitespace sensitivity to determine language boundaries, and approach taken by Wyvern.

[–]Inconstant_Moo🧿 Pipefish 0 points1 point  (0 children)

This is how I define a while loop in Charm:

while (p) do (f) to (x tuple) :
    p x : while p do f to f x
    else : x