Source code output

Ary Borenszweig ary at esperanto.org.ar
Wed Jul 17 07:13:30 PDT 2013


On 7/17/13 4:33 AM, Jacob Carlborg wrote:
> On 2013-07-17 05:27, JS wrote:
>> With heavy ctfe code generation usage is it possible to have the d
>> compiler output the source code after all mixin templates have been
>> "used"? This way it is easier to visually check for errors in the
>> generated code.
>>
>> I imagine one could use pragma in a "special way" to do this but I was
>> hoping for something more direct.
>>
>
> The Eclipse plugin Descent had a nice compile time view. In general it
> showed how the compiler lowers some features to other lower level
> features. I.e. "scope" is lowered to try-catch-finally. It also showed
> the result of string and template mixins. It was really nice to have.
> Too bad the plugin was abandoned. It never got any real support for D2.
>

Since Descent used a port of the D compiler to Java, I think the same 
can be done by tweaking dmd. You have the generated AST after semantic 
analysis and you can easily output that. But of course you need to be 
able to convert the AST to string with correct indentation.

In general, I think a compiler should *really* care about setting line 
and column numbers to AST nodes and assisting the user as much as 
possible, like providing a way to output the final representation of the 
program as a String.

For example compiling this program with D:

---
string foo() {
   return "void bar() {\n  return 1 + 2\n}";
}

void main() {
   mixin(foo());
}
---

gives this error:

foo.d(7): Error: expression expected, not ')'
foo.d(8): Error: found '}' when expecting ';' following statement
foo.d(8): Error: found 'EOF' when expecting '}' following compound statement
foo.d(7): Error: + has no effect in expression (1 + 2 + 0)

Can you see where is the error?

I'll show here some ideas which D can use, which we have implemented in 
Crystal.

1. Show errors in expanded macros:

Compiling this (similar to D's string mixins):

---
macro define_method(x)
   "
   def #{x}(x, y)
       x + y + )
   end
   "
end

define_method "hello"
---

Gives this error:

Error in foo.cr:9: macro didn't expand to a valid program, it expanded to:

================================================================================
--------------------------------------------------------------------------------
   1.
   2.   def hello(x, y)
   3.       x + y + )
   4.   end
   5.
--------------------------------------------------------------------------------
Syntax error in expanded macro:3: unexpected token: )

       x + y + )
               ^
================================================================================

define_method "hello"
^~~~~~~~~~~~~

2. The above should also work with semantic errors:

---
macro define_method(x)
   "
   def #{x}(x, y)
     x + y
   end
   "
end

define_method "hello"

hello(1, 'a')
---

gives this error:

Error in /Users/asterite-manas/Projects/crystal/foo.cr:11: instantiating 
'hello(Int32, Char)'

hello(1, 'a')
^~~~~

in macro 'define_method' 
/Users/asterite-manas/Projects/crystal/foo.cr:1, line 3:

   1.
   2.   def hello(x, y)
   3.     x + y
   4.   end
   5.

     x + y
       ^

no overload matches 'Int32#+'
Overloads are:
  - Int32#+(other : UInt8)
  - Int32#+(other : UInt16)
  - Int32#+(other : UInt32)
  - Int32#+(other : UInt64)
  - Int32#+(other : Int8)
  - Int32#+(other : Int16)
  - Int32#+(other : Int32)
  - Int32#+(other : Int64)
  - Int32#+(other : Float32)
  - Int32#+(other : Float64)
Couldn't find overloads for these types:
  - Int32#+(other : Char)

---

If you don't provide clear errors for metaprogramming, even though it 
can be very powerful, if you don't understand the errors you go slower 
and slower and maybe eventually you decide not to use those features.

For macros (string mixins), associate the AST nodes to virtual files 
whose source code is the expanded source code. Keep track of line *and* 
column numbers (lines alone are not enough when you have long lines).


More information about the Digitalmars-d-learn mailing list