diff --git a/civet.dev/cheatsheet.md b/civet.dev/cheatsheet.md
index ecdab409..062f2282 100644
--- a/civet.dev/cheatsheet.md
+++ b/civet.dev/cheatsheet.md
@@ -403,7 +403,14 @@ you can prepare it ahead of time using `return.value`
Using this feature disables implicit `return` for that function.
-function search(list)
+function sum(list: number[])
+ return .= 0
+ for item of list
+ return += item
+
+
+
+function search(list: T[]): T | undefined
return unless list
for item of list
if match item
@@ -412,14 +419,6 @@ function search(list)
list.destroy()
-
-function search(list: T[], pred: (T) => boolean)
- let return: number | undefined
- if list
- return = list.findIndex pred
- list.splice return.value, 1
-
-
### Single-Argument Function Shorthand
diff --git a/source/parser.hera b/source/parser.hera
index 21860572..5055202d 100644
--- a/source/parser.hera
+++ b/source/parser.hera
@@ -312,7 +312,7 @@ ArrowFunctionTail
return {
type: "ArrowFunction",
parameters,
- returnType: suffix?.children?.[1]?.[0]?.[1]?.token,
+ returnType: suffix,
ts: false,
block: expOrBlock,
children: $0,
@@ -1331,7 +1331,7 @@ FunctionSignature
type: "FunctionSignature",
id: wid?.[1],
parameters,
- returnType: suffix?.children?.[1]?.[0]?.[1]?.token,
+ returnType: suffix,
ts: false,
block: null,
children: !parameters.implicit ? $0 :
@@ -1425,7 +1425,7 @@ OperatorSignature
type: "FunctionSignature",
id,
parameters,
- returnType: suffix?.children?.[1]?.[0]?.[1]?.token,
+ returnType: suffix,
ts: false,
block: null,
children: [ func, w1, id, w2, parameters, suffix ],
@@ -1469,7 +1469,7 @@ ThinArrowFunction
type: "FunctionExpression",
id: undefined,
parameters,
- returnType: suffix?.children?.[1]?.[0]?.[1]?.token,
+ returnType: suffix,
ts: false,
block: block,
children: [
@@ -2272,7 +2272,7 @@ MethodSignature
name: name,
modifier: $1?.[0]?.token, // get/set
// TODO: get return type from type annotation
- returnType: undefined,
+ returnType: suffix,
parameters,
}
@@ -5273,21 +5273,31 @@ TypeSuffix
}
ReturnTypeSuffix
- __ Colon ( __ "asserts" NonIdContinue )? TypePredicate ->
- const children = [...$1, $2]
- if ($3) children./**/push($3)
- children./**/push($4)
+ __ Colon ( __ "asserts" NonIdContinue )?:asserts TypePredicate:t ->
+ if (asserts) {
+ t = {
+ type: "AssertsType",
+ t,
+ children: [asserts[0], asserts[1], t],
+ }
+ }
return {
type: "ReturnTypeAnnotation",
- children,
+ children: [$1, $2, t],
+ t,
ts: true,
}
TypePredicate
- Type ( __ "is" NonIdContinue Type )? ->
- if (!$2) return $1
- return $0
+ Type:lhs ( __ "is" NonIdContinue Type )?:rhs ->
+ if (!rhs) return lhs
+ return {
+ type: "TypePredicate",
+ lhs,
+ rhs: rhs[3],
+ children: [lhs, ...rhs],
+ }
Type
TypeConditional
@@ -5299,6 +5309,7 @@ TypeBinary
TypeUnary
( __ TypeUnaryOp NonIdContinue )* TypePrimary TypeUnarySuffix* ->
+ if (!$1.length && !$3.length) return $2
return [...$1, $2, ...$3]
TypeUnarySuffix
@@ -5320,8 +5331,19 @@ TypePrimary
_? InlineInterfaceLiteral
_? TypeTuple
_? ImportType
- _? TypeLiteral
- _? IdentifierName (Dot IdentifierName)* TypeArguments?
+ _? TypeLiteral:t ->
+ return {
+ type: "LiteralType",
+ t,
+ children: $0,
+ }
+ _? IdentifierName (Dot IdentifierName)* TypeArguments?:args ->
+ return {
+ type: "IdentifierType",
+ children: $0,
+ raw: [$2.name, ...$3.map(([dot, id]) => dot.token + id.name), ].join(''),
+ args,
+ }
# NOTE: Check FunctionType before parenthesized in order to distinguish between (a: T) => U and
# A parenthesized inline interface (a: T) ---> ({a: T})
# NOTE: Check Type before ( EOS Type ) to find implicit nested interfaces first. EOS would swallow the
@@ -5360,7 +5382,7 @@ TypeLiteral
# interpolated strings get checked first before StringLiteral.
Literal
"void" NonIdContinue ->
- return { $loc, token: "void" }
+ return { type: "VoidType", $loc, token: $1 }
"[]" ->
return { $loc, token: "[]" }
@@ -7014,7 +7036,8 @@ Init
// Support for `return.value` and `return =`
// for changing automatic return value of function.
// Returns whether any present (so shouldn't do implicit return).
- function processReturnValue(block) {
+ function processReturnValue(func) {
+ const {block} = func
const values = gatherRecursiveWithinFunction(block,
({type}) => type === "ReturnValue")
if (!values.length) return false
@@ -7038,11 +7061,18 @@ Init
// Add declaration of return.value after {
if (!declared) {
+ let returnType = func.returnType ?? func.signature?.returnType
+ if (returnType) {
+ const {t} = returnType
+ if (t.type === "AssertsType" || t.type === "TypePredicate") {
+ returnType = undefined
+ }
+ }
block.expressions.unshift([
getIndent(block.expressions[0]),
{
type: "Declaration",
- children: ["let ", ref, ";\n"],
+ children: ["let ", ref, returnType, ";\n"],
names: [],
}
])
@@ -7071,13 +7101,17 @@ Init
return true
}
+ function isVoidType(t) {
+ return t?.type === "LiteralType" && t.t.type === "VoidType"
+ }
+
function processFunctions(statements) {
gatherRecursiveAll(statements, ({type}) => type === "FunctionExpression" || type === "ArrowFunction")
.forEach((f) => {
processParams(f)
- const { block, returnType } = f
- if (!processReturnValue(block) && module.config.implicitReturns) {
- const isVoid = returnType === "void"
+ if (!processReturnValue(f) && module.config.implicitReturns) {
+ const { block, returnType } = f
+ const isVoid = isVoidType(returnType?.t)
const isBlock = block?.type === "BlockStatement"
if (!isVoid && isBlock) {
insertReturn(block)
@@ -7088,10 +7122,10 @@ Init
gatherRecursiveAll(statements, ({type}) => type === "MethodDefinition")
.forEach((f) => {
processParams(f)
- const {signature, block} = f
- if (!processReturnValue(block) && module.config.implicitReturns) {
+ if (!processReturnValue(f) && module.config.implicitReturns) {
+ const {signature, block} = f
const isConstructor = signature.name === "constructor"
- const isVoid = signature.returnType === "void"
+ const isVoid = isVoidType(signature.returnType?.t)
const isSet = signature.modifier === "set"
if (!isConstructor && !isSet && !isVoid) {
diff --git a/test/function.civet b/test/function.civet
index acbd83d2..df54115d 100644
--- a/test/function.civet
+++ b/test/function.civet
@@ -1451,6 +1451,75 @@ describe "function", ->
}
"""
+ testCase """
+ return.value typed by function
+ ---
+ function f: number
+ return = 5
+ ---
+ function f(): number {
+ let ret: number;
+ ret = 5
+ return ret
+ }
+ """
+
+ testCase """
+ return.value typed by arrow function
+ ---
+ (): number =>
+ return = 5
+ ---
+ (): number => {
+ let ret: number;
+ ret = 5
+ return ret
+ }
+ """
+
+ testCase """
+ return.value typed by method
+ ---
+ {
+ f(): number
+ return = 5
+ }
+ ---
+ ({
+ f(): number {
+ let ret: number;
+ ret = 5
+ return ret
+ }
+ })
+ """
+
+ testCase """
+ return.value not typed for asserts
+ ---
+ function f(x): asserts x is number
+ return = false
+ ---
+ function f(x): asserts x is number {
+ let ret;
+ ret = false
+ return ret
+ }
+ """
+
+ testCase """
+ return.value not typed for is
+ ---
+ function f(x): x is number
+ return = false
+ ---
+ function f(x): x is number {
+ let ret;
+ ret = false
+ return ret
+ }
+ """
+
testCase.skip """
return.value parameter
---