Skip to content

Instantly share code, notes, and snippets.

@Todd-Davies
Last active September 3, 2023 20:05
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Todd-Davies/7666505 to your computer and use it in GitHub Desktop.
Save Todd-Davies/7666505 to your computer and use it in GitHub Desktop.
I wanted to see what a programming language that was also parsable JSON would look like. This is what I came up with.
"""
I wanted to see what a programming language that was also parsable JSON would look like. This is what I came up with.
Features:
+ Methods (nestable)
+ Variables
+ Built in functions (add, subtract, print etc)
+ Maybe more I've forgotten
Notable omissions as of yet:
+ Methods cannot return values
+ Arrays
+ Pretty much every feature *real* programming languages have
"""
import json
class Executor:
"""
Executes my little JSON based programming language
"""
def cmd_multiply(self, values):
"""
Multiplies two values
"""
if len(values)!=3:
raise Exception("Multiplication takes three values")
# Get the first parameter
number1 = self.get_variable(values[1])
# Get the second parameter
number2 = self.get_variable(values[2])
if values[0][0]!='$':
raise Exception("First argument of mul must be a variable")
else:
self.set_variable(values[0][1:], number1 * number2)
def cmd_division(self, values):
"""
Divide one value by another
"""
if len(values)!=3:
raise Exception("Division takes three values")
# Get the first parameter
number1 = self.get_variable(values[1])
# Get the second parameter
number2 = self.get_variable(values[2])
if values[0][0]!='$':
raise Exception("First argument of div must be a variable")
else:
self.set_variable(values[0][1:], number1 / number2)
def cmd_addition(self, values):
"""
Adds two values
"""
if len(values)!=3:
raise Exception("Addition takes three values")
# Get the first parameter
number1 = self.get_variable(values[1])
# Get the second parameter
number2 = self.get_variable(values[2])
if values[0][0]!='$':
raise Exception("First argument of add must be a variable")
else:
self.set_variable(values[0][1:], number1 + number2)
def cmd_subtraction(self, values):
"""
Subtracts one value from another
"""
if len(values)!=3:
raise Exception("Subtraction takes three values")
# Get the first parameter
number1 = self.get_variable(values[1])
# Get the second parameter
number2 = self.get_variable(values[2])
if values[0][0]!='$':
raise Exception("First argument of sub must be a variable")
else:
self.set_variable(values[0][1:], number1 - number2)
def cmd_print(self, values):
"""
Prints the values to std out
"""
output = []
for token in values:
output.append(str(self.get_variable(token)))
print " ".join(output)
# Define the built in commands using a dict
commands = { "mul" : cmd_multiply,
"div" : cmd_division,
"add" : cmd_addition,
"sub" : cmd_subtraction,
"print": cmd_print}
# Holds the variables for this instance of Executor
local_variables = {}
# Holds the variables for this instance of Executor
local_methods = {}
def set_variable(self, key, value):
"""
Set a variable
"""
self.local_variables[key] = value
def get_variable(self, key):
"""
Gets a variable
If the variable is not set, then the name of the variable is returned and a warning sent
"""
# Convert to a string (incase it's an integer literal)
key = str(key)
# Check to see if the key is a variable
if key[0] == '$':
# Strip the '$'
key = key[1:]
# Check if the key is in the variables array
if key in self.local_variables:
return self.local_variables[key];
else:
print "Variable %s not found." % key
return key
else:
# The key isn't a variable, return it
return key
def set_method(self, key, value):
"""
Set a method
"""
self.local_methods[key] = value
def execute_method(self, key, params=[]):
"""
Executes a method
"""
# Create a new instance of Executor for the method
method_ex = Executor()
# Get the statement from the statements list
statement_to_execute = self.local_methods[key]
# Extract the method parameters from the
method_params = statement_to_execute["params"]
# Set the variables in the method executor
for param_index in range(0, len(method_params)):
param = self.get_variable(params[param_index])
# Set the parameter
method_ex.set_variable(
method_params[param_index],
param)
# Execute the method
method_ex.execute_statement(json.dumps(statement_to_execute["body"]))
def tokenize(self, statement):
"""
Splits the statement into words
"""
return statement.split(" ")
def run_command(self,tokens):
"""
Runs a command from a selection of built in commands and the methods
defined by the code
"""
# Is the command a defined method?
if tokens[0][0]=='!':
if tokens[0][1:] in self.local_methods:
self.execute_method(tokens[0][1:], tokens[1:])
else:
print "Method %s not found" % tokens[0][1:]
# Nope, is it a operation?
elif tokens[0] in self.commands:
self.commands[tokens[0]](self, tokens[1:])
else:
print "Unknown command: '%s'" % tokens[0]
def execute_statement(self, statement):
"""
Executes an array of commands
"""
# Parse the json into an array
code = json.loads(statement)
# For each item in the array
for stmnt in code:
# If the statement is a dict, then it's a method or an assignment
if isinstance(stmnt, dict):
# If the value inside the statement is a dict, then it's a method
if isinstance(stmnt.values()[0], dict):
self.set_method(stmnt.keys()[0], stmnt.values()[0])
else: # Otherwise it's a variable assignment
self.set_variable(stmnt.keys()[0], stmnt.values()[0])
# If it's a string then it must be a command
elif isinstance(stmnt, unicode):
# Split the command into tokens first
tokens = self.tokenize(stmnt.strip())
# Run the command
self.run_command(tokens)
else:
# If it's none of those, feed it back into here
self.execute_statement(json.dumps(stmnt))
# This is the code we'll run
app_code = '''
[
{"x":9},
{"y":3},
["print The value of x is: $x"],
["print The value of x is: $y"],
["print Now lets add x and y"],
["add $z $x $y"],
["print The answer is: $z"],
["print Now lets subtract y from x"],
["sub $z $x $y"],
["print The answer is: $z"],
["print Now lets divide x by y"],
["div $z $x $y"],
["print The answer is: $z"],
["print Now lets multiply x by y"],
["mul $z $x $y"],
["print The answer is: $z"],
{"myMethod":
{
"params": [
"p1",
"p2"
],
"body": [
{"nestedMethod":
{
"params": [
"p1"
],
"body": [
["print Methods can be nested, and arguments can be trickled down."],
["print The result was: $p1"]
]
}
},
["print You passed me: $p1 and $p2"],
["print Lets add them and pass the result into another method!"],
["add $p2 $p1 $p2"],
["!nestedMethod $p2"]
]
}
},
["!myMethod $x $y"]
]'''
# Create an executor object
ex = Executor()
# Run the program
ex.execute_statement(app_code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment