Skip to content
Open
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
9 changes: 9 additions & 0 deletions src/parser/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,15 @@ void Lexer::skipSpace() {
}
}

std::optional<char> Lexer::peekChar() const {
auto n = next();
if (n.empty()) {
return std::nullopt;
}

return n[0];
}

bool Lexer::takeLParen() {
if (LexCtx(next()).startsWith("("sv)) {
++pos;
Expand Down
2 changes: 2 additions & 0 deletions src/parser/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ struct Lexer {
advance();
}

std::optional<char> peekChar() const;

bool takeLParen();

bool peekLParen() { return Lexer(*this).takeLParen(); }
Expand Down
97 changes: 66 additions & 31 deletions src/parser/wast-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,72 @@ Result<NaNKind> nan(Lexer& in) {
}

Result<ExpectedResult> result(Lexer& in) {
if (in.takeSExprStart("v128.const"sv)) {
LaneResults results(in.peekChar() == 'f' ? LaneResults::LaneType::Float
: LaneResults::LaneType::Int);
auto& lanes = results.lanes;

if (in.takeKeyword("i8x16"sv)) {
for (int i = 0; i < 16; ++i) {
auto int_ = in.takeI8();
if (!int_) {
return in.err("expected i8 immediate");
}
lanes.push_back(Literal(static_cast<uint32_t>(*int_)));
}
} else if (in.takeKeyword("i16x8"sv)) {
for (int i = 0; i < 8; ++i) {
auto int_ = in.takeI16();
if (!int_) {
return in.err("expected i16 immediate");
}
lanes.push_back(Literal(static_cast<uint32_t>(*int_)));
}
} else if (in.takeKeyword("i32x4"sv)) {
for (int i = 0; i < 4; ++i) {
auto int_ = in.takeI32();
if (!int_) {
return in.err("expected i32 immediate");
}
lanes.push_back(Literal(static_cast<uint32_t>(*int_)));
}
} else if (in.takeKeyword("i64x2"sv)) {
for (int i = 0; i < 2; ++i) {
auto int_ = in.takeI64();
if (!int_) {
return in.err("expected i64 immediate");
}
lanes.push_back(Literal(*int_));
}
} else if (in.takeKeyword("f32x4"sv)) {
for (int i = 0; i < 4; ++i) {
if (auto f = in.takeF32()) {
lanes.push_back(Literal(*f));
} else {
auto kind = nan(in);
CHECK_ERR(kind);
lanes.push_back(NaNResult{*kind, Type::f32});
}
}
} else if (in.takeKeyword("f64x2"sv)) {
for (int i = 0; i < 2; ++i) {
if (auto f = in.takeF64()) {
lanes.push_back(Literal(*f));
} else {
auto kind = nan(in);
CHECK_ERR(kind);
lanes.push_back(NaNResult{*kind, Type::f64});
}
}
} else {
return in.err("unexpected vector shape");
}
if (!in.takeRParen()) {
return in.err("expected end of v128.const");
}
return results;
}

Lexer constLexer = in;
auto c = const_(constLexer);
// TODO: Generating and discarding errors like this can lead to quadratic
Expand Down Expand Up @@ -198,37 +264,6 @@ Result<ExpectedResult> result(Lexer& in) {
return NaNResult{*kind, Type::f64};
}

if (in.takeSExprStart("v128.const"sv)) {
LaneResults lanes;
if (in.takeKeyword("f32x4"sv)) {
for (int i = 0; i < 4; ++i) {
if (auto f = in.takeF32()) {
lanes.push_back(Literal(*f));
} else {
auto kind = nan(in);
CHECK_ERR(kind);
lanes.push_back(NaNResult{*kind, Type::f32});
}
}
} else if (in.takeKeyword("f64x2"sv)) {
for (int i = 0; i < 2; ++i) {
if (auto f = in.takeF64()) {
lanes.push_back(Literal(*f));
} else {
auto kind = nan(in);
CHECK_ERR(kind);
lanes.push_back(NaNResult{*kind, Type::f64});
}
}
} else {
return in.err("unexpected vector shape");
}
if (!in.takeRParen()) {
return in.err("expected end of v128.const");
}
return lanes;
}

if (in.takeSExprStart("ref.null")) {
if (!in.takeRParen()) {
return in.err("expected end of ref.null");
Expand Down
12 changes: 11 additions & 1 deletion src/parser/wat-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,17 @@ struct NaNResult {

using LaneResult = std::variant<Literal, NaNResult>;

using LaneResults = std::vector<LaneResult>;
struct LaneResults {
enum class LaneType {
Int,
Float,
};
LaneResults(LaneType type, std::vector<LaneResult> lanes = {})
: type(type), lanes(std::move(lanes)) {}

LaneType type;
std::vector<LaneResult> lanes;
};

using ExpectedResult =
std::variant<Literal, NullRefResult, RefResult, NaNResult, LaneResults>;
Expand Down
49 changes: 32 additions & 17 deletions src/tools/wasm-shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,28 +400,43 @@ struct Shell {
err << e->msg << atIndex();
return Err{err.str()};
}
} else if (auto* lanes = std::get_if<LaneResults>(&expected)) {
} else if (auto* l = std::get_if<LaneResults>(&expected)) {
auto* lanes = &l->lanes;

auto check = [&](const auto& vals) -> Result<> {
for (size_t i = 0; i < vals.size(); ++i) {
auto check = checkLane(vals[i], (*lanes)[i], i);
if (auto* e = check.getErr()) {
err << e->msg << atIndex();
return Err{err.str()};
}
}
return Ok{};
};

bool isFloat = l->type == WATParser::LaneResults::LaneType::Float;
switch (lanes->size()) {
// Use unsigned values for the smaller types here to avoid sign
// extension when storing 8/16-bit values in 32-bit ints. This isn't
// needed for i32 and i64.
case 16: {
// There is no f8.
CHECK_ERR(check(val.getLanesUI8x16()));
break;
}
case 8: {
CHECK_ERR(
check(isFloat ? val.getLanesF16x8() : val.getLanesUI16x8()));
break;
}
case 4: {
auto vals = val.getLanesF32x4();
for (Index i = 0; i < 4; ++i) {
auto check = checkLane(vals[i], (*lanes)[i], i);
if (auto* e = check.getErr()) {
err << e->msg << atIndex();
return Err{err.str()};
}
}
CHECK_ERR(
check(isFloat ? val.getLanesF32x4() : val.getLanesI32x4()));
break;
}
case 2: {
auto vals = val.getLanesF64x2();
for (Index i = 0; i < 2; ++i) {
auto check = checkLane(vals[i], (*lanes)[i], i);
if (auto* e = check.getErr()) {
err << e->msg << atIndex();
return Err{err.str()};
}
}
CHECK_ERR(
check(isFloat ? val.getLanesF64x2() : val.getLanesI64x2()));
break;
}
default:
Expand Down
Loading