How To Have Comments In Haxe Be In Target Languages?

Summary: See sample code near the end of this thread for a way that works.

Hopefully I am foolishly missing something.
Would really like to have Comments in Haxe be passed along to generated target languages.

WHY ?
I am working on a project (not yet Open Source) that allows anyone to edit definitions in a Dictionary in a simplified natural language of their choice. The project then takes the definitions and runs them (Interpreter is a rough prototype). So you could do Computer Programming without needing to know English or Programming before. I have some simple proofs of concept working with some European languages.

I then had an A HA ! ! ! momentā€¦
Comments are available as part of the simplified natural language
AND my Interpreter outputs the various details as it evaluates stuff
THEN I can have an output of the Interpreter reformatted into Haxe source.
I need to faithfully copy the Comments also to the Haxe source.
I would likely have an Option or Feature to add comments that relate the original word Name and definition to the appropriate Haxe source.

Having Comments in their own language while reading the generated language sources I expect to enable some awesome A HA moments from those using the project.
And also generate a large respect for the Haxe community.

Thanks for your help!
Randy Maxwell
p.s. My coding style has LOTS of Comments in the Haxe sources. Because of the complexity of my Interpreter and the mistakes I make :slight_smile: I spend significant time in C++ or C# or Python or Web Debuggers. Having Comments would help me find things quicker while Debugging. Like using the source Map view at the right side of Visual Studio Code showing Comments in Green for example.

2 Likes

Iā€™m not sure thereā€™s a way to do this apart from ugly hacks like:

static function main() {
    untyped __js__("// some comment");
}

Which would generate this on JS:

Test.main = function() {
	// some comment;
};

Thanks Jens.
I already saw the earlier post about this for JavaScript.
I am talking about a LOT more than a single line comment here or there.

It was Really Cool to see the results given from your link.
Thanks to the Haxians who made the Web hosted Haxe run work.

But to help others learn programming I would think they would want Comments in at least a few other languages like:
Java
C++
C#
Python
which are what I have been targeting along with JavaScript.
Best case would be ALL the target languages.

Still hoping I have missed something.
Thanks!
Randy Maxwell

You can make a nice function of this yourself:

In Haxe 3 you would do:

public static inline function comment(message:String) {
  return untyped __js__("// {0}", some comment);
}

In Haxe4 this would be

public static inline function comment(message:String) {
  return js.Syntax.code("// {0}", some comment);
}

or to make it Haxe3 and 4 compatible: Try Haxe !

2 Likes

Nice Mark ! Looks simple but I think itā€™s the first time I see a clean solution to this regular question.

Mark,
Good info about how Comments can be output during generation of JavaScript.

If I needed to do manual detailed edits to transfer Comments I would really like to know that the other Haxe target languages would work and not be limited to JavaScript.

Thanks anyway!
Randy Maxwell

I may be not understanding something, but I think you could do conditional compilation in that inlined function and cover all your targets.

public static inline function comment(message:String) {
#if python
  return untyped __python__("# {0}", some comment);
#elseif js
  return untyped __js__("// {0}", some comment);
#elseif php
  return untyped __php__("/* {0} */", some comment);
#end
}

Could this be a good use case for macros? Hm, perhaps not yet, because I assume the comments donā€™t get parsed into the abstract syntax tree. Perhaps a compiler flag could (in the future) allow that?

I think this is something that can be handled in the compiler somehow.

The main problem I see with this is that the target code can be quite different than the Haxe code.

Letā€™s say you write some comments about a generic type, unsupported in JS. And you use that in a number of generic classes and interfaces. The output may become quite confusing.

Iā€™d stick with a system of documenting function signatures & parameters, but even this might require some compiler support.

Thatā€™s an interesting thinking. In fact some comments are extracted by the parser - functions ā€œjavadocā€ show up in completion.

However that probably wonā€™t make sense for inline comments.

Iā€™d suggest to raise a request in Haxe GitHub.

I would love to see Haxe supporting this kind of documentation for fields and types (in combination with something like -D keep_comments=pack,otherpack, which would keep comments in the output.

/*!
  Exposed in output
*/
public var word: String;

Thanks for the helpful feedback.
Sorry for my late reply.

JavaScript and Python work (I am guessing PHP but I did not try).
(based on [Haxe 4.0.0-preview.3 - Haxe - The Cross-platform Toolkit](Haxe 4.0.0-preview.3 - Haxe - The Cross-platform Toolkit Deprecations )
When I try C++ or C# or Java the Haxe compiler finishes but the language compilers give various Errors.

I tried to make a little utility class to help anyone else that wants to have Comments survive. I tried using the @remove Haxe flag but no success.

I expect I am missing something about controlling the Haxe compiler here.

To Reproduce:
If you have your Main in a separate file then I expect you will find the same Errors I did.

/*
 * Comments.hx	This supports Comments in various Haxe target programming languages
 *
 * 		THIS ONLY SEEMS TO WORK FOR JAVASCRIPT AND PYTHON (maybe PHP, I did not test)
 * 
 * 		OTHER target languages like: C++, C# and Java   FAIL
 * 			Haxe compiler finishes but language specific compiler haves various errors.
 */

// Here I use the same package name as where this code is used.  Change to fit your needs.
package lg4;

/** 
 * @author Randy Maxwell
 */

@:remove
class  Comments
{

//		Helper to put Comments in output target languages
//		This gets called during a Haxe compile
//	
//	public static var comment_call_count = 0;
//	public static var comment_multiline_call_count = 0;

@:remove
	public static inline function comment( multiline : Bool, message : String )
	{
		// var retVal = "UNKNOWN  target Language.  ";
//		comment_call_count++;

//		if ( multiline )
//			comment_multiline_call_count++;

		// To find number of single line comments use  
		//  comment_call_count  -  comment_multiline_call_count

	#if (haxe_ver >= 4.0)
		#if cpp				// C++
			if ( multiline )
				return untyped __cpp__("/* {0} */", message);
			else
				return untyped __cpp__("// {0}", message);

		#elseif cs			// C#
			if ( multiline )
				return untyped __cs__("/* {0} */", message);
			else
				return untyped __cs__("// {0}", message);

		#elseif fl			//  SWF ?  maybe commonly called flash ?
			if ( multiline )
				return fl.Syntax.code("/* {0} */", message);
			else
				return fl.Syntax.code("// {0}", message);
		
		#elseif hl			// HashLink   NOT SURE if  HashLink  even HAS comments ?
			if ( multiline )
				return hl.Syntax.code("/* {0} */", message);
			else
				return hl.Syntax.code("// {0}", message);

		#elseif java
			if ( multiline )
				return java.Syntax.code("/* {0} */", message);
			else
				return java.Syntax.code("// {0}", message);

		#elseif js			// JavaScript
			if ( multiline )
				return js.Syntax.code("/* {0} */", message);
			else
				return js.Syntax.code("// {0}", message);
		
		#elseif lua
			if ( multiline )
				return lua.Syntax.code("/* {0} */", message);
			else
				return lua.Syntax.code("// {0}", message);
				
		#elseif neko			// NOT SURE if  Neko  even HAS comments ?
			if ( multiline )
				return neko.Syntax.code("/* {0} */", message);
			else
				return neko.Syntax.code("// {0}", message);
		
		#elseif php
			if ( multiline )
				return php.Syntax.code("/* {0} */", message);
			else
				return php.Syntax.code("// {0}", message);

		#elseif python
			if ( multiline )	// uses 3 double Quote characters before and after
				return python.Syntax.code("\"\"\" {0} \"\"\"", message);
			else
				return python.Syntax.code("# {0}", message);
		#else
				// return "UNKNOWN  target Language.  ";
		#end
	#end
	
    #if (haxe_ver < 4.0)
		// User older syntax from Haxe
		#if cpp				// C++
			if ( multiline )
				return untyped __cpp__("/* {0} */", message);
			else
				return untyped __cpp__("// {0}", message);
		
		#elseif cs			// C#
			if ( multiline )
				return untyped __cs__("/* {0} */", message);
			else
				return untyped __cs__("// {0}", message);
		
		#elseif fl			//  SWF ?  maybe commonly called flash ?
			if ( multiline )
				return untyped __fl__("/* {0} */", message);
			else
				return untyped __fl__("// {0}", message);

		#elseif hl			// HashLink   NOT SURE if  HashLink  even HAS comments ?
			if ( multiline )
				return untyped __hl__("/* {0} */", message);
			else
				return untyped __hl__("// {0}", message);
		
		#elseif java
			if ( multiline )
				return untyped __java__("/* {0} */", message);
			else
				return untyped __java__("// {0}", message);

		#elseif js			// JavaScript
			if ( multiline )
				return untyped __js__("/* {0} */", message);
			else
				return untyped __js__("// {0}", message);
				
		#elseif lua
			if ( multiline )
				return untyped __js__("/* {0} */", message);
			else
				return untyped __js__("// {0}", message);
				
		#elseif neko			// NOT SURE if  Neko  even HAS comments ?
			if ( multiline )
				return untyped __neko__("/* {0} */", message);
			else
				return untyped __neko__("// {0}", message);
		
		#elseif php
			if ( multiline )
				return untyped __php__("/* {0} */", message);
			else
				return untyped __php__("// {0}", message);

		#elseif python
			if ( multiline )	// uses 3 double Quote characters before and after
				return untyped __python__("\"\"\" {0} \"\"\"", message);
			else
				return untyped __python__("# {0}", message);
		#else
				// return "UNKNOWN  target Language.  ";
		#end
    #end
	
		// return retVal;
	}
}

Thanks for you help!

1 Like

What kind of errors do you get? This should in theory work so otherwise we have to report an issue on GitHub.

Also for flash you need #if flash instead of fl

You can leave flash neko and hashlink out, doesnt make sense to have comments there.

Maybe you can add this in your else statement:

#else 
 #error "comment not supported on this platform";
#end

Which results in a compilation error.

All,

I think the problem is:
We want the comments to be substituted in place of a call to comment( ) at some time during a Haxe compile.
We do Not want the little Comments class and member function comment() to be output as generated C++ or other language source code.

Running the small sample that Mark kindly made available
or to make it Haxe3 and 4 compatible: https://try.haxe.org/#77000
When we look at the generated JavaScript source the little comment( ) helper is Not generated which is what we want.

Anyway the C++ Error

Error: Comments.cpp   ( I expect this file should not exist )
Comments.cpp(31): error C2561: 'lg4::Comments_obj::comment': function must return a value
Comments.cpp(28): note: see declaration of 'lg4::Comments_obj::comment'
Comments.cpp(35): error C2059: syntax error: '}'

Generated Comments.cpp fragment from lines 28 to 37

28  ::Dynamic Comments_obj::comment(bool multiline,::String message){
29            	HX_STACKFRAME(&_hx_pos_1f094a32dd694c7d_41_comment)
30 HXDLIN(  41)		if (multiline) {
31 HXLINE(  42)			return /* message */;
32            		}
33           		else {
34 HXLINE(  44)			return // message;
35            		}
36 HXLINE(  41)		return null();
37            	}

We see a single line comment on line 34 that also includes the trailing ;
which the compiler correctly complains about (in so many words).

So the Haxe compiler is generating a Comments.cpp source when no generation is wanted, just a form of text inserting of a comment.

The good news: The comment is inserted in the C++ source where expected.
Looking at where I tested with a single line and multiline comment:

|HXLINE( 139)   // HX_("                             Helper to do a possibly large amount of a definition ",4e,10,e7,66);
|HXLINE( 142)  /* HX_("  Helper to do a possibly large amount of a definition\n\nPre Conditions\n\tNo Quoted strings to worry about\n\nPost Conditions\n\treturned array with added strings that represent tokens to resolve later",59,33,2c,c6) */;|

We see that the inserted Comments have correct C++ syntax.
I see some extra information around the comment.
It would be nice if expansion of \n and \t characters happen when the multiline Comment is inserted.

Hope this helps!
Randy Maxwell
ps I tried various ways to use the Haxe macro approach. In my experiments & reading I could Not find a way to preserve an inserted Comment. And I did not find a Comment type at the macro level. Hopefully I am missing something here as well.

Didnā€™t check but you should be able to change public whatever comment( ā€¦ ) to macro public whatever comment( ā€¦ ) and then inside of comment() function instead of return untyped ā€¦ you do return macro untyped ā€¦, and it should just work.

Inline functions are a great help for stuff like this :slight_smile:

Instead of having comment(multiline, message) you could also create two functions commentBlock(message) and commentLine(message), thatā€™ll solve this inlined if (multiline) statement.

About the multilines \n issue, this is something I donā€™t know.

Dunno ā€¦ to me, the generated source-code (e.g. PHP, JS) is often so very different from the Haxe original that I rather think that the comments should just be in the original, which is what the developers would actually maintain. I usually regard the generated output-code as a black box.

One thing that might be useful if itā€™s not there now ā€“ ā€œThis is an automatically-generated file produced by Haxe. Do not modify by hand.ā€

1 Like

All,
SUMMARY:
I did Not test all available target languages.
My WORKAROUND is better in the sense that I can see (somewhat badly formatted) Comments that stand out nicely with the Color Syntax highlighting most Editors/Debuggers support. For myself I am moving on to other project features.

@ sundialservices
I agree with your general cautions about Editing any Generated code.
BUT
The project is to enable people to learn Computer Programming. Having a way to insert Comments into generated code is part of learning about programming because it allows traceability of original NL style syntax as it is transformed to Haxe and then to the generated sources. I expect this will help the learning process. Also the Comments may be in languages other than English; again to help learning.

@SaintAnne, All
I tried using macro and untyped but either I could not get the macro code to compile
or
the macro would compile but Not insert any Comment where wanted.
My knowledge of Haxe macro is sadly lacking :slightly_smiling_face:

@mark.knol, All,
2 WORKAROUNDS Applied:
1: Changed to only do multiline style Comments. Single line comments are as multiline.
This covers the case where the Comments class file is still generated in the target language after the Comment was actually inserted. This avoids the language specific compiler errors.
2: Used the multiline Strings form given in:
https://code.haxe.org/category/beginner/strings.html

PROBLEMS Remaining:
My tests only include C++, C#, Java, JavaScript and Python
Other output languages Not tested by me.

The inserted Comments are cluttered with \n and \t
and also with extra characters before and after the inserted Comment.
I can get rid of \t by using 4 blank spaces as I use for Tabs in editors.
Not sure if I can get rid of \n or the extra characters.
So the READABILITY of the inserted Comment is less than the original in Haxe.

Thanks to you all for your help!

This

import haxe.macro.Expr;

class Comments {
    static function main() {
        var x = 1;
        comment( "hello", "there", "world" );
        trace( x + 1 );
    }

    macro static function comment( first:Expr, rest:Array<Expr> ):Expr {
        var cmts = [ first ].concat( rest ).map( extract ).map( x -> macro untyped __js__( '/* $x */' ) );
        return macro $b{cmts};
    }

    static function extract( e:Expr ) return
        switch e.expr {
            case EConst( CString( v ) ): v;
            case _: "not a proper comment";
        }
}

Compiled like this

haxe -js out.js -main Comments -dce full

Produces this:

// Generated by Haxe 4.0.0-preview.5+7eb789f54
(function () { "use strict";
var Comments = function() { };
Comments.main = function() {
	var x = 1;
	/* hello */;
	/* there */;
	/* world */;
	console.log("Comments.hx:7:",x + 1);
};
Comments.main();
})(); 

If you actually want multiline comments from a single multiline string then youā€™ll have to just split the string by ā€˜\nā€™, and everything else should remain the same.

1 Like

I gotta say ā€“ and this is just my opinion ā€“ that ā€œshenanigans like that wouldnā€™t pass my code-review.ā€ If I was your manager or team-lead, Iā€™d make you take it out and fuhgeddaboudit. (But, of course, Iā€™m not.)

I really donā€™t see the value in putting comments into generated code that no oneā€™s supposed to be looking at anyway, and I would veto all of these various ways to try to do it. If the insertion of comments into compiler-output source code is a feature desired by the community, then I say that it should be inserted into a future release of Haxe as a formal compiler feature ā€“ with strictures specifically designed to prevent it being used to insert executable code (compile-time ā€œcode injectionā€).

Among the problems that I see in it are the implicit assumption that the comment, wherever it was inserted, would actually be nearby to the generated code, and so somehow actually relevant to it. I donā€™t think that we should impose any such assumptions on the compilerā€™s output-stages. Comments about what the Haxe source-code is doing, IMHO, belong in ā€œthe only source-code that really exists ā€“ the Haxe source-code that people actually wrote.ā€

But ā€“ thatā€™s just me, and I damn-sure donā€™t wanna start a flame-war. ā€¦ :slight_smile:

1 Like