blob: 4d00c3cfc0c40d4bce86ed03e26a2d69fbf230d3 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/shell/interpreter/src/expressions.h"
#include <limits>
#include <memory>
#include <ostream>
#include "src/developer/shell/interpreter/src/instructions.h"
#include "src/developer/shell/interpreter/src/interpreter.h"
#include "src/developer/shell/interpreter/src/nodes.h"
#include "src/developer/shell/interpreter/src/schema.h"
#include "src/developer/shell/interpreter/src/scope.h"
#include "src/developer/shell/interpreter/src/types.h"
namespace shell {
namespace interpreter {
// - IntegerLiteral --------------------------------------------------------------------------------
void IntegerLiteral::Dump(std::ostream& os) const {
if (negative_) {
os << '-';
}
os << absolute_value_;
}
std::unique_ptr<Type> IntegerLiteral::InferType(ExecutionContext* context) const {
uint64_t max_absolute_value = std::numeric_limits<int64_t>::max();
if (negative_) {
++max_absolute_value;
}
if (absolute_value_ <= max_absolute_value) {
return std::make_unique<TypeInt64>();
}
return std::make_unique<TypeInteger>();
}
bool IntegerLiteral::Compile(ExecutionContext* context, code::Code* code,
const Type* for_type) const {
return for_type->GenerateIntegerLiteral(context, code, this);
}
// - ObjectField -----------------------------------------------------------------------------------
void ObjectDeclarationField::Dump(std::ostream& os) const {
std::stringstream type_str;
field_schema_->type()->Dump(type_str);
std::string type = type_str.str();
if (type != "") {
os << field_schema_->name() << ": " << *(field_schema_->type()) << "(" << *expression_ << ")";
} else {
os << field_schema_->name() << ": " << *expression_;
}
}
// - ObjectDeclaration -----------------------------------------------------------------------------
ObjectDeclaration::ObjectDeclaration(Interpreter* interpreter, uint64_t file_id, uint64_t node_id,
std::shared_ptr<ObjectSchema> object_schema,
std::vector<std::unique_ptr<ObjectDeclarationField>>&& fields)
: Expression(interpreter, file_id, node_id),
object_schema_(std::move(object_schema)),
fields_(std::move(fields)) {
// Fields need to be in the same order that they are in the schema. Find them in the schema and
// insert them at the correct point.
for (size_t i = 0; i < object_schema_->fields().size(); i++) {
if (object_schema_->fields()[i].get() != fields_[i]->schema()) {
bool found = false;
for (size_t j = i + 1; j < object_schema_->fields().size(); j++) {
if (object_schema_->fields()[i].get() == fields_[j]->schema()) {
ObjectDeclarationField* tmp = fields_[j].release();
fields_[j].reset(fields_[i].release());
fields_[i].reset(tmp);
found = true;
break;
}
}
FX_DCHECK(found) << "Unable to find schema for field";
}
}
}
void ObjectDeclaration::Dump(std::ostream& os) const {
os << "{";
const char* separator = "";
for (size_t i = 0; i < fields_.size(); i++) {
os << separator << *(fields_[i]);
separator = ", ";
}
os << "}";
}
std::unique_ptr<Type> ObjectDeclaration::InferType(ExecutionContext* context) const {
return std::make_unique<TypeObject>(object_schema_);
}
bool ObjectDeclaration::Compile(ExecutionContext* context, code::Code* code,
const Type* for_type) const {
const TypeObject* object_type = const_cast<Type*>(for_type)->AsTypeObject();
object_type->GenerateInitialization(context, code, this);
object_type->GenerateObject(context, code, this);
return true;
}
// - StringLiteral ---------------------------------------------------------------------------------
void StringLiteral::Dump(std::ostream& os) const {
// TODO(vbelliard): escape special characters.
os << '"' << string()->value() << '"';
}
std::unique_ptr<Type> StringLiteral::InferType(ExecutionContext* context) const {
return std::make_unique<TypeString>();
}
bool StringLiteral::Compile(ExecutionContext* context, code::Code* code,
const Type* for_type) const {
return for_type->GenerateStringLiteral(context, code, this);
}
// - ExpressionVariable ----------------------------------------------------------------------------
void ExpressionVariable::Dump(std::ostream& os) const { os << name_; }
std::unique_ptr<Type> ExpressionVariable::InferType(ExecutionContext* context) const {
const Variable* definition = context->interpreter()->SearchGlobal(name_);
if (definition == nullptr) {
return std::unique_ptr<TypeUndefined>();
}
return definition->type()->Duplicate();
}
bool ExpressionVariable::Compile(ExecutionContext* context, code::Code* code,
const Type* for_type) const {
const Variable* definition = context->interpreter()->SearchGlobal(name_);
if (definition == nullptr) {
context->EmitError(id(), "Can't find variable " + name_ + ".");
return false;
}
return for_type->GenerateVariable(context, code, id(), definition);
}
void ExpressionVariable::Assign(ExecutionContext* context, code::Code* code) const {
const Variable* definition = context->interpreter()->SearchGlobal(name_);
if (definition == nullptr) {
context->EmitError(id(), "Can't find variable " + name_ + ".");
return;
}
if (!definition->is_mutable()) {
context->EmitError(id(), "Can't assign constant " + name_ + ".");
return;
}
definition->type()->GenerateAssignVariable(context, code, id(), definition);
}
// - Addition --------------------------------------------------------------------------------------
void Addition::Dump(std::ostream& os) const {
os << *left() << (with_exceptions_ ? " +? " : " + ") << *right();
}
std::unique_ptr<Type> Addition::InferType(ExecutionContext* context) const {
return left()->IsConstant() ? right()->InferType(context) : left()->InferType(context);
}
bool Addition::Compile(ExecutionContext* context, code::Code* code, const Type* for_type) const {
return for_type->GenerateAddition(context, code, this);
}
size_t Addition::GenerateStringTerms(ExecutionContext* context, code::Code* code,
const Type* for_type) const {
return left()->GenerateStringTerms(context, code, for_type) +
right()->GenerateStringTerms(context, code, for_type);
}
} // namespace interpreter
} // namespace shell