Dragon banner

Dragon & Fox
Collective

Fox banner

the baby code is you

Published by Jady on 6/12/24, 7:09 PM

my roommates keep telling me i'm programming baby code in ms paint, when i'm doing stuff like th is

Another helpful tip

Published by Jady on 6/5/24, 10:23 PM

Friendly reminder to cut your losses! I could spend an extra two weeks rewriting part of the Cetus compiler to be all sorts of safe, at the cost of my sanity. Or, since I know I'm gonna be rewriting the whole thing in Cetus in a while anyway, which is way easier to do these certain things in, I can just wait it out. So, no spamming generic classes everywhere.

Fewer syntax definitions

Published by Jady on 5/23/24, 11:36 PM

I've narrowed down all the syntax definitions to just a few lines of really flexible code:


IToken fieldToken = new TokenString([new ParameterValueToken("fieldTypes"), new ParameterValueToken("fieldNames")]);
IToken parameterToken = new TokenString([new ParameterValueToken("parameterTypes"), new ParameterValueToken("parameterNames")]);
IToken varArgParameterToken = new TokenString([new ParameterValueToken("varArgParameterType"), new LiteralToken("..."), new ParameterValueToken("varArgParameterName")]);
AddFunction(ContextType.Program, Functions.Program, 100, new TokenSplit(new PassToken(), new LiteralToken(";"), new EOFToken(), new ParameterExpressionToken("statements")));
AddFunction(ContextType.Program, Functions.Struct, 90, new TokenString([new ParameterValueToken("name"), new TokenSplit(new LiteralToken("{"), new LiteralToken(";"), new  LiteralToken("}"), new TokenOptions([fieldToken, new ParameterExpressionToken("functions")]))]));
AddFunction(ContextType.Program, Functions.Function, 80, new TokenString([new ParameterValueToken("returnType"), new ParameterValueToken("name"), new TokenSplit(new LiteralToken("("), new LiteralToken(","), new LiteralToken(")"), new TokenOptions([parameterToken, varArgParameterToken])), new TokenOptional(new TokenSplit(new LiteralToken("{"), new LiteralToken(";"), new LiteralToken("}"), new ParameterExpressionToken("statements")))]));

AddFunction(ContextType.Function, Functions.Declare, 100, new TokenString([new LiteralToken("Declare"), new ParameterValueToken("type"), new ParameterValueToken("name")]));
AddFunction(ContextType.Function, Functions.Define, 100, new TokenString([new ParameterValueToken("type"), new ParameterValueToken("name"), new LiteralToken("="), new ParameterExpressionToken("value")]));
AddFunction(ContextType.Function, Functions.Assign, 100, new TokenString([new ParameterExpressionToken("target"), new LiteralToken("="), new ParameterExpressionToken("value")]));
AddFunction(ContextType.Function, Functions.Return, 100, new TokenString([new LiteralToken("Return"), new TokenOptional(new ParameterExpressionToken("value"))]));
AddFunction(ContextType.Function, Functions.Add, 30, new TokenString([new ParameterExpressionToken("a"), new LiteralToken("+"), new ParameterExpressionToken("b")]));
AddFunction(ContextType.Function, Functions.LessThan, 40, new TokenString([new ParameterExpressionToken("a"), new LiteralToken("<"), new ParameterExpressionToken("b")]));
AddFunction(ContextType.Function, Functions.While, 100, new TokenString([new LiteralToken("While"), new LiteralToken("("), new ParameterExpressionToken("condition"), new LiteralToken(")"), new ParameterExpressionToken("body")]));

More functions

Published by Jady on 5/22/24, 10:57 PM

Here's a more in-depth diagram of how the compiler works, if you can understand stuff like regex:


// Source code

extern Void printf(String format, Int... values);

Foo
{
	Int a;
	Int b;
	
	Foo New(Int a, Int b)
	{
		Declare Foo this;
		this.a = a;
		this.b = b;
		Return this;
	}
	
	Int* A(Foo this)
	{
		Return this.a;
	}
};

Void main()
{
	Foo foo = Foo.New(2, 3);
	printf("Starting at %i\n", foo.A());
	
	While (foo.A() < 6)
	{
		foo.A() = foo.A() + 1;
		printf("Loop %i\n", foo.A());
	};
	
	printf("Ending at %i\n", foo.A());
	Return;
};

// Compiler first pass
// Mostly just grab all the type and function information

// Available functions
Parameter(String type, String name)
	as "$type $name";
VarArgParameter(String type, String name)
	as "$type... $name";
Body(Int index)
	as "\{ $index=lexer.Index \}";
Function(String name, Parameter[] parameters, VarArgParameter? varArgParameter, String returnType, Body? body)
	as "$returnType $name \(\) $body"
	as "$returnType $name \( $varArgParameter (,)? \) $body"
	as "$returnType $name \( $parameters (, $parameters)* (, $varArgParameter)? (,)? \) $body";
Field(String type, String name)
	as "$type $name";
Struct(String name, Field[] fields, Function[] functions)
	as "$name \{ ($fields | $functions)+ \}";
Program(Struct[] structs, Function[] functions)
	as "($structs | $functions)+";



Program(
[
	Struct("Foo", [Field("Int", "a"), Field("Int", "b")],
		[
			Function("New", [Parameter("Int", "a"), Parameter("Int", "b")], None, "Foo", Some(FOO.NEW BODY INDEX)),
			Function("A", [Parameter("Foo", "this")], None, "Int*", Some(FOO.A BODY INDEX),
		]),
],
[
	Function("printf", [Parameter("String", "format")], Some(Parameter("Int", "values")), "Void", None),
	Function("main", [], None, "Void", Some(MAIN BODY INDEX)),
]);

// Compiler second pass
// Generate any intermediary code needed to parse function bodies

// Available functions
Parameter(Type type, String name);
Body(Int index);
Function(String name, Parameter[] parameters, Parameter? varArgParameter, String returnType, Body? body);
Field(Type type, String name);
Struct(String name, Field[] fields, Function[] functions);
Program(Struct[] structs, Function[] functions);



Program(
[
	Struct("Foo", [Field(Int, "a"), Field(Int, "b")],
		[
			Function("New", [Parameter(Int, "a"), Parameter(Int, "b")], None, Foo, Some(FOO.NEW BODY INDEX)),
			Function("A", [Parameter(Foo, "this")], None, Int*, Some(FOO.A BODY INDEX),
			Function("Get_a", [Parameter(Foo, "this")], None, Int*, None),
			Function("Get_b", [Parameter(Foo, "this")], None, Int*, None),
		]),
],
[
	Function("printf", [Parameter(String, "format")], Some(Parameter(Int, "values")), Void, None),
	Function("main", [], None, Void, Some(MAIN BODY INDEX)),
	Function("Get_Foo.New", [Parameter(Type<Foo>, "type")], None, Foo.New, None),
	Function("Get_Foo.A", [Parameter(Type<Foo>, "type")], None, Foo.A, None),
	Function("Call_Foo.A", [Parameter(Foo, "this")], None, () => Foo.A(this), None),
]);

// Compiler third pass
// Now we get to the actual function definitions

// Available functions

/// Compiler functions
Define(Type type, String name, Value value)
	as "$type $name = $value";
Declare(Type type, String name)
	as "$type $name";
Assign(Value target, Value value)
	as "$target = $value";
Return(Value? value)
	as "Return $value?";
While(Expression condition, Expression body)
	as "While ( $condition ) $body";
LessThan(Value left, Value right)
	as "$left < $right";
Add(Value left, Value right)
	as "$left + $right";

/// User functions
printf(String format, Value... values);
main();

/// Compiler-generated user functions
Foo.Get_a(Foo this)
	as "$this.a";
Foo.Get_b(Foo this)
	as "$this.b";
Get_Foo.New(Type type)
	as "$type.New";
Get_Foo.A(Type type)
	as "$type.A";
Call_Foo.A(Foo this)
	as "$this.A";



Foo.New(Int a, Int b)
{
	Declare(Foo, "this");
	Assign(Foo.Get_a(this), a);
	Assign(Foo.Get_b(this), b);
	Return(Some(this));
}

Foo.A(Foo this)
{
	Return(Foo.Get_a(this));
}

Main()
{
	Define(Foo, "foo", Get_Foo.New(Foo)(2, 3));
	printf("Starting at %i", Call_Foo.A(foo)());
	
	While(LessThan(Call_Foo.A(foo)(), 6),
	{
		Assign(Call_Foo.A(foo)(), Add(Call_Foo.A(foo)(), 1));
		printf("Loop %i", Call_Foo.A(foo)());
	});
	
	printf("Ending at %i", Call_Foo.A(foo));
	Return(None);
}

Everything is functions. Even the functions.

Dot functions

Published by Jady on 5/21/24, 11:17 PM

Remember how I said everything's a function? I've been working on dot notation, which of course are also functions. But they're procedurally generated functions at compile time to keep them safe, which is... particularly goofy.


Foo
{
    Int a
    
    Int GetA(Foo this)
    {
        Return this.a
    }
}

Void Main()
{
    Declare Foo foo
    Foo.GetA(foo)
    foo.GetA()
}

becomes


Foo
{
    Int a
    
    Int GetA(Foo this)
    {
        Return Get_a(this)
    }
    
    Int* Get_a(Foo this)
    as "$0.a"
    {
        Return #access(this, a)
    }
}

(Foo => Int) Get_GetA(Type<Foo> foo)
as "$0.GetA"
{
    Return #access(foo, GetA)
}

(() => Int) Call_GetA(Foo foo)
as "$0.GetA"
{
    Return () => #access(foo.Type, GetA)(foo)
}

Void Main()
{
    Declare Foo foo
    Get_GetA(Foo)(foo)
    Call_GetA(foo)()
}

These extra generated functions only exist in the compiler though, and can't be accessed any other way.