dev
dev copied to clipboard
Function Syntax RFC
Goal
- Concise syntax for SCM functions
- Make SCM functions easier to use by hiding some low-level details
Considerations for function syntax
Pascal-style:
function a12(name: string): string
- easier to find using a "function" keyword
- param declaration is consistent with the "var" block syntax
~~#### C-style:~~
string a12(string name)
~~* consistent with inline var declaration~~
Pascal-style is more consistent with the rest of the language.
Rules
-
~~Function must be declared before first usage~~ Function are available anywhere within current scope. Functions defined inside other functions are available anywhere in that function body
-
Function body starts with the "function" keyword followed by the function signature.
-
Function name ~~prefixed with @~~ is a valid label
-
The signature includes input parameters (if any) and their types, comma-separated.
-
Input parameters, when present, must be enclosed in "()". For zero-input functions "()" is optional
-
Input parameters are followed by a return type if the function returns anything
-
Multiple return types are comma-separated, ~~and parenthesized.~~
-
Return type(s) can be prefixed with the
optional
keyword. Function with an optional result may return nothing. -
Function body ends with the
end
keyword. -
return
keyword immediately exits the function and returns control to the calling code. See Return Semantics- functions with optional return type(s) can use blank
return
to bail out immediately while returning nothing - There is special
logical
return type. This result can only be validated in IF..THEN and can not be stored in a variable. Logical function returns true or false. - functions that define return type(s) must return same number of values. logical function must return a condition flag. Optional functions may return nothing.
- When you return with some value(s), it is always a true condition for IF..THEN. Empty return is always a false condition. Value returned from a logical function defines the condition.
- functions with optional return type(s) can use blank
-
~~Function can return one or more values using the following syntax:
return <condition flag> <value1> <value2> ....
~~ -
~~
return
keyword in functions should not be confused withreturn
keyword in gosubs. Function's return is always followed by some values, ortrue
, orfalse
using CLEO5's CLEO_RETURN_WITH~~ -
end
keywords serves as an implicitreturn
~~with the default values matching the function signature~~ ~~using RETURN (CLEO5 is required)~~ using CLEO_RETURN -
~~
return false
is a special case that can be used in any function. It sets the condition result to false and exits the function ignoring all output variables~~ -
~~
return true
is a special case that can be used in function with no return type. It sets the condition result to true.~~
Examples
Declaration
- Function name serves as a label. it can not duplicate an existing label.
- Functions can be declared upfront to allow calls be located before the function body (forward declarations, see below)
- "end" represents ~~
CLEO_RETURN_FAIL
~~ ~~RETURN
~~CLEO_RETURN 0
~~if there no an explicitcleo_return_*
on the preceding line~~
{$CLEO}
function a0
end // implicit CLEO_RETURN 0
function a1(x: int)
end // implicit CLEO_RETURN 0
function a2(x: int, y: int)
end // implicit CLEO_RETURN 0
function a3(): int
end // implicit CLEO_RETURN 0
function a4(): int, int
end // implicit CLEO_RETURN 0
function a5(): int
return 42 // explicit cleo_return_with true 42
end // implicit CLEO_RETURN 0
function a6(): int, int
return 42 84 // explicit cleo_return_with true 42 84
end // implicit CLEO_RETURN 0
function a7(): int
if 0@>0
then
return 42 // explicit cleo_return_with true 42
end
end // implicit CLEO_RETURN 0
function a8()
if 0@>0
then
return // explicit 0051: return
end
end // implicit CLEO_RETURN 0
function a9(): logical
return false // explicit cleo_return_with false
end // implicit CLEO_RETURN 0
function a10(): float
if 0@>0
then
return 42.0 // explicit cleo_return_with true 42.0
end
end // implicit CLEO_RETURN 0
function a11(): string
if 0@>0
then
return 'test' // explicit cleo_return_with true 'test'
end
end // implicit CLEO_RETURN 0
function a12(name: string): string
return name // explicit cleo_return_with true 0@ 1@
end // implicit CLEO_RETURN 0
function a14(): int
if 0@>0
then return 1 // cleo_return_with true 1
else return 0 // cleo_return_with true 0
end
end // implicit CLEO_RETURN 0
function a15(): int, float
if 0@>0
then return 1 2.0 // cleo_return_with true 1 2.0
else return 0 0 // cleo_return_with true 0 0
end
end // implicit CLEO_RETURN 0
Examples of logical/optional return types
function no_ret_ok
return
end
function no_ret_error
// return 1 // error, should not return a value
end
function ret_logical_ok: logical
return 1
return 0
return 0@ == 0
end
function ret_logical_error: logical
// return // error, should return 1 value
// return 1 2 // error, should return 1 value
end
function ret_1_ok: int
return 0
end
function ret_1_error: int
// return // error, should return 1 value
// return 1 2 // error, should return 1 value
end
function ret_2_ok: int, int
return 0 0
end
function ret_2_error: int, int
// return // error, should return 2 integer values
// return 1 // error, should return 2 integer values
end
function opt_1_ok: optional int
return
return 0
end
function opt_1_error: optional int
// return 1 2 // error, should return 1 integer value
end
function opt_2_ok: optional int, int
return
return 1 2
end
function opt_2_error: optional int, int
// return 1 // error, should return 2 integer values
// return 1 2 3 // error, should return 2 integer values
end
if and
ret_logical_ok()
0@ = ret_1_ok()
0@, 1@ = ret_2_ok()
0@ = opt_1_ok()
0@, 1@ = opt_2_ok()
then
// ok
else
// error
end
Calling functions
a0() // ambiguous: gosub or call?, need lookahead
a1(5) // cleo_call a1 1 5
a2(5,6) // cleo_call a2 2 5 6
// single result
0@ = a3() // cleo_call a3 0 0@
// multiple results
0@, 1@ = a4() // cleo_call a4 0 0@ 1@
// use functions in initialization position
int x = a3() // cleo_call a3 0 0@
string name = a12("test") // cleo_call a12 1 "test" 0@ 1@
// logical functions
if a9()
then
...
end
Grammar
function := ["export" whitespace] "function" whitespace identifier "(" params ")" ( return_type1 | return_type2)
params := [ identifier ":" type ] [ "," params ]
return_type1 := [ "(" ] type [ ")" ]
return_type2 := "(" type "," types ")"
types := type [ "," types ]
var1 := [ "(" ] var [ ")" ]
var2 := "(" var "," vars ")"
vars := var [ "," vars ]
function_call := [ ( var1 | var2 ) "=" ] identifier "(" args ")"
args := ( var | const ) [ "," args ]