Skip to content

Commit 1911a7d

Browse files
committed
Fix use of a[LAST] as an lvalue (fixes #163)
1 parent 00d0dea commit 1911a7d

File tree

4 files changed

+54
-18
lines changed

4 files changed

+54
-18
lines changed

src/analyzer.cpp

+43-8
Original file line numberDiff line numberDiff line change
@@ -1286,15 +1286,50 @@ const ast::Expression *Analyzer::analyze(const pt::SubscriptExpression *expr)
12861286
}
12871287
type = arraytype->elementtype;
12881288
const ast::ReferenceExpression *ref = dynamic_cast<const ast::ReferenceExpression *>(base);
1289-
// This check for ArrayReferenceRangeExpression is a stupendous hack that
1290-
// allows expressions like a[LAST] (which is compiled as a[LAST TO LAST][0])
1291-
// to work. Without this, the subscript [0] on the range expression tries
1292-
// to generate the address of the base so it can apply an INDEXAR opcode.
1293-
// Since the range expression is really a function call, it has no address.
1294-
if (ref != nullptr && dynamic_cast<const ast::ArrayReferenceRangeExpression *>(ref) == nullptr) {
1295-
return new ast::ArrayReferenceIndexExpression(type, ref, index, false);
1289+
if (ref != nullptr) {
1290+
if (expr->from_last) {
1291+
return new ast::ArrayReferenceIndexExpression(
1292+
type,
1293+
ref,
1294+
new ast::AdditionExpression(
1295+
new ast::SubtractionExpression(
1296+
new ast::FunctionCall(
1297+
new ast::VariableExpression(
1298+
ref->type->methods.at("size")
1299+
),
1300+
{ ref }
1301+
),
1302+
new ast::ConstantNumberExpression(number_from_sint32(1))
1303+
),
1304+
index
1305+
),
1306+
false
1307+
);
1308+
} else {
1309+
return new ast::ArrayReferenceIndexExpression(type, ref, index, false);
1310+
}
12961311
} else {
1297-
return new ast::ArrayValueIndexExpression(type, base, index, false);
1312+
if (expr->from_last) {
1313+
return new ast::ArrayValueIndexExpression(
1314+
type,
1315+
base,
1316+
new ast::AdditionExpression(
1317+
new ast::SubtractionExpression(
1318+
new ast::FunctionCall(
1319+
new ast::VariableExpression(
1320+
base->type->methods.at("size")
1321+
),
1322+
{ base }
1323+
),
1324+
new ast::ConstantNumberExpression(number_from_sint32(1))
1325+
),
1326+
index
1327+
),
1328+
false
1329+
);
1330+
} else {
1331+
return new ast::ArrayValueIndexExpression(type, base, index, false);
1332+
}
12981333
}
12991334
} else if (dicttype != nullptr) {
13001335
if (not index->type->is_assignment_compatible(ast::TYPE_STRING)) {

src/parser.cpp

+1-9
Original file line numberDiff line numberDiff line change
@@ -664,23 +664,15 @@ std::unique_ptr<Expression> Parser::parseAtom()
664664
last = parseExpression();
665665
}
666666
range.reset(new ArrayRange(tok_lbracket, std::move(index), first_from_end, std::move(last), last_from_end));
667-
} else {
668-
if (first_from_end) {
669-
range.reset(new ArrayRange(tok_lbracket, std::move(index), first_from_end, nullptr /*std::move(index)*/, first_from_end));
670-
}
671667
}
672668
if (tokens[i].type != COMMA && tokens[i].type != RBRACKET) {
673669
error(2020, tokens[i], "']' expected");
674670
}
675671
++i;
676672
if (range != nullptr) {
677673
expr.reset(new RangeSubscriptExpression(tok_lbracket, tokens[i].column, std::move(expr), std::move(range)));
678-
if (first_from_end && not has_range) {
679-
std::unique_ptr<Expression> index { new NumberLiteralExpression(Token(), number_from_uint32(0)) };
680-
expr.reset(new SubscriptExpression(tok_lbracket, tokens[i].column, std::move(expr), std::move(index)));
681-
}
682674
} else {
683-
expr.reset(new SubscriptExpression(tok_lbracket, tokens[i].column, std::move(expr), std::move(index)));
675+
expr.reset(new SubscriptExpression(tok_lbracket, tokens[i].column, std::move(expr), std::move(index), first_from_end));
684676
}
685677
} while (tokens[i-1].type == COMMA);
686678
} else if (tokens[i].type == LPAREN) {

src/pt.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,11 @@ class ArrowExpression: public Expression {
392392

393393
class SubscriptExpression: public Expression {
394394
public:
395-
SubscriptExpression(const Token &token, size_t end_column, std::unique_ptr<Expression> &&base, std::unique_ptr<Expression> &&index): Expression(token, base->get_start_column(), end_column), base(std::move(base)), index(std::move(index)) {}
395+
SubscriptExpression(const Token &token, size_t end_column, std::unique_ptr<Expression> &&base, std::unique_ptr<Expression> &&index, bool from_last): Expression(token, base->get_start_column(), end_column), base(std::move(base)), index(std::move(index)), from_last(from_last) {}
396396
virtual void accept(IParseTreeVisitor *visitor) const override { visitor->visit(this); }
397397
std::unique_ptr<Expression> base;
398398
std::unique_ptr<Expression> index;
399+
bool from_last;
399400
};
400401

401402
class InterpolatedStringExpression: public Expression {

t/array-slice.neon

+8
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,11 @@ dump(arr()[LAST-1 TO LAST])
6565
a[0 TO -1] := [9]
6666
dump(a)
6767
%= [9, 1, 5, 5, 5, 4]
68+
69+
a[FIRST] := 0
70+
dump(a)
71+
%= [0, 1, 5, 5, 5, 4]
72+
73+
a[LAST] := 0
74+
dump(a)
75+
%= [0, 1, 5, 5, 5, 0]

0 commit comments

Comments
 (0)