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

[Feature request] Ternary operator #621

Open
Rangi42 opened this issue Dec 9, 2020 · 11 comments
Open

[Feature request] Ternary operator #621

Rangi42 opened this issue Dec 9, 2020 · 11 comments
Labels
enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM rgblink This affects RGBLINK

Comments

@Rangi42
Copy link
Contributor

Rangi42 commented Dec 9, 2020

This would be mostly useful for within user-defined functions (#201), but would also be more terse than the current if/else/endc.

Example:

giveitem: MACRO
	db giveitem_command
	db \1 ; item
if _NARG == 2
	db \2 ; quantity
else
	db 1 ; quantity
endc
ENDM

; simplifies to

giveitem: MACRO
	db giveitem_command
	db \1 ; item
	db _NARG == 2 ? \2 : 1 ; quantity
ENDM
growth_rate: MACRO
; [1]/[2]*n**3 + [3]*n**2 + [4]*n - [5]
	dn \1, \2
	if \3 & $80 ; signed
		db -\3 | $80
	else
		db \3
	endc
	db \4, \5
ENDM

; simplifies to

growth_rate: MACRO
; [1]/[2]*n**3 + [3]*n**2 + [4]*n - [5]
	dn \1, \2
	db \3 & $80 ? -\3 | $80 : \3 ; signed
	db \4, \5
ENDM
@ISSOtm
Copy link
Member

ISSOtm commented Dec 9, 2020

Might as well make it short-circuiting too (#619).

@ISSOtm ISSOtm added enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM rgblink This affects RGBLINK labels Dec 10, 2020
@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 21, 2020

Lazy evaluation would make this more useful, but it's worth adding even before then. For example, this:

growth_rate: MACRO
; [1]/[2]*n**3 + [3]*n**2 + [4]*n - [5]
	dn \1, \2
	if \3 < 0 ; two's complement -> signed magnitude
		db -\3 | $80
	else
		db \3
	endc
	db \4, \5
ENDM

would become:

growth_rate: MACRO
; [1]/[2]*n**3 + [3]*n**2 + [4]*n - [5]
	dn \1, \2
	db \3 < 0 ? -\3 | $80 : \3 ; two's complement -> signed magnitude
	db \4, \5
ENDM

@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 21, 2020

Also note that to be consistent with other operators, including mere parentheses, this should turn strings into numbers. Which would disallow things like PRINTT \1 > 1 ? "items" : "item".

@ISSOtm
Copy link
Member

ISSOtm commented Dec 21, 2020

Well, RGBASM is actually very strongly typed, with expression syntax depending on the expected type, so the ternary operator could be separately implemented for strings.

@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 21, 2020

True, but should it? And if so/regardless, should T_LPAREN relocexpr T_RPAREN be split into two cases for numbers and strings? (It feels wrong to me that just parenthesizing an expression should change its meaning.) AFAIK all the other cases (+x, -x, x & y, HIGH(x), etc) are fine with the coercion to number with str2int2.

@aaaaaa123456789
Copy link
Member

Well, RGBASM is actually very strongly typed, with expression syntax depending on the expected type, so the ternary operator could be separately implemented for strings.

Is it? db "a" is ambiguous.

@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 21, 2020

db, dw, and dl are special-cased for strings (see parser.y).

@Rangi42
Copy link
Contributor Author

Rangi42 commented Feb 1, 2021

The Pasmo assembler also has a ?: ternary operator; it and the && and || logical operators are short-circuited.

@Rangi42 Rangi42 modified the milestones: v0.5.0, v1.0.0 Feb 28, 2021
@ISSOtm ISSOtm modified the milestones: v1.0.0, v0.5.1 Mar 5, 2021
@Rangi42
Copy link
Contributor Author

Rangi42 commented Apr 2, 2021

Another use case for ternary operators without waiting for lazy evaluation (even if they end up both being added in the same release): pokecrystal16's code-generating macros (a bad idea for small patterns, but necessary for cases like this).

		srl h
		; if HIGH(\1) is even, srl h is correct; otherwise, we have to invert it. Since we can't conditionally include a
		; ccf instruction (as it would create a circular dependency between assembler and linker), we have no choice but
		; to execute a ccf on odd HIGH(\1) and a nop on even HIGH(\1) by inserting the correct instruction dynamically
		; using a db. Note that ccf = $3F and nop = $00.
		db (HIGH(\1) & 1) * $3F

This would be clearer as:

		srl h
		db HIGH(\1) & 1 ? $3F : $00

Also:

		bit 0, h
		; if HIGH(\1EntriesEnd) is odd, we jump on z; otherwise, we jump on nz
		; so we have to encode a "jr z/nz, .search_loop" instruction according to that value - jr z = $28, jr nz = $20
		db 8 * (HIGH(\1EntriesEnd) & 1) + $20
		db .search_loop - (@ + 1)
		bit 0, h
		db HIGH(\1EntriesEnd) & 1 ? $28 : $20
		db .search_loop - (@ + 1)

@Rangi42 Rangi42 modified the milestones: v0.5.1, v0.6.0 Apr 25, 2021
@Rangi42
Copy link
Contributor Author

Rangi42 commented Jan 4, 2023

@ISSOtm's https://github.com/ISSOtm/rsgbds rewrite will make it more feasible to add a short-circuiting ternary operator. We're considering the syntax for it.

  1. cond ? foo : bar: Traditional terse C-style syntax, and very common throughout other languages, but might be problematic given rgbasm's other uses for :.
    • This works without any parser conflicts, but would make :- in cond?foo:-foo lex surprisingly as an anonymous label.
  2. if cond then foo else bar: Keyword syntax; self-explanatory and used in some other languages, but would be problematic if someone does continued if cond \ then foo \ else bar, particularly within an if/else block. The same issue applies to other use of inline if or else, e.g.:
    a. cond if foo else bar
    b. cond then foo else bar
    c. cond when foo else bar
  3. foo if cond else bar: Python-style; rejected due to unusual order of arguments, and the above lexing issue.
  4. cond ?? foo !! bar: Raku-style syntax; unusual (unique actually) but not ambiguous, and ! naturally pairs with ?.
    • This works without any parser conflicts, but would make !! lex as its own token, so it has to also work as a "not-not" unary operator.
  5. ifelse(cond, foo, bar): Built-in function-style; kind of like Lisp (if cond foo bar), Fortran merge(foo, bar, cond), or Visual Basic iif(cond, foo, bar), but would need lazy evaluation for its foo and bar arguments to be short-circuiting, which is unusual (though def(name) also has special evaluation of its argument).
  6. select(expr, 0 => foo, 1 => bar): More general function-style syntax (as opposed to chaining multiple ternaries).

Wikipedia may have more ideas.

(Note that short-circuiting cond && foo || bar works without needing a ternary operator, but not when foo is 0.)

(My personal vote is for 4 (?? !!), or 1 (? :) unless there's already a difficulty with lexing/parsing/evaluating a :. Those would even let us have a shorthand Elvis operator for x ? x : y, as x ?: y or x ?! y.)

@ISSOtm
Copy link
Member

ISSOtm commented Jan 7, 2023

I think ? : shouldn't be a problem... hopefully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM rgblink This affects RGBLINK
Projects
None yet
Development

No branches or pull requests

3 participants