Register

Constant evaluation, first deprecation and reflection

Jens
2 months ago
I was playing around a bit with pickle files (a python serialization format) and found out very quickly that there are some features in BEdit that needs prioritization.

One of the annoying things BEdit layout language has inherited from C is the horrible conditional chains. C++ tried to "fix it" by adopting object orientation but.. well, it didn't really solve the issue. Consider the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct DataTypeA
{
    int32 content;
};

struct DataTypeB
{
    float32 content;
    int64 someOtherContent;
};

enum Type
{
    A,
    B
};

struct AllData
{
    Type type;
    union
    {
        DataTypeA a;
        DataTypeB b;
    };
};


Why does enum Type exist? Just to tell which type to use. Also, since the compiler doesn't know what type is actually used the union will pad to largest member (something you generally don't want for storing data on disk). Going full OOP doesn't work for BEdit, even if it did I would steer away, since object-oriented programming is all about hiding the data, where BEdit is trying to show the data.

So what's the actual issue here? BEdit has if:s, we can just if-elseif all day long right?

Wrong.

This gets tremendously tedious very quickly. Let's look at an already existing example - in the current BEdit command line version there's a examples/png.bet, this file contains a very basic png file overview. Currently it looks something like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
default(endianess = big);

struct Header
{
    ...
};

struct Chunk_sRGB { ... };
struct Chunk_IHDR { ... };
struct Chunk_gAMA { ... };
struct Chunk_pHYs { ... };
struct Chunk_tEXt { ... };
struct Chunk_IDAT { ... };

struct Chunk
{
	u(4) size;
	string(4) type;
	if (type == "IHDR")
	{
		Chunk_IHDR IHDR;
	}
	else if (type == "tEXt")
	{
		Chunk_tEXt tEXt;
	}
	else if (type == "sRGB")
	{
		Chunk_sRGB sRGB;
	}
	else if (type == "gAMA")
	{
		Chunk_gAMA gAMA;
	}
	else if (type == "pHYs")
	{
		Chunk_pHYs pHYs;
	}
	else if (type == "IDAT")
	{
		Chunk_IDAT IDAT;
	}
	else
	{
		if (size)
		{
			raw(size) data;
		}
	}
	u(4) crc;
};

struct PNG
{
	Header header;
	Chunk ihdrChunk;
	assert(ihdrChunk.type == "IHDR");
	
	while (current_address() < size_of_file)
	{
		Chunk chunk;
	}
};


Whenever you add another chunk type, you have to add it to the if-chain as well. It's doable, but very annoying in the long run.

As such, I've started working on rudimentary reflection for BEdit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
default(endianess = big);

struct Header
{
    ...
};

struct category(chunk, "sRGB") Chunk_sRGB { ... };
struct category(chunk, "IHDR") Chunk_IHDR { ... };
struct category(chunk, "gAMA") Chunk_gAMA { ... };
struct category(chunk, "pHYs") Chunk_pHYs { ... };
struct category(chunk, "tEXt") Chunk_tEXt { ... };
struct category(chunk, "IDAT") Chunk_IDAT { ... };

struct Chunk
{
	u(4) size;
	string(4) type;
        
	// Not the best syntax...
	type_of(chunk, type) data;
	else
	{
		if (size)
		{
			raw(size) data;
		}
	}

	u(4) crc;
};

struct PNG
{
	Header header;
	Chunk ihdrChunk;
	assert(ihdrChunk.type == "IHDR");
	
	while (current_address() < size_of_file)
	{
		Chunk chunk;
	}
};


I think this feature could help out a lot since I've found myself writing similar if-chains in other formats too.

Next on the list (well, some already implemented) is constant evaluation and treating "current address" as a modifiable variable.

By constant evaluation I mean not only optimizing expressions that can be evaluated during instruction generation, but also when defining enums. This means ticket #6 will get implemented!

The keyword current_address() is also getting deprecated in favor of just plain at-sign @. This unifies the current address modifications as previously the only way to modify it was by adding a member, now you can simply do @ = whatever and the next member will be at whatever address.

There are still some more features I'd like to get in to next release so I can't say for sure when I'll push the button but if you have any suggestions on what to put on top of the priority list - head over to github and open a ticket!... Or you know, just post here on the forums.
Log in to comment