1 /*
   2  * This will be my attempt to build a graphical application with AEC,
   3  * specifically, one that will draw a discrete mathematical curve using SVG.
   4  * A few years ago, I've made a similar program in JavaScript
   5  * ( https://flatassembler.github.io/fraktal.html ). I've never before
   6  * attempted to write a program that will draw the Dragon Curve in AEC,
   7  * because there is no obvious way to do it using console graphics (and my
   8  * old AEC compiler, targeting x86, was basically limited to console
   9  * graphics). Also, to do that, I'll need to do a bit of string manipulation,
  10  * and the old version of AEC didn't support string manipulation at all (The
  11  * only data types available were Decimal32 and Decimal32Array, and there
  12  * were no functions. It's because I wanted the code my compiler generates
  13  * not to favor one operating system over another, and x86 OS-es do those
  14  * things very differently). This version of AEC is about at good at string
  15  * manipulation as C is without a standard library. JavaScript has many
  16  * useful string manipulation functions, however, since they are actually
  17  * methods of the "String" class, there is no standardized way to call them
  18  * from a WebAssembly program, even though it's running on JavaScript
  19  * Virtual Machine. That's because WebAssembly standard tries to be agnostic
  20  * about other programming languages running on the same virtual machine,
  21  * which may be a good thing (Why make it necessary for a JavaScript program
  22  * to be running on the same virtual machine for any program that's compiled
  23  * to WebAssembly to make sense?).
  24  */
  25 
  26 // Let's import some JavaScript functions...
  27 Function drawLine(Integer32 x1,
  28                   Integer32 y1,
  29                   Integer32 x2,
  30                   Integer32 y2,
  31                   PointerToCharacter color,
  32                   Integer32 lineWidth) Which Returns Nothing Is External;
  33 
  34 Function applyTurtleTransformation(PointerToCharacter svgDirective)
  35     Which Returns Nothing Is External; // We won't use the turtle for actual
  36                                        // drawing, but we will move it and
  37                                        // rotate it.
  38 
  39 Integer32 directionX[4] : = {0, 1, 0, -1},
  40           directionY[4] : = {-1, 0, 1, 0},
  41           currentX : = 10,
  42           currentY : = 250 + 490 - 410, // When set on 250, the
  43                                         // turtle reaches 410 and
  44                                         // then turns back (I know
  45                                         // this by experimenting).
  46           currentDirection : = 0,
  47           lineLength : = 5,
  48           lineWidth : = 2,
  49           currentStep : = 0;
  50 
  51 Character path[16384], reversedPath[16384];
  52 
  53 // Again, we need to implement string manipulation functions. Like I've said,
  54 // even though this program will be running on JavaScript Virtual Machine, it
  55 // can't call the methods of the JavaScript "String" class.
  56 Function strlen(PointerToCharacter str) Which Returns Integer32 Is Declared;
  57 Function strcpy(PointerToCharacter dest, 
  58                 PointerToCharacter src) Which Returns Nothing Is Declared;
  59 Function reverseString(PointerToCharacter string) 
  60                 Which Returns Nothing Is Declared;
  61 Function strcat(PointerToCharacter dest,
  62                 PointerToCharacter src) Which Returns Nothing Is Declared;
  63 Function convertIntegerToString(PointerToCharacter string, Integer32 number)
  64     Which Returns Integer32 Is Declared;
  65 
  66 // This is the function that's supposed to be called by JavaScript as soon
  67 // as it is ready.
  68 Function init() Which Returns Nothing Does
  69     PointerToCharacter path : = AddressOf(path[0]);
  70     PointerToCharacter reversedPath : = AddressOf(reversedPath[0]);
  71     strcpy(path, "R");
  72     Integer32 counter : = 0;
  73     While strlen(path) < 8192 Loop
  74         strcpy(reversedPath, path);
  75         If mod(counter, 4) = 0 Then
  76             reverseString(reversedPath);
  77         EndIf
  78         strcat(path, reversedPath);
  79         strcat(path, not(mod(counter, 4)) ? "L" : "LLL");
  80         counter : = counter + 1;
  81     EndWhile
  82 EndFunction
  83 
  84 // This function is supposed to be periodically called by JavaScript:
  85 Function step() Which Returns Nothing Does
  86     If not(path[currentStep] = 0)
  87         and 0 < currentX < 500
  88         and 0 < currentY < 500 Then
  89         Integer32 nextX : = currentX + directionX[currentDirection] * lineLength,
  90                   nextY : = currentY + directionY[currentDirection] * lineLength;
  91         drawLine(
  92             currentX,
  93             currentY,
  94             nextX,
  95             nextY,
  96             currentStep = 0 ? "lightYellow"
  97                 : path[currentStep] = 'R' ? "red"
  98                     : path[currentStep] =
  99                         'L' ? "lightBlue" : "lightYellow",
 100             lineWidth
 101         );
 102         currentX : = nextX;
 103         currentY : = nextY;
 104         If path[currentStep] = 'R' Then
 105             currentDirection : = mod(currentDirection + 1, 4);
 106         ElseIf not(currentDirection = 0) and path[currentStep] = 'L' Then
 107             currentDirection : = currentDirection - 1;
 108         ElseIf path[currentStep] = 'L' Then
 109             currentDirection : = 3;
 110         EndIf
 111         Integer32 tmp; // I had no idea WebAssembly would behave that way,
 112                        // that the assembler will complain about not storing
 113                        // the result of a function. This is very different
 114                        // from x86 assembly. So, I modified the compiler
 115                        // to warn about that.
 116         currentStep : = currentStep + 1;
 117         Character turtleTranformation[64] : = {0};
 118         PointerToCharacter turtleTranformation 
 119                            : = AddressOf(turtleTranformation[0]);
 120         strcat(turtleTranformation, "translate(");
 121         tmp : = convertIntegerToString(
 122             turtleTranformation + strlen(turtleTranformation),
 123             currentX
 124         );
 125         strcat(turtleTranformation, " ");
 126         tmp : = convertIntegerToString(
 127             turtleTranformation + strlen(turtleTranformation),
 128             currentY
 129         );
 130         strcat(turtleTranformation, ") rotate(");
 131         tmp : = convertIntegerToString(
 132             turtleTranformation + strlen(turtleTranformation),
 133             currentDirection * 90
 134         );
 135         strcat(turtleTranformation, ")");
 136         applyTurtleTransformation(turtleTranformation);
 137     EndIf
 138 EndFunction
 139 
 140 Function strlen(PointerToCharacter str) Which Returns Integer32 Does 
 141     // We can't implement this recursively, like we did in earlier AEC
 142     // programs, because we will be dealing with large strings which will
 143     // cause stack overflow.
 144     Integer32 length : = 0;
 145     While ValueAt(str + length) Loop
 146         length : = length + 1;
 147     EndWhile
 148     Return length;
 149 EndFunction
 150 
 151 Function strcpy(PointerToCharacter dest,
 152                 PointerToCharacter src) Which Returns Nothing Does
 153     While ValueAt(src) Loop
 154         ValueAt(dest) : = ValueAt(src);
 155         dest : = dest + 1;
 156         src : = src + 1;
 157     EndWhile
 158     ValueAt(dest) : = 0;
 159 EndFunction
 160 
 161 Function reverseString(PointerToCharacter string) Which Returns Nothing Does
 162     PointerToCharacter pointerToLastCharacter : = string + strlen(string) - 1;
 163     While pointerToLastCharacter - string > 0 Loop
 164         Character tmp : = ValueAt(string);
 165         ValueAt(string) : = ValueAt(pointerToLastCharacter);
 166         ValueAt(pointerToLastCharacter) : = tmp;
 167         string : = string + 1;
 168         pointerToLastCharacter : = pointerToLastCharacter - 1;
 169     EndWhile
 170 EndFunction
 171 
 172 Function strcat(PointerToCharacter dest,
 173                 PointerToCharacter src) Which Returns Nothing Does
 174     strcpy(dest + strlen(dest), src);
 175 EndFunction
 176 
 177 Function convertIntegerToString(PointerToCharacter string, Integer32 number)
 178     Which Returns Integer32 Does // Returns the length of the string.
 179     Integer32 isNumberNegative : = 0;
 180     If number < 0 Then
 181         number : = -number;
 182         isNumberNegative : = 1;
 183     EndIf
 184     Integer32 i : = 0;
 185     While number > 9 Loop
 186         ValueAt(string + i) : = '0' + mod(number, 10);
 187         number : = number / 10;
 188         i : = i + 1;
 189     EndWhile
 190     ValueAt(string + i) : = '0' + number;
 191     i : = i + 1;
 192     If isNumberNegative Then
 193         ValueAt(string + i) : = '-';
 194         i : = i + 1;
 195     EndIf
 196     ValueAt(string + i) : = 0;
 197     reverseString(string);
 198     Return i;
 199 EndFunction