Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
3.00/5 (1 vote)
See more:
Hi, there. I'm currently working on a basic compiler using C# and the Common Intermediate Language (CIL) to create a basic programming language (just for fun in my spare time). I forked the original project from GitHub and began adding to it. The original project allowed for basic console output, which allowed users to print either string literals, integers, or pass in variables (whose type would be string or int). Like this:
print "some line of text.";
print 50;
var x = 150;
print x; // prints 150, of course.

I'm now at a point where I want to allow users to inject variables into a string directly, have the string parsed, then the variables get replaced with their values. I think I may not have explained that well, so here's an example of what I'm trying to do (note, one change I made to the language was the syntax):
String player_name = "Ra";
Integer player_health = 2000;

// This ideally would print "Hello, Ra! You have 2000 health."
@IO:Print("Hello, {$player_name}! You have {$player_health} health.");

At the moment, I can only output my intended Text by doing:
@IO:Print("Hello, ");
@IO:Print(player_name);
@IO:Print("! You have ");
@IO:Print(player_health);
@IO:Print(" health.");

Despite the fact that this works, it's horrible to look at, requires multiple function calls, and more lines of code. Hence why I want to 'inject' variables directly into strings.

Just as reference here is a link to the original project that I forked, and here is a link to my forked version. Oh, and if you click the link to my repository, note I haven't exactly commented things yet. :(

Chances are there's something I haven't quite explained properly. Feel free to ask me to elaborate.

- MaidenKeebs

What I have tried:

When I say "my_string", I'm just referring to this string:
"Hello, {$player_name}! You have {$player_health} health!"

Right, I split my_string up into segments to a List<string> which gave me this:
s[0] = "Hello, ";
s[1] = "$player_name";
s[2] = "! You have ";
s[3] = "$player_health";
s[4] = " health.";

Then I generate IL for each string in the list above. The rules I use here is that if the string starts with "$", generate IL code to load the variable to the stack (Ldloc). Otherwise just load the string (Ldstr).

After that, I generate IL code to call the "IO:Print" function. Now, because the text that "IO:Print" would output to the screen contains string literals AND variables (and a varied number of each), I defined the "IO:Print" function as:
// Maybe something wrong with this?
public sealed class IO
{
    public static void Print(params[] string arguments)
    {
        // Probably wrong.
        Console.WriteLine(arguments.ToString());
    }
}

Just as a thing, I used ILDasm to look at the generated IL and this is what it shows:
ldstr   "Hello, "
ldloc.0                  // 0 points to 'player_name'.
ldstr   "! You have "
ldloc.1                  // 1 points to 'player_health
ldstr   " health."
call    void [gfn]GfnCompiler.GfnStdLib.IO::Print(params[] string)


To me, the IL code has generated properly, but the function doesn't call using the intended string/variable arguments.
Posted
Updated 18-Mar-16 7:15am
v3
Comments
Sergey Alexandrovich Kryukov 18-Mar-16 19:50pm    
In .NET, there is no such thing as arbitrary (or even variable number of arguments). Number of arguments is always fixed, period.
There is purely syntactic sugar expressed as "params" argument, but this is only one argument, in fact.
—SA

1 solution

My first thought is that you need to do the equivalent of calling .ToString() on any values that aren't already string.
You could either do that when you generate the IL at the point of the (Ldloc) or change IO.Print to something like:
C#
public sealed class IO
{
    public static void Print(params[] object arguments)
    {
        Console.WriteLine(string.Concat(arguments));
    }
}

You could take this a step further and generate the call to string.Concat(...) any time you needed to process such a string and then it would work for assigning this type of string into another string variable. You probably want something that indicates if you want the string "processed" or not. There ought to be cases when you want to copy the unprocessed string without doing the "interpolation".
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900