Skip to content

RFC: Compiler improvements - #373

Merged
jow- merged 2 commits into
ucode-lang:masterfrom
nbd168:compiler-improvements
Apr 6, 2026
Merged

jow- merged 2 commits into
ucode-lang:masterfrom
nbd168:compiler-improvements

Conversation

@nbd168

@nbd168 nbd168 commented Feb 11, 2026 •

Copy link
Copy Markdown
Contributor

Bring ucode closer to ECMAScript:

  1. allow export function without trailing semicolon
  2. add explicit function declaration syntax

@nbd168
nbd168 force-pushed the compiler-improvements branch 3 times, most recently from 26bd062 to 72f85f9 Compare February 11, 2026 08:45
@jow-

jow- commented Feb 11, 2026 •

Copy link
Copy Markdown
Collaborator

Export without trailing semicolon is fine, makes sense.

About the hoisting support; personally I am no fan of hoisting at all, it is confusing and counterintuitive and, as you've noticed with the compiler implementation, makes single-pass compilation impossible and requires juggling and swapping states.

I do agree that function hoisting for enabling mutual recursion is fine but things like

let x = foo();

function foo() {

}

Just do not feel right (yes I know it is established practise in JS / ECMA Script).
What I was considering the past is simple function forward declarations:

function foo;
let x = foo();

function foo() {

}

function is_odd;
function is_even(n) { return n == 0 ? true : is_odd(n - 1); }
function is_odd(n) { return n == 0 ? false : is_even(n - 1); }

print(is_even(4), "\n");
print(is_odd(3), "\n");

It is slightly more verbose but simplifies compiler implementation a lot and clearly communicates intent.

@nbd168

nbd168 commented Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

Fair enough. So function foo; as an alternative for the currently used let foo; variant except with enforced function type, right? I can look into that.

@jow-

jow- commented Feb 11, 2026 •

Copy link
Copy Markdown
Collaborator

Yes, a not fully fleshed out proposal is:

  • function foo; reserves a slot and constrains foo to function type
  • treat as constant: function foo; foo = function() {} -> Syntax error: Invalid assignment to constant 'foo'
  • attempts to redeclare foo result in a syntax error: function foo; let foo = 1; => Syntax error: Function 'foo' redeclared as different kind of symbol or Syntax error: Function 'foo' redeclared
  • a function stub (forward declaration) might only be declared once:
    • function foo; function foo() {} -> okay
    • function foo; function foo() {}; function foo() {} -> Syntax error: Function 'foo' redeclared
  • multiple forward declarations: undecided. If we treat it like let and const, it would be disallowed (let x; let x; -> Syntax error: Variable 'x' redeclared), but given that function prototypes have special semantics it might make sense to allow multiple ones (function foo; function foo; function foo() {}), to also mimic the behavior of C somewhat
  • forward declaration after actual declaration: depends on what is decided for the previous point. Gut feeling would be to disallow (function foo() {}; function foo; -> Syntax error: Function 'foo' redeclared) but it would probably negatively impact the usefulness of forward declarations as "safe way" to mark an identifer as callable value implemented somewhere
  • Call on forward declaration never fully declared -> runtime error Type error: left-hand side is not a function like let foo; foo();

Like ECMAScript, treat `export function foo() {}` as a complete
statement that does not require a trailing semicolon.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
Add `function foo;` as a forward declaration that reserves a constant
slot (initialized to null), later filled by a matching `function foo() {}`
definition. This enables mutual recursion between functions at the same
scope level without the `let foo; foo = function() {};` workaround.

Forward-declared bindings are constant, preventing reassignment and
redeclaration. Duplicate forward declarations, forward declarations
after definitions, and unfilled stubs called at runtime are all handled
with appropriate error messages.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
@nbd168
nbd168 force-pushed the compiler-improvements branch from 72f85f9 to d9e24e4 Compare February 11, 2026 17:50
@nbd168

nbd168 commented Feb 13, 2026

Copy link
Copy Markdown
Contributor Author

Does this look like what you wanted?

@jow-

jow- commented Feb 13, 2026

Copy link
Copy Markdown
Collaborator

Yes! I hope to merge it during the weekend, on a first glance it looks really good.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Perhaps an additional test-case. This might imply that a semicolon is now wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

extra semicolons are always harmless - they're just empty statements.

@jow-
jow- merged commit f453e19 into ucode-lang:master Apr 6, 2026
2 checks passed
@jow-

jow- commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

Merged now, sorry for the delay.

@nbd168
nbd168 deleted the compiler-improvements branch June 3, 2026 10:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants