Skip to content

Conversation

@zawaza-blog
Copy link

This implementation uses the GNU Modula2 compiler and it runs all sets and test suites. Dockerfile is availabe for systems without a gm2 compiler.

The implemention was harder than I expected. I worked with modula-2 twice in my early jobs. And I have fond memories of it. This work has also served as a reminder of those early days when everything was yet to be built, and we reinvented the wheel continously.

Summary

  • All steps implemented, Pass all tests.
  • Do not use modula2 ALLOCATE, details below.
  • Do not have a garbage collector.

GM2 Compiler

Having a GM2 compiler was the key enabler of this implementation, furthermore it includes the PIM and ISO libraries.

I realized there was a modula-2 compiler two years ago, despite it have been available for more than ten years. Knowing the compiler was available, the only remaining challenge was finding enough time to dedicate to the project.

GM2 ALLOCATE/NEW

50% of the project was fighting with the ALLOCATE/NEW to reserve memory. It's slow. ALLOCATE / NEW also tracks every reserved object in a list. Some of the steps make heavy use of dynamic memory, and the ALLOCATE is really slow due to the objet tracking management. By step 5 i give up, and started using malloc. It was soo slow that the TCO test timeout despite the tail call optimization was workin was working..

Garbage collector

I intend to implement a Garbage Collector (Mark-and-Sweep or Cheney-style copying), if I can allocate additional time.

Run Suite

$ make "docker-build^modula2"
$ make DOCKERIZE=1 "test^modula2"

Thanks

Obviously this implementation wasn't posible without the work of Niklaus Wirth and Gaius Mulley.

Pull request requirements:

  • Commits are well written and well organized.
  • Commits for a specific implementation should be prefixed with
    the implementation name.
  • Github Actions CI passes all checks (including self-host)

Additional requirements if you are adding a new implementation (see FAQ for details):

  • Follow incremental structure (no common eval code)
  • Add impls/<IMPL>/Dockerfile
  • Add impls/<IMPL>/Makefile
  • Update IMPLS.yml
  • Update Makefile.impls
  • Update README.md
This implementation uses the GNU Modula2 compiler and
it runs all sets and test suites. Dockerfile is availabe for systems without a gm2 compiler.

The implemention was harder than I expected. I worked with modula-2 twice in my early jobs.
And I have fond memories of it. This work has also served as a reminder of those early days
when everything was yet to be built, and we reinvented the wheel continously.

Summary
-------

* All steps implemented, Pass all tests.
* Do not use modula2 ALLOCATE, details below.
* Do not have a garbage collector.

GM2 Compiler
------------
Having a GM2 compiler was the key enabler of this implementation, furthermore it includes the PIM and ISO libraries.

I realized there was a modula-2 compiler two years ago, despite it have been available for more than ten years.
Knowing the compiler was available, the only remaining challenge was finding enough time to dedicate to the project.

GM2 ALLOCATE/NEW
----------------
50% of the project was fighting with the ALLOCATE/NEW to reserve memory. It's slow.
ALLOCATE / NEW also tracks every reserved object in a list. Some of the steps make heavy use of dynamic memory, and the
ALLOCATE is really slow due to the objet tracking management. By step 5 i give up, and started using malloc.
It was soo slow that the TCO test timeout despite the tail call optimization was workin was working..

Garbage collector
-----------------
I intend to implement a Garbage Collector (Mark-and-Sweep or Cheney-style copying), if I can allocate additional time.

Run Suite
---------
$ make "docker-build^modula2"
$ make DOCKERIZE=1 "test^modula2"

Thanks
------
Obviously this implementation wasn't posible without the work of Niklaus Wirth and Gaius Mulley.
@kanaka
Copy link
Owner

kanaka commented Jan 5, 2026

Hi @zawaza-blog. Sorry for the slow reply (work, travel, holidays, etc). Can you please add your implementation to IMPLS.yml so that the automated CI will activate?

- step2. input/output error.
- stepA. EVAL checked HasError() but not HasException() in recursive calls, throw  didn't stop evaluation.
@zawaza-blog
Copy link
Author

Hi @kanaka I'm really grateful you have find time to look to the pull requests.

The modula2 implementation has been added to IMPLS.yml, and the issues triggered in the self-hosted CI had been solved.

Copy link
Owner

@kanaka kanaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zawaza-blog Looks good. One inline comment that needs to be fixed before I merge it.

impls/mal/run Outdated
MAL_FILE="../mal/stepA_mal.mal ${MAL_FILE}" ;;
esac
exec ./../${MAL_IMPL:-js}/run ${MAL_FILE} "${@}"
exec ./../${MAL_IMPL:-modula2}/run ${MAL_FILE} "${@}"
Copy link
Owner

@kanaka kanaka Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you accidentally changed the mal run script to use modula2 by default. You shouldn't need to do this. If you run make MAL_IMPL=modula2 test^mal that should run the tests is self-host mode using the modula2 implementation as the host implementation. The "js" here is just the fallback if you don't specify MAL_IMPL.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ops. Sorry. default MAL_IMPL has been reverted to "js".

Thanks again for your time and dedication. 😃

@kanaka
Copy link
Owner

kanaka commented Jan 22, 2026

Hi @zawaza-blog. I'm requesting a couple more changes after reviewing the code in more detail:

  • Remove the debug at the end of step5
  • Use the current approach in the guide for how to handle macroexpand. This implementation is currently using the prior more complicated approach that has a separate macroexpand function/phase. The current approach integrates macroexpansion into the EVAL function in a more simple way.
@zawaza-blog
Copy link
Author

Of course 😃, I will try to find some time to align steps 8 and 9 with the current approach of macroexpansion.

- step8, step9 & stepA
  * Removed the early macro expansion in eval.
  * Changes to function application.
    - First evaluate only the first element. Shall be a function.
    - If function^.isMacro, apply it to unevaled arguments and update ast.
    - Else evaluate remaining ast and apply the function.

- Removed the env & cache debug at the end of step5
@zawaza-blog
Copy link
Author

Finally, I found spare time to implement the macroexpand current approach. It was fun. 😄

Changes done

  • Removed the env & cache debug at the end of step5
  • step8, step9 & stepA
    * Removed the early macro expansion in eval.
    * Changes to function application.
    - First evaluate only the first element. Shall be a function.
    - If function^.isMacro, apply it to unevaled arguments and update ast.
    - Else evaluate remaining ast and apply the function.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants