Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module-level static declarations (closes #7452) #8460

Merged
merged 3 commits into from
May 16, 2020

Conversation

nadako
Copy link
Member

@nadako nadako commented Jun 20, 2019

This PR implements module-level function, var and property declaration (proposed and discussed in HaxeFoundation/haxe-evolution#24):

final version = 4;

function main() {
    trace("Hello from version " + version);
}
Generated JS
function Main_main() {
	console.log("src/Main.hx:4:","Hello from version " + Main_version);
}
var Main_version = 4;
Main_main();

This is implemented the following way:

  • Definition:
    • Parse such declarations into the new type_def variant: EStatic of (placed_access, class_field_kind) definition
    • When loading module, all its EStatics are collected into a list of static fields for an implicitly created class (fields are public unless explicitly defined as private, just like types)
    • Class is created with a special cl_kind: KModuleStatics of module_def
    • Class is then stored into its module using new field m_statics : tclass option
  • Import:
    • import Mod will import all the module-level statics
    • import Mod.func [as name] will first try importing module-level func and Mod.func static field
    • import Mod.* will NOT import module-level statics (debatable, but consistent with it not importing other module-level declarations)
  • Resolution:
    • Unqualified name will first search for this-module statics and then imported ones
    • Qualified path will first look for module-level statics and then fall back to sub-type and main-type-static resolution.
  • Misc:
    • -main Mod works with module-level main function
    • using Mod will consider module-level static extension functions
    • Module-level macro functions are also supported
  • Macro:
    • New haxe.macro.Type.ClassKind variant: KModuleStatics(module:String)
    • New haxe.macro.Expr.TypeDefKind variant: TDStatic(kind:FieldType, ?access:Array<Access>)
  • Generation:
    • Target generator can choose to not generate KModuleStatics class and instead output functions and vars directly (implemented for JS)
    • If target still has to wrap them in class it can at least omit reflection helpers and apply extra optimizations (e.g. add static/final modifiers)

TODO checklist:

  • handle imported module-statics resolution
  • handle import pack.Module.moduleLevel
  • handle import pack.Module.moduleLevel as otherName
  • handle pack.Module.moduleLevel access (the MORDOR)
  • refactor TyperDotPath into something readable
  • finish parsing, support var, property, modifiers, etc.
  • adjust haxe.macro.Expr API
  • think of macro API to retrieve the statics class
  • discuss and decide module-scoping or package scoping
  • think of static extensions
  • handle display stuff
    • resume
  • double-check positions
  • check access control (i.e. @:access)
  • check @:rtti (ugh)
  • check haxe.PosInfos
  • add tests
    • test module-level -main on different targets (e.g. java)
    • test Context.defineType/defineModule for statics
  • support class-less main
  • support class-less --macro calls and @:build (tame eval)
  • flatten module-statics class in genjs (as an example)
  • discuss import Mod.*
  • filter out private when importing not to pollute the local namespace (prevents @:privateAccess but is consistent with private types)

Things that can be done after the merge: #9436

@nadako nadako added this to the Release 4.1 milestone Jun 20, 2019
@RealyUniqueName
Copy link
Member

Why is it called "globals" in AST but "module statics" after typing?

@nadako
Copy link
Member Author

nadako commented Jun 21, 2019

Why is it called "globals" in AST but "module statics" after typing?

Naming is hard :)

Well the idea is that the untyped AST does not care about whether it's implemented as statics or not, so it uses the term "global", which might as well be "module-local" or something, I'm not really sure.

In the typed AST it's implemented as statics collected in a class, so it makes sense to name it as that.

@nadako nadako force-pushed the module_level branch 2 times, most recently from 9575b29 to ab8db8d Compare June 24, 2019 19:26
@nadako nadako force-pushed the module_level branch 3 times, most recently from 3d29516 to b3b83eb Compare February 9, 2020 12:20
@Simn Simn modified the milestones: Release 4.1, Release 4.2 Feb 13, 2020
@nadako nadako force-pushed the module_level branch 2 times, most recently from c333f12 to f0fd752 Compare February 16, 2020 14:05
@nadako
Copy link
Member Author

nadako commented Feb 16, 2020

Well the idea is that the untyped AST does not care about whether it's implemented as statics or not, so it uses the term "global", which might as well be "module-local" or something, I'm not really sure.

Thinking about this with a "fresh" head, maybe we should officially call them module statics. It is easy to pronounce, close to the implementation and rather easy to understand: "like class statics, but module statics".

@nanjizal
Copy link
Contributor

So you could have module level static functions, with module level properties and constants ( finals ) soon to be implemented, but are you going to change EGlobal to EModule ?

@nadako
Copy link
Member Author

nadako commented Feb 16, 2020

EStatic, I guess, but yeah :)

@fullofcaffeine
Copy link

Will modules have some kind of initialiser hook? I mean, in js you can just add code to the body to be ran when at runtime when the module is interpreted and it can be quite useful.

@nadako
Copy link
Member Author

nadako commented Feb 16, 2020

Will modules have some kind of initialiser hook? I mean, in js you can just add code to the body to be ran when at runtime when the module is interpreted and it can be quite useful.

I am not sure what exactly are you asking here. In JS modules are loaded at run-time, while in Haxe we just load them at compile-time to find and build the classes, there's no concept of a module at run-time.

@fullofcaffeine
Copy link

I'm aware that it's a compile-time feature. I was just curious if some abstraction for initialization would be provided that would then run at runtime, but I'm probably not fully aware of the implementation and how it's going to work.

@RealyUniqueName
Copy link
Member

I wonder if defining function __init__() would automatically work with the same semantics as static function __init__() because module functions get compiled as static function of an auto-genetared class.

@nadako
Copy link
Member Author

nadako commented Feb 16, 2020

I think it will, but so will var initializations - both will be executed at program startup.

@nadako nadako force-pushed the module_level branch 2 times, most recently from 5eae1e5 to 55970a3 Compare February 17, 2020 20:14
src/typing/typeloadModule.ml Outdated Show resolved Hide resolved
@nadako nadako force-pushed the module_level branch 2 times, most recently from 9bf5973 to 5e9d742 Compare March 28, 2020 13:40
@nadako nadako mentioned this pull request Apr 5, 2020
@nadako
Copy link
Member Author

nadako commented Apr 5, 2020

This should close #7452

@nadako
Copy link
Member Author

nadako commented Apr 30, 2020

(blindly) rebased on top development with all the latest changes, let's see if tests still pass

@nadako nadako force-pushed the module_level branch 2 times, most recently from 72651ec to 991550d Compare May 15, 2020 15:09
@nadako nadako marked this pull request as ready for review May 15, 2020 15:26
@nadako nadako force-pushed the module_level branch 2 times, most recently from eff9b32 to 61dee7c Compare May 15, 2020 16:35
@nadako
Copy link
Member Author

nadako commented May 15, 2020

I need to check and add test for the behaviour of module-statics regarding #9367, and will merge afterwards.

@jeremyfa
Copy link

jeremyfa commented May 15, 2020

A fun side effect of this evolution is that one could create module level code in, say, Mod.hx and make it compatible with hscript very easily (no surrounding class etc...).

Looking awesome overall!

@nadako nadako merged commit 01cfe55 into HaxeFoundation:development May 16, 2020
@nadako nadako deleted the module_level branch May 16, 2020 13:49
@skial skial mentioned this pull request May 18, 2020
1 task
@uvtc
Copy link
Contributor

uvtc commented May 25, 2020

Any guess as to what release this will land in?

@uvtc
Copy link
Contributor

uvtc commented May 25, 2020

@codingthat
Copy link

Just curious, are these still to do, or just didn't get checked off formally?
image

@nadako
Copy link
Member Author

nadako commented Jun 2, 2020

Still kinda to do. For the "display stuff" there are separate issues now, rtti and access controls are... also waiting for specific issues :)

AlexHaxe added a commit to AlexHaxe/haxeparser that referenced this pull request Jun 27, 2020
Simn pushed a commit to HaxeCheckstyle/haxeparser that referenced this pull request Jun 27, 2020
* support metadata in var declaration syntax HaxeFoundation/haxe#9618

* print arrow functions correctly in haxe.macro.Printer HaxeFoundation/haxe#9151

* Module-level static declarations HaxeFoundation/haxe#8460

* [parser] allow `function` as package name HaxeFoundation/haxe#7697

* compatibility with Haxe 4.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants