Obython

From Esolang
Jump to navigation Jump to search

Obython is a language made in python, when i thought, what could be the longest way to make a hello world program

Things in it

Print

Print - does stuff
Print(print=String(value="this is valid")),
Print(print="this is valid"),
Print("and so is this"),
Print("also the commas are because thats how you structure \
this in...")

Program

Program - contains the program
Program(code=[
Print("yeah thats why there was commas\
this is used to contain code, and etc"),
Print("it goes through everything in the code and\
 calls .value() on it, and also some things that\
use it is...")
])

If

If - checks if condition is true, and if it is, does its program
If(condition=Equal(a=Number(value=1),
b=Number(value=1)),
program=Program(code=[
Print("yes this runs because 1 in fact does equal 1, also if\
you are wondering what Number and String are, they are...")
]))

Literals

Literal - when called .value() on, they return themselves
but also for only literals, if .literal() is called on
them, it returns its literal, which is used in print
and Equal, and more
String  - a literal, specifically a string
Number  - a literal, specifically an int or float
Boolean - a literal, specifically a bool
Dict    - a literal, specifically a dictionary
List    - a literal, specifically a list
No      - a literal, specifically None
also Program returns a No(value=None) when the
Program has empty code, as in [], or has its
last statement not returning anything,
it would return a None instead of a No,
which is bad, because None
isnt supported as an...

Object

Everything inherits from the Object class,
just with different value method, and for literals, different
typerfilter method
class Object:
    def __init__(self, *positional, **values):
        if self.typefilter(values):
            self.values = values
            self.positional = positional
        else:
            raise TypeError()
   
    def value(self):
        raise NotImplementedError("Subclasses must override value()")

    def literal(self):
        raise NotImplementedError("Only Literals implement literal(), but got class '"+str(type(self))+"'") 

    def typefilter(self, values):
        return True

There is more

i am just too lazy to show them

Examples

99 bottles of beer

code = Program(code=[
    Assign(variable=String(value="bottles"), value=Number(value=99)),
    While(condition=GreaterThan(a=Get(variable=String(value="bottles")), b=Number(value=1)), code=Program(code=[
        Print(Add(a=ToString(value=Get(variable=String(value="bottles"))), b=String(value=" bottles of beer on the wall"))),
        Print(Add(a=ToString(value=Get(variable=String(value="bottles"))), b=String(value=" bottles of beer"))),
        Print(String(value="Take one down, pass it around")),
        Assign(variable=String(value="bottles"), value=Subtract(a=Get(variable=String(value="bottles")), b=Number(value=1))),
        If(condition=GreaterThan(a=Get(variable=String(value="bottles")), b=Number(value=1)),  program=Program(code=[
            Print(Add(a=ToString(value=Get(variable=String(value="bottles"))), b=String(value=" bottles of beer on the wall")))
            ]))
        ])),
    Print("1 bottle of beer on the wall"),
    Print("1 bottle of beer"),
    Print("Take one down, pass it around"),
    Print("No more bottles of beer on the wall")
    ])

Interpeter

import time, random
class ReturnSignal(Exception):
    def __init__(self, value):
        self.value = value
class Helper:
    def wrap_literal(value):
        if isinstance(value, bool):
            return Boolean(value=value)
        elif isinstance(value, int) or isinstance(value, float):
            return Number(value=value)
        elif isinstance(value, str):
            return String(value=value)
        elif isinstance(value, list):
            return List(value=[wrap_literal(v) for v in value])
        else:
            raise TypeError(f"No literal wrapper for: {type(value)}")
    def wrapifneed(value):
        if not(isinstance(value, Object)):
            return Helper.wrap_literal(value)
        return value
class Environment:
    frames = [{}]  # a list of dicts, top is current scope
    recursionlimit = 100

    @classmethod
    def get(cls, name):
        for frame in reversed(cls.frames):
            if name in frame:
                return frame[name]
        raise NameError(f"Variable '{name}' not found in any scope")

    @classmethod
    def set(cls, name, value, scope="local"):
        if scope == "local":
            cls.frames[-1][name] = value
        elif scope == "global":
            cls.frames[0][name] = value

    @classmethod
    def push(cls):
        if len(cls.frames) < cls.recursionlimit:
            cls.frames.append({})
        else:
            raise RecursionError("too many recursive calls")

    @classmethod
    def pop(cls):
        cls.frames.pop()
        
    @classmethod
    def define(cls, varibs):
        for key in varibs:
            cls.frames[-1][key] = varibs[key].value()
class Object:
    def __init__(self, *positional, **values):
        if self.typefilter(values):
            self.values = values
            self.positional = positional
        else:
            raise TypeError()
    
    def value(self):
        raise NotImplementedError("Subclasses must override value()")

    def literal(self):
        raise NotImplementedError("Only Literals implement literal(), but got class '"+str(type(self))+"'")

    def typefilter(self, values):
        return True
class Time(Object):
    def value(self):
        start = time.perf_counter()
        self.values["do"].value()  # Run the code block
        end = time.perf_counter()
        duration = end - start
        return Number(value=duration)
class RandomInt(Object):
    def value(self):
        lo = self.values.get("min", Number(value=0)).value().literal()
        hi = self.values.get("max", Number(value=100)).value().literal()
        return Number(value=random.randint(lo, hi))
class Define(Object):
    def value(self):
        name = self.values["name"].value().literal()
        val = self.values["code"]
        Environment.set(name, val)
        return None
class Return(Object):
    def value(self):
        result = self.values["value"].value()
        raise ReturnSignal(result)
class Get(Object):
    def value(self):
        name = self.values["variable"].value().literal()
        return Environment.get(name)

class Assign(Object):
    def value(self):
        if "scope" not in self.values:
            self.values["scope"] = "local"
        name = self.values["variable"].value().literal()
        val = self.values["value"].value()
        Environment.set(name, val, self.values["scope"])
        return val  # return the new value
class Call(Object):
    def value(self):
        if "inputs" not in self.values:
            self.values["inputs"] = Dict(value={})
        code = self.values["proced"]
        Environment.push()
        Environment.define(self.values["inputs"].value().literal())
        try:
            result = code.value()
        except ReturnSignal as r:
            Environment.pop()
            return r.value
        Environment.pop()
        return result
class Literal(Object):
    def value(self):
        return self
    def literal(self):
        return self.value().values["value"]
class Program(Object):
    def value(self):
        lastval = No(value=None)
        for code in self.values["code"]:
            try:
                lastval = code.value()
            except ReturnSignal as r:
                # Bubble return up immediately
                raise r
        return lastval
    def literal(self):
        return self
class Dot(Object):
    def value(self):
        obj = self.values["object"].value()
        method = self.values["method"]
        method.values["object"] = obj
        return method.value()
class Number(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (int, float))
class String(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (str))
class List(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (list))
class Dict(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (dict))
class No(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), type(None))
class Add(Object):
    def value(self):
        result = self.values["a"].value().literal() + self.values["b"].value().literal()
        return Helper.wrapifneed(value=result)
class Subtract(Object):
    def value(self):
        result = self.values["a"].value().literal() - self.values["b"].value().literal()
        return Helper.wrapifneed(value=result)
class Multiply(Object):
    def value(self):
        result = self.values["a"].value().literal() * self.values["b"].value().literal()
        return Helper.wrapifneed(value=result)
class Divide(Object):
    def value(self):
        result = self.values["a"].value().literal() / self.values["b"].value().literal()
        return Helper.wrapifneed(value=result)
class Print(Object):
    def value(self):
        if self.positional:
            self.values["print"] = self.positional[0]
        print(Helper.wrapifneed(self.values["print"]).value().literal(), flush=True)
class Read(Object):
    def value(self):
        prompt = ""
        if "prompt" in self.values:
            prompt = self.values["prompt"].value().literal()
        user_input = input(prompt)
        return Helper.wrapifneed(user_input)
class Repeat(Object):
    def value(self):
        for i in range(self.values["times"].literal()):
            self.values["code"].value()
class Forever(Object):
    def value(self):
        while True:
            self.values["code"].value()
class While(Object):
    def value(self):
        while self.values["condition"].value().literal():
            self.values["code"].value()
class Index(Object):
    def value(self):
        return Helper.wrapifneed(self.values["object"].value().literal()[self.values["index"].value().literal()])
class Boolean(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (bool))
class String(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (str))
class List(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (list))
class Dict(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), (dict))
class No(Literal):
    def typefilter(self, values):
        return isinstance(values.get("value"), type(None))
class If(Object):
    def value(self):
        if self.values["condition"].value().literal():
            self.values["program"].value()
class Equal(Object):
    def value(self):
        result = self.values["a"].value().literal() == self.values["b"].value().literal()
        return Boolean(value=result)
class GreaterThan(Object):
    def value(self):
        return Boolean(
            value=self.values["a"].value().literal() > self.values["b"].value().literal()
        )
class LessThan(Object):
    def value(self):
        return Boolean(
            value=self.values["a"].value().literal() < self.values["b"].value().literal()
        )
class Not(Object):
    def value(self):
        return Boolean(value=not(self.values["condition"].value().literal()))
class And(Object):
    def value(self):
        a = self.values["a"].value().literal()
        if not(a):
            return Boolean(value=False)
        b = self.values["b"].value().literal()
        return Boolean(value=b)
class Or(Object):
    def value(self):
        a = self.values["a"].value().literal()
        if a:
            return Boolean(value=True)
        b = self.values["b"].value().literal()
        return Boolean(value=b)
class Scope(Object):
    def value(self):
        Environment.push()
        self.values["program"].value()
        Environment.pop()
class ToNumber(Object):
    def value(self):
        val = self.values["value"].value().literal()
        return Number(value=float(val))
class ToString(Object):
    def value(self):
        val = self.values["value"].value().literal()
        return String(value=str(val))

code = Program(code=[
    Assign(variable=String(value="bottles"), value=Number(value=99)),
    While(condition=GreaterThan(a=Get(variable=String(value="bottles")), b=Number(value=1)), code=Program(code=[
        Print(Add(a=ToString(value=Get(variable=String(value="bottles"))), b=String(value=" bottles of beer on the wall"))),
        Print(Add(a=ToString(value=Get(variable=String(value="bottles"))), b=String(value=" bottles of beer"))),
        Print(String(value="Take one down, pass it around")),
        Assign(variable=String(value="bottles"), value=Subtract(a=Get(variable=String(value="bottles")), b=Number(value=1))),
        If(condition=GreaterThan(a=Get(variable=String(value="bottles")), b=Number(value=1)),  program=Program(code=[
            Print(Add(a=ToString(value=Get(variable=String(value="bottles"))), b=String(value=" bottles of beer on the wall")))
            ]))
        ])),
    Print("1 bottle of beer on the wall"),
    Print("1 bottle of beer"),
    Print("Take one down, pass it around"),
    Print("No more bottles of beer on the wall")
    ])
try:
    code.value()
except ReturnSignal as e:
    print("execution stopped with exit code", e.value)