Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion modules/Kernel/BareTests/BareTestsModule.st
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ Class {
#category : #'Powerlang-Core'
}

{ #category : #spec }
BareTestsModule >> imports [
^{
#Kernel -> #(HashTable)
}
]

{ #category : #tests }
BareTestsModule >> test001SendYourself [
^true yourself
Expand Down Expand Up @@ -385,6 +392,11 @@ BareTestsModule >> test232BitShiftRightSelector [
^(16rAA00 bitShiftRight: 8) == 16rAA
]

{ #category : #tests }
BareTestsModule >> test240HashTablePrimeForReturnsNextGoodPrime [
^(HashTable primeFor: 300) == 359
]

{ #category : #main }
BareTestsModule >> runTest: selector [
| result |
Expand Down Expand Up @@ -434,7 +446,8 @@ BareTestsModule >> main: anArray [
test220BitXorSmallIntegers test221BitXorSmallIntWithLargeInt
test222BitXorLargeIntWithSmallInt
test230BitShiftLeftOverflow test231BitShiftRightNegativeArg
test232BitShiftRightSelector).
test232BitShiftRightSelector
test240HashTablePrimeForReturnsNextGoodPrime).
tests do: [:sel |
(self runTest: sel)
ifTrue: [passed := passed + 1]
Expand Down
2 changes: 1 addition & 1 deletion modules/Kernel/HashTable.st
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ HashTable class >> primeFor: size [
primes := self goodPrimes.
1 to: primes size do: [:i | | p |
p := primes at: i.
p > n ifTrue: [p]].
p > n ifTrue: [^p]].
^n
]

Expand Down
2 changes: 1 addition & 1 deletion modules/Kernel/LMR/Float.st
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ LMRFloat >> basicAt: index [

{ #category : #random }
LMRFloat >> fractionPart [
| new result |>
| new result |
new := Float new.
result := self _floatFractionPartInto: new.
result == new ifTrue: [^result].
Expand Down
2 changes: 1 addition & 1 deletion runtime/cpp/Allocator/AllocationZone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ HeapObject *AllocationZone::shallowCopyCommiting_(HeapObject *object)
if (copy)
return copy;

auto size = object->bodySizeInBytes();
auto size = object->totalSizeInBytes();
if (size > GCHeap::LargeThreshold)
{
auto space = _heap->createLargeSpace_(size);
Expand Down
4 changes: 1 addition & 3 deletions runtime/cpp/Allocator/GCHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,9 @@ GCSpace *Egg::GCHeap::createLargeSpace_(uintptr_t size)
error_(std::string("Not enough memory to allocate ") + std::to_string(size) + "bytes");

auto limit = address + size;
auto space = GCSpace::allocatedAt_limit_(address, limit);
auto space = GCSpace::allocatedAt_limit_(address, limit, true);

space->_name = "Large";
space->_committedLimit = limit;
space->_softLimit = limit;
this->addSpace_(space);
_largeSpaces.push_back(space);
return space;
Expand Down
10 changes: 8 additions & 2 deletions runtime/cpp/Allocator/GCSpace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,18 @@ uintptr_t GCSpace::allocateCommittingIfNeeded_(uint32_t size)
{
auto answer = _next;
auto next = answer + size;
if (next <= _softLimit || this->commitMemoryUpTo_(next))
if (next <= _softLimit)
{
_next = next;
return answer;
}
if (this->commitMemoryUpTo_(next))
{
_softLimit = _committedLimit;
_next = next;
return answer;
}
else return 0;
return 0;
}

bool GCSpace::increaseSoftLimit_(uint32_t delta)
Expand Down
2 changes: 2 additions & 0 deletions runtime/cpp/Bootstrap/Bootstrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,8 @@ void Bootstrapper::compileAndInstallMethod_(const Egg::string& source, HeapObjec

// Transfer the compiled method to a heap object
HeapObject* method = allocateSlots_(Offsets::MethodInstSize + literalCount);
method->beNamed();
method->beArrayed();

// Set method's behavior to CompiledMethod's instance behavior
Object* cmBehavior = _compiledMethodClass->slot(Offsets::SpeciesInstanceBehavior);
Expand Down
150 changes: 87 additions & 63 deletions runtime/cpp/Compiler/Parser/SSmalltalkParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,82 +644,106 @@ bool SSmalltalkParser::hasKeywordSelector() const {
}

SParseNode* SSmalltalkParser::literalArray() {
// Matches Smalltalk literalArray → arrayBody → arrayElement
uint32_t position = _token->position().start();
std::vector<LiteralValue> elements;

// Step past #( (or ( for nested arrays)
auto* array = arrayBody();
step();
while (_token && !_token->is(')') && !_token->isEnd()) {
// arrayElement
if (_token->isLiteral()) {
elements.push_back(parseLiteralValue());
} else if (_token->isName()) {
elements.push_back(pseudoLiteralValue());
} else if (_token->isKeyword()) {
// literalKeyword: collect multi-part keyword symbol
Egg::string keyword = _token->value();
step();
while (_token && _token->isKeyword()) {
keyword += _token->value();
step();
}
elements.push_back(LiteralValue::fromSymbol(keyword));
continue; // already stepped past last keyword
} else if (_token->is('-')) {
LiteralValue neg = negativeNumberOrBinary();
if (!neg.isNone()) {
elements.push_back(std::move(neg));
} else {
elements.push_back(LiteralValue::fromSymbol("-"));
}
} else if (_token->hasSymbol()) {
elements.push_back(LiteralValue::fromSymbol(_token->value()));
} else if (_token->is('(') || _token->is("#(")) {
// nested literal array
auto* nested = static_cast<SLiteralNode*>(literalArray());
elements.push_back(nested->literalValue());
continue; // literalArray already stepped past )
} else if (_token->is("#[")) {
auto* nested = static_cast<SLiteralNode*>(literalByteArray());
elements.push_back(nested->literalValue());
continue; // literalByteArray already stepped past ]
} else {
error_("invalid literal array element");
}
return array;
}

SParseNode* SSmalltalkParser::literalByteArray() {
auto* node = byteArrayBody();
step();
return node;
}

SLiteralNode* SSmalltalkParser::arrayBody() {
std::vector<LiteralValue> literals;
uint32_t position = _token->position().start();

while (true) {
step();
if (!_token || _token->is(')') || _token->isEnd()) {
break;
}
literals.push_back(arrayElement());
}

if (_token && _token->isEnd()) missingToken_(")");
if (!_token || _token->isEnd()) {
missingToken_(")");
}

auto lit = new SLiteralNode(_compiler);
lit->literalValue_(LiteralValue::fromArray(std::move(elements)));
lit->position_(Stretch(position, _token ? _token->position().end() : position));
step(); // past )
return lit;
auto* node = new SLiteralNode(_compiler);
node->literalValue_(LiteralValue::fromArray(std::move(literals)));
node->position_(Stretch(position, _token->position().end()));
return node;
}

SParseNode* SSmalltalkParser::literalByteArray() {
uint32_t position = _token->position().start();
step();
std::vector<uint8_t> bytes;
while (_token && !_token->is(']') && !_token->isEnd()) {
if (_token->isLiteral()) {
// Each element should be a number 0-255
std::string v = _token->value().toUtf8();
int val = static_cast<int>(std::stol(v, nullptr, 0));
bytes.push_back(static_cast<uint8_t>(val));
LiteralValue SSmalltalkParser::arrayElement() {
if (_token->isLiteral()) {
return parseLiteralValue();
}
if (_token->isName()) {
return pseudoLiteralValue();
}
if (_token->isKeyword()) {
return literalKeyword();
}
if (_token->is('-')) {
LiteralValue neg = negativeNumberOrBinary();
return neg.isNone() ? LiteralValue::fromSymbol("-") : std::move(neg);
}
if (_token->hasSymbol()) {
return LiteralValue::fromSymbol(_token->value());
}
if (_token->is('(') || _token->is("#(")) {
return arrayBody()->literalValue();
}
if (_token->is("#[")) {
return byteArrayBody()->literalValue();
}
error_("invalid literal array element");
return LiteralValue();
}

LiteralValue SSmalltalkParser::literalKeyword() {
Egg::string keyword = _token->value();
uint32_t prevEnd = _token->position().end();

while (true) {
auto* nextToken = peek();
if (!nextToken || !nextToken->isKeyword() || nextToken->position().start() != prevEnd) {
break;
}
step();
keyword += _token->value();
prevEnd = _token->position().end();
}

return LiteralValue::fromSymbol(keyword);
}

SLiteralNode* SSmalltalkParser::byteArrayBody() {
std::vector<uint8_t> bytes;
uint32_t position = _token->position().start();

while (true) {
step();
if (!_token || !_token->isLiteral()) {
break;
}

std::string v = _token->value().toUtf8();
int val = static_cast<int>(std::stol(v, nullptr, 0));
bytes.push_back(static_cast<uint8_t>(val));
}

if (!_token || !_token->is(']')) {
missingToken_("]");
}
auto lit = new SLiteralNode(_compiler);
lit->literalValue_(LiteralValue::fromByteArray(std::move(bytes)));
lit->position_(Stretch(position, _token->position().end()));
step();
return lit;

auto* node = new SLiteralNode(_compiler);
node->literalValue_(LiteralValue::fromByteArray(std::move(bytes)));
node->position_(Stretch(position, _token->position().end()));
return node;
}

SBraceNode* SSmalltalkParser::bracedArray() {
Expand Down
4 changes: 4 additions & 0 deletions runtime/cpp/Compiler/Parser/SSmalltalkParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ class SSmalltalkParser {

SParseNode* literalArray();
SParseNode* literalByteArray();
SLiteralNode* arrayBody();
LiteralValue arrayElement();
LiteralValue literalKeyword();
SLiteralNode* byteArrayBody();
SBraceNode* bracedArray();

LiteralValue parseLiteralValue();
Expand Down
104 changes: 104 additions & 0 deletions runtime/cpp/Compiler/tests/ParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,110 @@ TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Literal string", "[parser
tearDown();
}

TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Literal array", "[parser]") {
setUp();

SMethodNode* method = parseExpression("#(16rFE $a 'hello' #s #(1 2))");

REQUIRE(method != nullptr);
REQUIRE(method->statements().size() == 1);

SParseNode* stmt = method->statements()[0];
REQUIRE(stmt->isLiteral());

SLiteralNode* lit = static_cast<SLiteralNode*>(stmt);
const LiteralValue& array = lit->literalValue();
REQUIRE(array.isArray());
REQUIRE(array.asArray().size() == 5);

REQUIRE(array.asArray()[0].isInteger());
REQUIRE(array.asArray()[0].asInteger() == 0xFE);
REQUIRE(array.asArray()[1].isCharacter());
REQUIRE(array.asArray()[1].asCharacter() == 'a');
REQUIRE(array.asArray()[2].isString());
REQUIRE(array.asArray()[2].asString() == "hello");
REQUIRE(array.asArray()[3].isSymbol());
REQUIRE(array.asArray()[3].asString() == "s");
REQUIRE(array.asArray()[4].isArray());
REQUIRE(array.asArray()[4].asArray().size() == 2);
REQUIRE(array.asArray()[4].asArray()[0].asInteger() == 1);
REQUIRE(array.asArray()[4].asArray()[1].asInteger() == 2);

tearDown();
}

TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Literal keyword array symbols", "[parser]") {
setUp();

SMethodNode* method = parseExpression("#(a:b: c: d:)");

REQUIRE(method != nullptr);
REQUIRE(method->statements().size() == 1);

SParseNode* stmt = method->statements()[0];
REQUIRE(stmt->isLiteral());

SLiteralNode* lit = static_cast<SLiteralNode*>(stmt);
const LiteralValue& array = lit->literalValue();
REQUIRE(array.isArray());
REQUIRE(array.asArray().size() == 3);

REQUIRE(array.asArray()[0].isSymbol());
REQUIRE(array.asArray()[0].asString() == "a:b:");
REQUIRE(array.asArray()[1].isSymbol());
REQUIRE(array.asArray()[1].asString() == "c:");
REQUIRE(array.asArray()[2].isSymbol());
REQUIRE(array.asArray()[2].asString() == "d:");

tearDown();
}

TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Negative elements in literal array", "[parser]") {
setUp();

SMethodNode* method = parseExpression("#(-21 1 -5 4)");

REQUIRE(method != nullptr);
REQUIRE(method->statements().size() == 1);

SParseNode* stmt = method->statements()[0];
REQUIRE(stmt->isLiteral());

SLiteralNode* lit = static_cast<SLiteralNode*>(stmt);
const LiteralValue& array = lit->literalValue();
REQUIRE(array.isArray());
REQUIRE(array.asArray().size() == 4);
REQUIRE(array.asArray()[0].asInteger() == -21);
REQUIRE(array.asArray()[1].asInteger() == 1);
REQUIRE(array.asArray()[2].asInteger() == -5);
REQUIRE(array.asArray()[3].asInteger() == 4);

tearDown();
}

TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Dash-starting symbols in literal array", "[parser]") {
setUp();

SMethodNode* method = parseExpression("#(#++ #--)");

REQUIRE(method != nullptr);
REQUIRE(method->statements().size() == 1);

SParseNode* stmt = method->statements()[0];
REQUIRE(stmt->isLiteral());

SLiteralNode* lit = static_cast<SLiteralNode*>(stmt);
const LiteralValue& array = lit->literalValue();
REQUIRE(array.isArray());
REQUIRE(array.asArray().size() == 2);
REQUIRE(array.asArray()[0].isSymbol());
REQUIRE(array.asArray()[0].asString() == "++");
REQUIRE(array.asArray()[1].isSymbol());
REQUIRE(array.asArray()[1].asString() == "--");

tearDown();
}

TEST_CASE_METHOD(SSmalltalkParserTestFixture, "Parser: Complex expression", "[parser]") {
setUp();

Expand Down
Loading
Loading