1 /*
   2  * This is a test whether the compiler properly supports named function
   3  * parameters (arguments), so that arguments of functions do not always
   4  * need to be written in the same order.
   5  */
   6 
   7 #target WASI //Will make JavaScript a bit shorter.
   8 
   9 Structure ComplexNumber Consists Of
  10   Decimal32 real, imaginary;
  11 EndStructure
  12 
  13 Structure QuadraticEquationSolution Consists Of
  14   ComplexNumber firstSolution, secondSolution;
  15 EndStructure
  16 
  17 Function solveQuadraticEquation(Decimal32 a := 1, Decimal32 b := 0,
  18                                 Decimal32 c := 0,
  19                                 QuadraticEquationSolutionPointer solution)
  20                                 Which Returns Nothing Is Declared;
  21 Function abs(Decimal32 x) Which Returns Decimal32 Is Declared;
  22 Function areStructuresEqual(NothingPointer first, NothingPointer second,
  23                             Integer32 sizeOfStructuresInBytes)
  24                             Which Returns Integer32 Is Declared;
  25 
  26 Decimal32 goldenRatio := (sqrt(5) + 1) / 2,
  27           epsilon := 1 / 100;
  28 
  29 Function printFloat32(Decimal32 x) Which Returns Nothing Is Declared;
  30 /*
  31  * We cannot make it external because we are not actually using WASI, and the
  32  * compiler thinks we are, and will output code that will not run in NodeJS.
  33  * Therefore, we need to import the function from JavaScript manually in
  34  * inline assembly. Not hard, fortunately.
  35  */
  36 asm("(func $printFloat32 (import \"JavaScript\" \"printFloat32\") (param f32))");
  37 
  38 // Should return 0.
  39 Function namedArgumentsTest() Which Returns Integer32 Does
  40   InstantiateStructure QuadraticEquationSolution solution[1 * 2 * 3];
  41   solveQuadraticEquation(a := 1 , b := -1, c := -1, AddressOf(solution[0]));
  42   // Since 'a' is set to default to 1 in the declaration of the
  43   // "solveQuadraticEquation" function, it does not need to be written
  44   // if it is indeed 1 when calling that function. In the next line, it is not.
  45   solveQuadraticEquation(c := -1, b := -1, solution := AddressOf(solution[1]));
  46   solveQuadraticEquation(b := -1, c := -1, solution := AddressOf(solution[2]));
  47   solveQuadraticEquation(b := -1, c := -1, a := 1 , AddressOf(solution[3]));
  48   solveQuadraticEquation(c := -1, a := 1 , b := -1, AddressOf(solution[4]));
  49   solveQuadraticEquation(c := -1, b := -1, solution := AddressOf(solution[5]));
  50   Integer32 iterator := 0;
  51   While iterator < 1*2*3 - 1 Loop
  52     If not(areStructuresEqual(AddressOf(solution[iterator]),
  53                               AddressOf(solution[iterator + 1]),
  54                               SizeOf(QuadraticEquationSolution))) Then
  55       Return iterator + 1;
  56     EndIf
  57     iterator += 1;
  58   EndWhile
  59   iterator := 0;
  60   // Let's test whether structure comparisons work...
  61   While iterator < 1*2*3 - 1 Loop
  62     If not(solution[iterator] = solution[iterator + 1]) Then
  63       Return iterator + 7;
  64     EndIf
  65     iterator += 1;
  66   EndWhile
  67   iterator := 0;
  68   While iterator < 1*2*3 - 1 Loop /*
  69                                    * This loop should have no effect,
  70                                    * but the compiler must not crash
  71                                    * when compiling it.
  72                                    */
  73     solution[iterator] := solution[iterator + 1];
  74     iterator += 1;
  75   EndWhile
  76   If not(solution[0].firstSolution.imaginary = 0 and
  77          solution[0].secondSolution.imaginary = 0 and
  78          abs(solution[0].firstSolution.real + goldenRatio - 1) < epsilon and
  79          abs(solution[0].secondSolution.real - goldenRatio) < epsilon) Then
  80     printFloat32(solution[0].firstSolution.real);
  81     printFloat32(solution[0].firstSolution.imaginary);
  82     printFloat32(solution[0].secondSolution.real);
  83     printFloat32(solution[0].secondSolution.imaginary);
  84     Return 15;
  85   EndIf
  86   Return 0;
  87 EndFunction
  88 
  89 Function abs(Decimal32 x) Which Returns Decimal32 Does
  90   Return x < 0 ? -x : x;
  91 EndFunction
  92 
  93 Function areStructuresEqual(CharacterPointer first, CharacterPointer second,
  94                             Integer32 size) Which Returns Integer32 Does
  95   Integer32 i := 0;
  96   While i < size Loop
  97     If not(ValueAt(first + i) = ValueAt(second + i)) Then
  98       Return 0;
  99     EndIf
 100     i += 1;
 101   EndWhile
 102   Return 1;
 103 EndFunction
 104 
 105 Function sqrt(Decimal32 realNumber, ComplexNumberPointer result)
 106          Which Returns Nothing Is Declared;
 107 
 108 Function solveQuadraticEquation(Decimal32 a, Decimal32 b, Decimal32 c,
 109                                 QuadraticEquationSolutionPointer solution)
 110                                 Which Returns Nothing Does
 111   solution->firstSolution.real := -b;
 112   solution->firstSolution.imaginary := 0;
 113   solution->secondSolution := solution->firstSolution;
 114   InstantiateStructure ComplexNumber rootOfDiscriminant;
 115   sqrt(b*b - 4*a*c, AddressOf(rootOfDiscriminant));
 116   solution->firstSolution.real -= rootOfDiscriminant.real;
 117   solution->firstSolution.imaginary -= rootOfDiscriminant.imaginary;
 118   solution->secondSolution.real += rootOfDiscriminant.real;
 119   solution->secondSolution.imaginary += rootOfDiscriminant.imaginary;
 120   solution->firstSolution.real /= 2*a;
 121   solution->firstSolution.imaginary /= 2*a;
 122   solution->secondSolution.real /= 2*a;
 123   solution->secondSolution.imaginary /= 2*a;
 124 EndFunction
 125 
 126 Function sqrt(Decimal32 x, ComplexNumberPointer result)
 127         Which Returns Nothing Does
 128   If x < 0 Then
 129     result->real := 0;
 130     result->imaginary := asm_f32("(f32.sqrt\n"
 131                                  "\t(f32.sub\n"
 132                                  "\t\t(f32.const 0)\n"
 133                                  "\t\t(local.get 0)\n"
 134                                  "\t)\n"
 135                                  ")");
 136   Else
 137     result->real := asm_f32("(f32.sqrt\n"
 138                             "\t(local.get 0)\n"
 139                             ")");
 140     result->imaginary := 0;
 141   EndIf
 142 EndFunction
 143