DEV Community

Jun Nishimura
Jun Nishimura

Posted on

You can write programs in JSON

You can write programs in JSON.

This may sound like something else, but I have created a programming language/interpreter for writing programs in JSON format.

The name is “ JSOP,” an abbreviation for JSON Processor, and I named it after LISP (LIST Processor).

https://github.com/JunNishimura/JSOP

This article is not much more than “I made a programming language,” but I hope to explain my motivation and some simple language specifications. I hope you will enjoy the idea that such a language is possible.

{
    "command": {
      "symbol": "print",
      "args": "Hello, World!"
    }
}
Enter fullscreen mode Exit fullscreen mode

🔥 Motivation

When I was studying LISP, I came across the statement that the fact that “data and code are identical” is what makes LISP unique.

I thought that if I could create programs in JSON (JavaScript object representation), which is a data structure other than lists, I could create a language like LISP in which “data and code are the same”.

💾 Installation

Homebrew Tap

brew install JunNishimura/tap/JSOP
Enter fullscreen mode Exit fullscreen mode

go intall

go install github.com/JunNishimura/jsop@latest
Enter fullscreen mode Exit fullscreen mode

GitHub Releases

Download exec files from GitHub Releases.

💾 How to use

Since REPL is not provided, you can write your program in any file and pass the file path as a command line argument to execute the program.

jsop ./path/to/file.jsop.json
Enter fullscreen mode Exit fullscreen mode

📖 Language Specification

  1. Everything is an expression.
  2. Only .jsop and .jsop.json are accepted as file extensions.

Integer

Integer value is a sequence of numbers.

123
Enter fullscreen mode Exit fullscreen mode

String

String value is a sequence of letters, symbols, and spaces enclosed in double quotation marks.

"this is a string"
Enter fullscreen mode Exit fullscreen mode

Boolean

Boolean value is either true or false.

true
Enter fullscreen mode Exit fullscreen mode

Array

Arrays are composed of expressions.

[1, "string", true]
Enter fullscreen mode Exit fullscreen mode

Identifiers

Strings beginning with the $ symbol are considered as identifiers.

"$x"
Enter fullscreen mode Exit fullscreen mode

Embedding the Identifier in a string is accomplished by using curly brackets.

"{$hello}, world!"
Enter fullscreen mode Exit fullscreen mode

Assignment

To assign a value or function to an identifier, use the set key.

parent key children key explanation
set declaration of assignment
var identifier name
val value to assign
[
    {
        "set": {
            "var": "$x",
            "val": 10
        }
    },
    "$x"
]
Enter fullscreen mode Exit fullscreen mode

Function

Function Definition

Functions can be defined by using set key and lambda expression.

parent key children key explanation
lambda declaration
params parameters(optional)
body body of function
{
    "set": {
        "var": "$add",
        "val": {
            "lambda": {
                "params": ["$x", "$y"],
                "body": {
                    "command": {
                        "symbol": "+",
                        "args": ["$x", "$y"]
                    }
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Function Call

Functions can be called by using command key.

parent key children key explanation
command declaration of function calling
symbol function to call
args arguments(optional)
{
    "command": {
        "symbol": "+",
        "args": [1, 2]
    }
}
Enter fullscreen mode Exit fullscreen mode

Builtin Functions

Builtin functions are as follows,

関数 explanation
+ addition
- subtraction
* multiplication
/ division
% modulo
! negation
&& and operation
\ \
== equation
!= non equation
> greater than
>= greater than equal
< smaller than
>= smaller than equal
print print to standard output
len length of array
at access to the element of array

If

Conditional branches can be implemented by using the if key.

parent key children key explanation
if declaratoin of if
cond condition
conseq consequence(the program to execute when cond is true)
alt alternative(the program to execute when cond is false)
{
    "if": {
        "cond": {
            "command": {
                "symbol": "==",
                "args": [1, 2]
            }
        },
        "conseq": {
            "command": {
                "symbol": "+",
                "args": [3, 4]
            }
        },
        "alt": {
            "command": {
                "symbol": "*",
                "args": [5, 6]
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Loop

Iterations are handled by using the loop key.

parent key children key explanation
loop declaration of loop
for the identifier for loop counter
from the initial value of loop counter
until loop termination condition (break when loop counter equals this value)
do Iterative processing body
{
    "loop": {
        "for": "$i",
        "from": 0,
        "until": 10,
        "do": {
            "command": {
                "symbol": "print",
                "args": "$i"
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

You can also perform a loop operation on the elements of an Array. Unlike the example above, the in key specifies an Array.

[
    {
        "set": {
            "var": "$arr",
            "val": [10, 20, 30] 
        }
    },
    {
        "loop": {
            "for": "$element",
            "in": "$arr",
            "do": {
                "command": {
                    "symbol": "print",
                    "args": "$element"
                }
            }
        }
    }
]
Enter fullscreen mode Exit fullscreen mode

Also, insert break and continue as keys as follows.

[
    {
        "set": {
            "var": "$sum",
            "val": 0
        }
    },
    {
        "loop": {
            "for": "$i",
            "from": 1,
            "until": 15,
            "do": {
                "if": {
                    "cond": {
                        "command": {
                            "symbol": ">",
                            "args": ["$i", 10]
                        }
                    },
                    "conseq": {
                        "break": {}
                    },
                    "alt": {
                        "if": {
                            "cond": {
                                "command": {
                                    "symbol": "==",
                                    "args": [
                                        {
                                            "command": {
                                                "symbol": "%",
                                                "args": ["$i", 2]
                                            }
                                        },
                                        0
                                    ]
                                }
                            },
                            "conseq": {
                                "set": {
                                    "var": "$sum",
                                    "val": {
                                        "command": {
                                            "symbol": "+",
                                            "args": ["$sum", "$i"]
                                        }
                                    }
                                }
                            },
                            "alt": {
                                "continue": {}
                            }
                        }
                    }
                }
            }
        }
    },
    "$sum"
]
Enter fullscreen mode Exit fullscreen mode

Retrun

Use return key when you exit the program with return.

[
    {
        "set": {
            "var": "$f",
            "val": {
                "lambda": {
                    "body": [
                        {
                            "set": {
                                "var": "$sum",
                                "val": 0
                            }
                        },
                        {
                            "loop": {
                                "for": "$i",
                                "from": 1,
                                "until": 11,
                                "do": {
                                    "if": {
                                        "cond": {
                                            "command": {
                                                "symbol": ">",
                                                "args": ["$i", 5]
                                            }
                                        },
                                        "conseq": {
                                            "return": "$sum"
                                        },
                                        "alt": {
                                            "set": {
                                                "var": "$sum",
                                                "val": {
                                                    "command": {
                                                        "symbol": "+",
                                                        "args": ["$sum", "$i"]
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        }
    },
    {
        "command": {
            "symbol": "$f"
        }
    }
]
Enter fullscreen mode Exit fullscreen mode

Macro

Macro can be defined by using defmacro key.

parent key children key explanation
defmacro declaration of macro definition
name name of macro
keys keys
body the body of macro

You can also call the quote symbol for quoting, and unquote by adding backquotes to the beginning of the string.

{
    "defmacro": {
        "name": "unless",
        "keys": ["cond", "conseq", "alt"],
        "body": {
            "command": {
                "symbol": "quote",
                "args": {
                    "if": {
                        "cond": {
                            "command": {
                                "symbol": "!", 
                                "args": ",cond"
                            }
                        },
                        "conseq": ",conseq",
                        "alt": ",alt"
                    }
                }
            } 
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Defining function can be much simpler if you use Macro.

[
    {
        "defmacro": {
            "name": "defun",
            "keys": ["name", "params", "body"],
            "body": {
                "command": {
                    "symbol": "quote",
                    "args": {
                        "set": {
                            "var": ",name",
                            "val": {
                                "lambda": {
                                    "params": ",params",
                                    "body": ",body"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "defun": {
            "name": "$add",
            "params": ["$x", "$y"],
            "body": {
                "command": {
                    "symbol": "+",
                    "args": ["$x", "$y"]
                }
            }
        }
    },
    {
        "command": {
            "symbol": "$add",
            "args": [1, 2]
        }
    }
]
Enter fullscreen mode Exit fullscreen mode

Comment

Comments can be inesrted by using // key.

{
    "//": "this is a function to add two values",
    "set": {
        "var": "$add",
        "val": {
            "lambda": {
                "params": ["$x", "$y"],
                "body": {
                    "command": {
                        "symbol": "+",
                        "args": ["$x", "$y"]
                    }
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

🤔 FizzBuzz Problem

Finally, I have included an example of solving a FizzBuzz problem in JSOP.

[
    {
        "set": {
            "var": "$num",
            "val": 31
        }
    },
    {
        "loop": {
            "for": "$i",
            "from": 1,
            "until": "$num",
            "do": {
                "if": {
                    "cond": {
                        "command": {
                            "symbol": "&&",
                            "args": [
                                {
                                    "command": {
                                        "symbol": "==",
                                        "args": [
                                            {
                                                "command": {
                                                    "symbol": "%",
                                                    "args": ["$i", 3]
                                                }
                                            },
                                            0
                                        ]
                                    }
                                },
                                {
                                    "command": {
                                        "symbol": "==",
                                        "args": [
                                            {
                                                "command": {
                                                    "symbol": "%",
                                                    "args": ["$i", 5]
                                                }
                                            },
                                            0
                                        ]
                                    }
                                }
                            ]
                        }
                    },
                    "conseq": {
                        "command": {
                            "symbol": "print",
                            "args": "{$i}: FizzBuzz"
                        }
                    },
                    "alt": {
                        "if": {
                            "cond": {
                                "command": {
                                    "symbol": "==",
                                    "args": [
                                        {
                                            "command": {
                                                "symbol": "%",
                                                "args": ["$i", 3]
                                            }
                                        },
                                        0
                                    ]
                                }
                            },
                            "conseq": {
                                "command": {
                                    "symbol": "print",
                                    "args": "{$i}: Fizz"
                                }
                            },
                            "alt": {
                                "if": {
                                    "cond": {
                                        "command": {
                                            "symbol": "==",
                                            "args": [
                                                {
                                                    "command": {
                                                        "symbol": "%",
                                                        "args": ["$i", 5]
                                                    }
                                                },
                                                0
                                            ]
                                        }
                                    },
                                    "conseq": {
                                        "command": {
                                            "symbol": "print",
                                            "args": "{$i}: Buzz"
                                        }
                                    },
                                    "alt": {
                                        "command": {
                                            "symbol": "print",
                                            "args": "$i"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
]
Enter fullscreen mode Exit fullscreen mode

🎬 At the end

I started JSOP in imitation of LISP, and I like the fact that it can be easily metaprogrammed by using macros just like LISP. As you can see from the solution to the FizzBuzz problem, I think it is not a practical language.

I would be happy to get your advice/feedback. I am looking forward to your comments!

https://github.com/JunNishimura/JSOP

Top comments (0)