Skip to content

Commit

Permalink
Allow returning composite literal addr from funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
vtereshkov authored Dec 2, 2020
1 parent 4ebaa8a commit e98054d
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 48 deletions.
21 changes: 7 additions & 14 deletions examples/lisp/ev.um
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import "../../import/std.um"


type Expr* = struct {
atom: str
val: int
car, cdr: ^Expr
atom: str
val: int
car, cdr: ^Expr
}


Expand Down Expand Up @@ -44,17 +44,12 @@ fn (e: ^Expr) toBool*(): bool {


fn strExpr*(s: str): ^Expr {
e := new(Expr)
e.atom = s
return e
return &Expr{s, 0, null, null}
}


fn intExpr*(i: int): ^Expr {
e := new(Expr)
e.atom = "<number>"
e.val = i
return e
return &Expr{"<number>", i, null, null}
}


Expand Down Expand Up @@ -86,10 +81,8 @@ fn cdr*(x: ^Expr): ^Expr {
}


fn cons*(x, y: ^Expr): ^Expr {
z := new(Expr)
z^ = Expr{"", 0, x, y}
return z
fn cons*(x, y: ^Expr): ^Expr {
return &Expr{"", 0, x, y}
}


Expand Down
4 changes: 1 addition & 3 deletions examples/lisp/parse.um
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ fn (p: ^Parser) parse(): ^ev.Expr {

// Parse atom
p.lexer.check(lex.tokAtom)
res := new(ev.Expr)
res.atom = p.lexer.tok.name
res.val = p.lexer.tok.val
res := &ev.Expr{p.lexer.tok.name, p.lexer.tok.val, null, null}
p.lexer.next()
return res

Expand Down
75 changes: 47 additions & 28 deletions src/umka_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ static void doCopyResultToTempVar(Compiler *comp, Type *type)
}


static void doEscapeToHeap(Compiler *comp, Type *ptrType)
{
// Allocate heap
genPushIntConst(&comp->gen, typeSize(&comp->types, ptrType->base));
genCallBuiltin(&comp->gen, TYPE_PTR, BUILTIN_NEW);
doCopyResultToTempVar(comp, ptrType);

// Save heap pointer
genDup(&comp->gen);
genPopReg(&comp->gen, VM_REG_COMMON_0);

// Copy to heap and use heap pointer
genSwapAssign(&comp->gen, ptrType->base->kind, typeSize(&comp->types, ptrType->base));
genPushReg(&comp->gen, VM_REG_COMMON_0);
}


static void doIntToRealConv(Compiler *comp, Type *dest, Type **src, Const *constant, bool lhs)
{
BuiltinFunc builtin = lhs ? BUILTIN_REAL_LHS : BUILTIN_REAL;
Expand Down Expand Up @@ -214,22 +231,8 @@ static void doValueToInterfaceConv(Compiler *comp, Type *dest, Type **src, Const
if (constant)
comp->error.handler(comp->error.context, "Conversion to interface is not allowed in constant expressions");

Type *srcPtrType = typeAddPtrTo(&comp->types, &comp->blocks, *src);

// Allocate heap
genPushIntConst(&comp->gen, typeSize(&comp->types, *src));
genCallBuiltin(&comp->gen, TYPE_PTR, BUILTIN_NEW);
doCopyResultToTempVar(comp, srcPtrType);

// Save heap pointer
genDup(&comp->gen);
genPopReg(&comp->gen, VM_REG_COMMON_0);

// Copy to heap and use heap pointer (interfaces accept only pointers as their dynamic types)
genSwapAssign(&comp->gen, (*src)->kind, typeSize(&comp->types, *src));
genPushReg(&comp->gen, VM_REG_COMMON_0);

*src = srcPtrType;
*src = typeAddPtrTo(&comp->types, &comp->blocks, *src);
doEscapeToHeap(comp, *src);
doPtrToInterfaceConv(comp, dest, src, constant);
}

Expand Down Expand Up @@ -1121,14 +1124,20 @@ static void parseCompositeLiteral(Compiler *comp, Type **type, Const *constant)
}


static void parseTypeCastOrCompositeLiteral(Compiler *comp, Ident *ident, Type **type, Const *constant, bool *isVar, bool *isCall)
static void parseTypeCastOrCompositeLiteral(Compiler *comp, Ident *ident, Type **type, Const *constant, bool *isVar, bool *isCall, bool *isCompLit)
{
*type = parseType(comp, ident);

if (comp->lex.tok.kind == TOK_LPAR)
{
parseTypeCast(comp, type, constant);
*isCompLit = false;
}
else if (comp->lex.tok.kind == TOK_LBRACE)
{
parseCompositeLiteral(comp, type, constant);
*isCompLit = true;
}
else
comp->error.handler(comp->error.context, "Type cast or composite literal expected");

Expand Down Expand Up @@ -1317,7 +1326,7 @@ static void parseCallSelector(Compiler *comp, Type **type, Const *constant, bool


// selectors = {derefSelector | indexSelector | fieldSelector | callSelector}.
static void parseSelectors(Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall)
static void parseSelectors(Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall, bool *isCompLit)
{
while (comp->lex.tok.kind == TOK_CARET || comp->lex.tok.kind == TOK_LBRACKET ||
comp->lex.tok.kind == TOK_PERIOD || comp->lex.tok.kind == TOK_LPAR)
Expand All @@ -1333,27 +1342,32 @@ static void parseSelectors(Compiler *comp, Type **type, Const *constant, bool *i
case TOK_LPAR: parseCallSelector (comp, type, constant, isVar, isCall); break;
default: break;
} // switch

*isCompLit = false;
} // while
}


// designator = (primary | typeCast | compositeLiteral) selectors.
void parseDesignator(Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall)
void parseDesignator(Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall, bool *isCompLit)
{
*isCompLit = false;

Ident *ident = NULL;
if (comp->lex.tok.kind == TOK_IDENT && (ident = parseQualIdent(comp)) && ident->kind != IDENT_TYPE)
parsePrimary(comp, ident, type, constant, isVar, isCall);
else
parseTypeCastOrCompositeLiteral(comp, ident, type, constant, isVar, isCall);
parseTypeCastOrCompositeLiteral(comp, ident, type, constant, isVar, isCall, isCompLit);

parseSelectors(comp, type, constant, isVar, isCall);
parseSelectors(comp, type, constant, isVar, isCall, isCompLit);
}


// designatorList = designator {"," designator}.
void parseDesignatorList(Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall)
{
parseDesignator(comp, type, constant, isVar, isCall);
bool isCompLit;
parseDesignator(comp, type, constant, isVar, isCall, &isCompLit);

if (comp->lex.tok.kind == TOK_COMMA)
{
Expand All @@ -1374,8 +1388,8 @@ void parseDesignatorList(Compiler *comp, Type **type, Const *constant, bool *isV

lexNext(&comp->lex);

bool fieldIsVar, fieldIsCall;
parseDesignator(comp, &fieldType, NULL, &fieldIsVar, &fieldIsCall);
bool fieldIsVar, fieldIsCall, fieldIsCompLit;
parseDesignator(comp, &fieldType, NULL, &fieldIsVar, &fieldIsCall, &fieldIsCompLit);

if (fieldIsVar != *isVar || fieldIsCall != *isCall)
comp->error.handler(comp->error.context, "Inconsistent designator list");
Expand All @@ -1400,8 +1414,8 @@ static void parseFactor(Compiler *comp, Type **type, Const *constant)
case TOK_FN:
{
// A designator that isVar is always an addressable quantity (a structured type or a pointer to a value type)
bool isVar, isCall;
parseDesignator(comp, type, constant, &isVar, &isCall);
bool isVar, isCall, isCompLit;
parseDesignator(comp, type, constant, &isVar, &isCall, &isCompLit);
if (isVar)
{
if (!typeStructured(*type))
Expand Down Expand Up @@ -1498,14 +1512,19 @@ static void parseFactor(Compiler *comp, Type **type, Const *constant)

lexNext(&comp->lex);

bool isVar, isCall;
parseDesignator(comp, type, constant, &isVar, &isCall);
bool isVar, isCall, isCompLit;
parseDesignator(comp, type, constant, &isVar, &isCall, &isCompLit);

if (!isVar)
comp->error.handler(comp->error.context, "Unable to take address");

// A value type is already a pointer, a structured type needs to have it added
if (typeStructured(*type))
*type = typeAddPtrTo(&comp->types, &comp->blocks, *type);

// Allow returning addresses of composite literals from functions
if (isCompLit)
doEscapeToHeap(comp, *type);
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/umka_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ void doImplicitTypeConv (Compiler *comp, Type *dest, Type **src, Const *constant
void doApplyOperator (Compiler *comp, Type **type, Type **rightType, Const *constant, Const *rightConstant, TokenKind op, bool apply, bool convertLhs);

Ident *parseQualIdent (Compiler *comp);
void parseDesignator (Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall);
void parseDesignator (Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall, bool *isCompLit);
void parseDesignatorList(Compiler *comp, Type **type, Const *constant, bool *isVar, bool *isCall);
void parseExpr (Compiler *comp, Type **type, Const *constant);
void parseExprList (Compiler *comp, Type **type, Type *destType, Const *constant);
Expand Down
4 changes: 2 additions & 2 deletions tests/gc.um
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ fn f2() {

fn g2(): ^int {a := new(int); return a}

fn h2(): st {
fn h2(): ^st {
d := new(int)
return st{x: 7, p: d, y: 5, q: d}
return &st{x: 7, p: d, y: 5, q: d}
}

fn test*() {
Expand Down

0 comments on commit e98054d

Please sign in to comment.