❔ System.Linq.Expressions custom expression
Hi guys!
I'm parsing a custom language and building an Expression Tree based on it, but I came into an issue:
My language can use Labels, but since I parse the file line by line, I can't reference a label that hasn't been parsed yet when creating a
Goto
expression.
So parsing something like that would give issues:
So, my idea was to inherit the Expression
class to create a kind of LazyGotoExpression
, where the LabelTarget
would be evaluated by the time the expression is compiled, but I have no clue how to do that.
Could you guys give me a hand?
Current parsing code:
If there is a way to make a custom Expression
return another Expression
instance, that would be perfect.67 Replies
Nvm, I guess this does the trick:
This is a cool looking project. Would you mind sharing the source code? I always get excited by custom languages
I'll surely do. I'm porting an old Brazilian game to Unity 3D
The game is Alien Anarchy
I'll post the source on GitHub soon (what I've done so far)
Oh man that's even more cool
Original game screenshot:
Map loaded in Unity
Still missing some floor and ceiling stuff, and I have to adjust the skybox texture
So, the engine is ACKNEX (3D Game Studio). Version 3.0, I guess
It uses a custom script language (similar to Basic)
So I'm converting the script files to Expression Trees in runtime
Aaah so you're making a parser that you can plug the existing scripts into
Yes
There are other few games made using the same engine, so the code could potentially be used to run them in the future as well
Ah do you plan to keep the ported engine and this game separate, then, so other people can port whatever games they want?
Yes. Idk if it is legal to share the game files. They are listed as abandonware, since the company has ended
I can reach one of the developers and ask if he agrees on sharing the game data files, tho
Not too far off what started the FOSS movement in the first place, tbh
The company who created the engine still exists, tho. And the game has some script files that company has written. One more reason I'm not sure about sharing the game files (which you can easily find anywhere in the internet)
I always wanted a modern port of this game
Civvie 11
YouTube
The Varginha Incident - Vicious Cycles
Possibly I've seen too much.
Patrons see episodes early: https://www.patreon.com/civvie11
Twitter: https://twitter.com/civvie11
Join the Dungeon Discord: https://discord.gg/CEBKKJS Links: https://www.youtube.com/user/SpeedySPCFan/videos - Speedy's channel #FreeCivvie #DOS #Retrogaming
Join the Dungeon Discord: https://discord.gg/CEBKKJS Links: https://www.youtube.com/user/SpeedySPCFan/videos - Speedy's channel #FreeCivvie #DOS #Retrogaming
This custom expression thing I did is not working, tho
What's wrong with it?
It doesn't seem to do what I want it to do
I just want to make a
Goto
Expression
that only evaluates when it is compiled
Bc by that time, I would have the Label
references created
A lazy gotoThe second snippet you pasted never sets
Label
Nor does it inherit itBy Label, I mean any label I create by code
A
GOTO
statement can be declared before a LABEL
statement
So the goto expression must be evaluated when the syntax is compiled or right before it
The syntax is compiled at CloseAndCompile
Yes I remember bumping into a similar problem when I was writing a language parser in lua a few years back
Random question for thought - are the labels meant to be case sensitive?
No idea, in the original format they are declared like this:
I add a token
LABEL
as the first token in the list to indicate it is a label (only bc I'm lazy to fix it the right way)
When I find something like no_quake:
Nice readingCode with the wind
Extending LINQ Expressions
In the previous post we looked into what expression trees are and how they can be used. While this is enough most of the time, you may find yourself wondering if you can extend expressions. This might especially be the case if you are constructing expression trees directly via factory methods and you just need to pass some additional data which ...
This seems to work
Hmm you think you were overriding the wrong method before?
Sorry I was still absorbing your code / watching that video you posted haha
Yes, now it works, but my "if" parsing is wrong, trying to understand why
I can send u the github linq later, if u want to check it out
I was just looking into Linq Expressions - I've never used those before. They're quite neat
yos
Oh you might also be interested to know that
switch
is better than it used to be and that ParseExpression
can use list patterns
Here's an example I've just put togetherYes, I see
Just could not optimize it yet
I'm still getting used to newer C# syntax sugar
hmm
Just realized the script version the game uses has onliner IFs only
Not block ifs
Easier to parse
Your examples of
IFEQUALS
seem to have their body on the following line, though?The original script files doesnt
Just oneliners, so far
Trying to understand what they call RULES
Seem to be expressions assigned to variables
Strange name to choose
U saw nothing yet :V
There arent many keywords, tho
Which is good
no idea what is branch
Bc there is the
CALL
command as well
Docs doesnt make it clearThere's
IF
and BRANCH
o.Oye
From the initial scripts, only 40 keywords left to "parse"
Actually, just dummy methods are implemented for the keywords
[SIN][SQRT], etc are parsed wrongly, I guess, they are meant to be inside a RULE
Other ones are generating valid expressions
That makes sense
Original
Are you making new textures rather than importing the old ones, then?
Importing the old ones
My language can use Labels, but since I parse the file line by line, I can't reference a label that hasn't been parsed yet when creating a Goto expression.So! This is typically done by passing through the source code in multiple phases. Initially you just parse and construct a tree where you don't resolve anything. In the next phase you can start resolving entities. The problem is that the expression tree API generally expects you know everything beforehand.
Yes. I fixed that by inheriting an Expression, and returning a goto statement in expression compile time
rick_o_max#7424
Quoted by
<@!934156543555932201> from #System.Linq.Expressions custom expression (click here)
React with ❌ to remove this embed.
Yeah that's actually a very clever trick
I didn't know the Expression API would allow for something like this
So Im thinking about the state machines now
So an action (method) could be stopped/resumed
Essentially coroutines I assume
I could use a switch on the methods first expressions
Yes
But cant use default Unity coroutines bc expressions cant yield anything
Im using expressions bc I dont want to create an interpreter
And code compilation does not work on iOS and WebGL on Unity
Well a wild idea, if this is a serious attempt at porting the engine, why not write a bytecode interpreter?
Hmm
What would be the benefits?
You don't need to do workaround with the expression tree API and it's a bit easier to debug a visible bytecode than a tree IME
The downside is that it's more work yes, but if the language is fairly simple, it's not even a gigantic task
I assume there's no fancy stuff like type-inference, closures, ... so it'd be a fairly simple one
The language is basically an early basic version
The version Alien Anarchy uses is even simpler
So not even statically typed, that's really cool
Do you have some specification for the language?
Or at least sizable examples?
It only has one liner IFs, no LOOPs (so far, Im still going thru all sources)
Will send it, one sec
This is the official API doc
It is from a newer engine version, but many things can be applied to Alien Anarchy
Sent you a PM
ACTION
keyword declares an action (a method)
RULE
is basically a local variable that receives an expression value
SYNONYM
represents a "group", which can have custom fields. This synonym can be applied to any game object, so N objects can use the fields from a single synonym
SKILL
represents a global variable (float type), which can have its values clamped automatically (min, max)
IFDEF
, IFNDEF
, ENDIF
, IFELSE
, DEFINE
, UNDEF
are compiler directives
ACTOR
is used to represent an object that can move, have animations, etc
THING
is a static object
BMAP
is a bitmap (PCX files in Alien Anarchy)
TEXTURE
is a texture which can use a series of BITMAP
s, and can be applied to walls, ceilings and floors
REGION
is a convex 2D region outline (topdown)
WALL
represents the walls between two regions
WAY
represents a path, made of waypoints
SOUND
represents a sound file (WAV in Alien Anarchy)Yeah this looks really-really simplistic so far fortunately
Script-wise, most complicated stuff are the
WAIT
and WAITT
keywords
As I said, these makes the script waits for N frames or N ticks
Actions can't use parameters or return values, which makes it even simplerWaypoint parsing
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.