Skip to content

Commit

Permalink
Redeclarations in list assignments (#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
vtereshkov committed Dec 25, 2023
1 parent c47cdb1 commit d212887
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 7 deletions.
2 changes: 2 additions & 0 deletions doc/lang.md
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,8 @@ a := 5
s, val := "Hello", sin(0.1 * a)
```

A short variable declaration may redeclare variables provided they were originally declared earlier in the same block and at least one of the variables in the left-hand side list is new.

### Function and method declarations

A function or method declaration can be either a complete definition that includes the function block, or a *prototype* declaration if the function block is omitted. A prototype should be resolved somewhere below in the same module by duplicating the declaration, now with the function block. If a prototype is not resolved, it is considered an external C/C++ function. If such a function has not been registered via the Umka API, it is searched in the shared library (Umka module implementation library, UMI) `mod.umi`, where `mod` is the current module name. If the UMI does not exist or contains no such function, an error is triggered.
Expand Down
2 changes: 1 addition & 1 deletion playground/umka.js

Large diffs are not rendered by default.

48 changes: 42 additions & 6 deletions src/umka_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static void parseListAssignmentStmt(Compiler *comp, Type *type, Const *varPtrCon
doImplicitTypeConv(comp, leftType, &rightType, &rightConstantBuf, false);
typeAssertCompatible(&comp->types, leftType, rightType, false);

constAssign(&comp->consts, varPtrConstList[i].ptrVal, &rightConstantBuf, rightType->kind, typeSize(&comp->types, rightType));
constAssign(&comp->consts, varPtrConstList[i].ptrVal, &rightConstantBuf, leftType->kind, typeSize(&comp->types, leftType));
}
else // Assign to variable
{
Expand Down Expand Up @@ -313,32 +313,68 @@ static void parseListDeclAssignmentStmt(Compiler *comp, IdentName *names, bool *
if (numExpr != num)
comp->error.handler(comp->error.context, "%d expressions expected but %d found", num, numExpr);

bool newVarFound = false;

for (int i = 0; i < num; i++)
{
Type *rightType = rightListType->field[i]->type;
Ident *ident = identAllocVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, names[i], rightType, exported[i]);

bool redecl = false;
Ident *ident = identFind(&comp->idents, &comp->modules, &comp->blocks, comp->blocks.module, names[i], NULL, false);
if (ident && ident->kind == IDENT_VAR && ident->block == comp->blocks.item[comp->blocks.top].block)
{
// Redeclaration in the same block
redecl = true;
ident->used = true;
}
else
{
// New variable
newVarFound = true;
ident = identAllocVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, names[i], rightType, exported[i]);
}

if (constExpr) // Initialize global variable
{
Const rightConstantBuf = {.ptrVal = (char *)rightListConstant->ptrVal + rightListType->field[i]->offset};
constDeref(&comp->consts, &rightConstantBuf, rightType->kind);
constAssign(&comp->consts, ident->ptr, &rightConstantBuf, rightType->kind, typeSize(&comp->types, rightType));

if (redecl)
{
doImplicitTypeConv(comp, ident->type, &rightType, &rightConstantBuf, false);
typeAssertCompatible(&comp->types, ident->type, rightType, false);
}

constAssign(&comp->consts, ident->ptr, &rightConstantBuf, ident->type->kind, typeSize(&comp->types, ident->type));
}
else // Assign to variable
{
genDup(&comp->gen); // Duplicate expression list pointer
genGetFieldPtr(&comp->gen, rightListType->field[i]->offset); // Get expression pointer
genDeref(&comp->gen, rightType->kind); // Get expression value

genChangeRefCnt(&comp->gen, TOK_PLUSPLUS, rightType); // Increase right-hand side reference count
if (redecl)
{
doImplicitTypeConv(comp, ident->type, &rightType, NULL, false);
typeAssertCompatible(&comp->types, ident->type, rightType, false);

doPushVarPtr(comp, ident);
genSwapAssign(&comp->gen, rightType->kind, typeSize(&comp->types, rightType));
doPushVarPtr(comp, ident);
genSwapChangeRefCntAssign(&comp->gen, ident->type); // Assign expression to variable - both left-hand and right-hand side reference counts modified
}
else
{
genChangeRefCnt(&comp->gen, TOK_PLUSPLUS, rightType); // Increase right-hand side reference count
doPushVarPtr(comp, ident);
genSwapAssign(&comp->gen, ident->type->kind, typeSize(&comp->types, ident->type)); // Assign expression to variable
}
}
}

if (!constExpr)
genPop(&comp->gen); // Remove expression list pointer

if (!newVarFound)
comp->error.handler(comp->error.context, "No new variables declared");
}


Expand Down
2 changes: 2 additions & 0 deletions tests/all.um
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"untypedlit.um"
"ternary.um"
"typeswitch.um"
"redecl.um"
)

fn main() {
Expand Down Expand Up @@ -80,4 +81,5 @@ fn main() {
printf("\n\n>>> Untyped literals\n\n"); untypedlit.test()
printf("\n\n>>> Ternary operator\n\n"); ternary.test()
printf("\n\n>>> Type switches\n\n"); typeswitch.test()
printf("\n\n>>> Redeclarations\n\n"); redecl.test()
}
9 changes: 9 additions & 0 deletions tests/expected.log
Original file line number Diff line number Diff line change
Expand Up @@ -689,3 +689,12 @@ str: 425 + 5 = 4255
[]real: [42 5] + [5] = [42 5 5]
unknown: 42



>>> Redeclarations

f(): 42 "OK!" true
g(): 43 "FAIL!" false
f(): 42 "OK!" true
"Merry Christmas!" true [5 7] 0.333
"Merry Christmas!" false [5 7] 144 "Hmmm"
Expand Down
39 changes: 39 additions & 0 deletions tests/redecl.um
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
excl := "!"

fn f(): (int, str, bool) {
return 42, "OK" + excl, true
}

fn g(): (int, str, bool) {
return 43, "FAIL" + excl, false
}

fn test1*() {
res, err, ok := f()
printf("f(): %v %v %v\n", res, err, ok)

res, err, ok = g()
printf("g(): %v %v %v\n", res, err, ok)

res2, err, ok := f()
printf("f(): %v %v %v\n", res2, err, ok)
}

a, b, c := "Hello " + "World!", true, [2]int{11, 13}
a, d, c := "Merry " + "Christmas!", 0.333, [2]int{5, 7}

fn test2*() {
printf("%v %v %v %v\n", a, b, c, d)

b, d, e := false, 144, "Hmmm"
printf("%v %v %v %v %v\n", a, b, c, d, e)
}

fn test*() {
test1()
test2()
}

fn main() {
test()
}

0 comments on commit d212887

Please sign in to comment.