Compare commits

...

2 Commits

5 changed files with 148 additions and 79 deletions
+15 -3
View File
@@ -110,6 +110,10 @@ static const char* typeNames[furvm::instruction::Count] = {
"load",
// Store:
"store",
// LoadGlobal:
"loadg",
// StoreGlobal:
"storeg",
// Call:
"call",
// Jump:
@@ -132,7 +136,7 @@ int main(int argc, char** argv) {
furvm::mod mod;
try {
mod = furvm::mod::load(file);
} catch (std::exception ex) {
} catch (const std::exception& ex) {
std::cerr << "Failed to load module " << argv[1] << ": " << ex.what() << '\n';
return 1;
}
@@ -154,7 +158,7 @@ int main(int argc, char** argv) {
std::unordered_set<std::size_t> deadLabels;
std::size_t labelCounter = 0;
std::cout << "; Functions:\n";
std::cout << "\n; Functions:\n";
for (const auto& ptr : mod.functions()) {
const auto& [header, func] = *ptr;
auto it = mod.function_map().find(header.id());
@@ -187,7 +191,14 @@ int main(int argc, char** argv) {
std::cout << '\n';
}
std::cout << "; Bytecode:\n";
if (mod.get_global_variable_count() > 0) {
std::cout << "\n; Global Variables:\n";
for (std::uint16_t i = 0; i < mod.get_global_variable_count(); ++i) {
std::cout << "allocate __g" << i << '\n';
}
}
std::cout << "\n; Bytecode:\n";
// Label pass:
for (std::size_t off = 0; off < mod.bytecode().size();) {
furvm::instruction instr{};
@@ -217,6 +228,7 @@ int main(int argc, char** argv) {
case furvm::instruction_argument::Constant: throw std::runtime_error("unimplemented");
case furvm::instruction_argument::Type: std::cout << " $__t" << instr.arg.u16; break;
case furvm::instruction_argument::Variable: std::cout << " %" << instr.arg.u16; break;
case furvm::instruction_argument::GlobalVariable: std::cout << " %__g" << instr.arg.u16; break;
case furvm::instruction_argument::Function: std::cout << ' ' << funcNames[instr.arg.s16]; break;
case furvm::instruction_argument::Offset: std::cout << " #" << labels[instr.arg.s16]; break;
case furvm::instruction_argument::Count: break;
+2 -2
View File
@@ -1,6 +1,6 @@
type arr = array $s8 10
func println $arr = native println
func println ref $arr = native println
public func main = #main
main:
@@ -30,5 +30,5 @@ body:
end:
drop
load %0
call $arr println
call ref $arr println
ret
+104 -72
View File
@@ -126,14 +126,10 @@ struct mod_context {
std::vector<std::size_t> unknowns;
};
furvm::mod mod;
std::unordered_map<std::pair<std::string, furvm::function_sig>,
furvm::function_h,
furlang::utility::
pair_hash<std::string, furvm::function_sig, std::hash<std::string>, furvm::detail::function_sig_hash>>
functions;
std::unordered_map<std::string, furvm::mod_type_h> types;
std::unordered_map<std::string, std::uint16_t> variables;
furvm::mod mod;
std::unordered_map<std::string, std::vector<furvm::function_h>> functions;
std::unordered_map<std::string, furvm::mod_type_h> types;
std::unordered_map<std::string, std::uint16_t> variables;
std::unordered_map<std::string, label_context> labels;
@@ -147,6 +143,46 @@ struct mod_context {
bool operator!() const { return error.type != generator_error::Success; }
};
bool compare_types(const furvm::mod_type_h& lhs, const furvm::mod_type_h& rhs) const {
if (lhs->type != rhs->type) return false;
switch (lhs->type) {
case furvm::mod_type::S8:
case furvm::mod_type::S16:
case furvm::mod_type::S32:
case furvm::mod_type::S64:
case furvm::mod_type::U8:
case furvm::mod_type::U16:
case furvm::mod_type::U32:
case furvm::mod_type::U64: return true;
case furvm::mod_type::Ptr:
case furvm::mod_type::Ref:
return compare_types(mod.type_at(lhs->value.typeRef), mod.type_at(rhs->value.typeRef));
case furvm::mod_type::Array:
return lhs->value.array.size == rhs->value.array.size &&
compare_types(mod.type_at(lhs->value.array.typeId), mod.type_at(rhs->value.array.typeId));
case furvm::mod_type::Import:
return lhs->value.imprt.modId == rhs->value.imprt.modId &&
lhs->value.imprt.typeId == rhs->value.imprt.typeId;
case furvm::mod_type::Count: break;
}
throw std::runtime_error("unreachable");
}
furvm::function_h find_function(const std::string& name, const furvm::function_sig& signature) const {
if (auto it = functions.find(name); it != functions.end()) {
for (const auto& func : it->second) {
if (func->signature().params.size() != signature.params.size()) continue;
std::size_t idx = 0;
while (idx < signature.params.size()) {
if (!compare_types(func->signature().params[idx], signature.params[idx])) break;
++idx;
}
if (idx == signature.params.size()) return func;
}
}
return {};
}
mod_context() {
types.emplace("s8", mod.emplace_type(furvm::mod_type::S8));
types.emplace("u8", mod.emplace_type(furvm::mod_type::U8));
@@ -182,6 +218,44 @@ struct mod_context {
return { { generator_error::Success }, token.value };
}
furvm::mod_type_h eat_type(lexer& lexer, const token& tok) {
switch (tok.type) {
case token::Dolar: {
auto result = eat_token(lexer, token::Identifier);
if (auto it = types.find(std::string(result->value.string)); it != types.end()) {
return it->second;
}
throw std::runtime_error("unknown type");
}
case token::Import: {
throw std::runtime_error("unimplemented");
// auto typeNameRes = eat_token(lexer, token::Identifier);
// if (!typeNameRes) return typeNameRes.error;
// return { generator_error::Success };
}
case token::Ref: {
auto result = next_token(lexer);
if (!result) throw std::runtime_error("error");
auto inner = eat_type(lexer, result.value);
return mod.emplace_type(furvm::mod_type::Ref, inner.id());
}
case token::Array: {
auto result = next_token(lexer);
if (!result) throw std::runtime_error("error");
auto inner = eat_type(lexer, result.value);
auto size = eat_token(lexer, token::Unsigned);
if (!size) throw std::runtime_error("error");
return mod.emplace_type(inner.id(), size->value.uint);
}
default: throw std::runtime_error("error");
}
}
generator_error generate(lexer& lexer) {
auto result = next_token(lexer);
if (result.error.type == generator_error::UnexpectedEof) return { generator_error::Eof };
@@ -203,8 +277,7 @@ struct mod_context {
(func.pub ? mod.emplace_function(func.name, std::move(func.signature), label.offset)
: mod.emplace_function(std::move(func.signature), label.offset));
functions.emplace(std::make_pair(std::move(func.name), std::move(func.signature)), handle);
functions[std::move(func.name)].push_back(handle);
handle.dispatch();
}
for (auto unknown : label.unknowns) {
@@ -251,14 +324,8 @@ struct mod_context {
result = next_token(lexer);
if (!result) return result.error;
while (result->type == token::Dolar) {
result = eat_token(lexer, token::Identifier);
if (!result) return result.error;
if (auto it = types.find(std::string(result->value.string)); it != types.end()) {
signature.params.push_back(it->second);
} else {
return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) };
}
while (result->type != token::EqSign) {
signature.params.push_back(eat_type(lexer, result.value));
result = next_token(lexer);
if (!result) return result.error;
@@ -280,13 +347,15 @@ struct mod_context {
if (!result) return result.error;
}
std::string name = std::string(nameRes->value.string);
if (!find_function(name, signature).empty()) throw std::runtime_error("function already defined");
switch (result->type) {
case token::Sha256: {
result = eat_token(lexer, token::Identifier);
if (!result) return result.error;
std::string name = std::string(nameRes->value.string);
std::string labelName = std::string(result->value.string);
std::size_t offset = 0;
if (auto it = labels.find(labelName); it != labels.end()) {
@@ -299,10 +368,9 @@ struct mod_context {
furvm::function_h handle =
(pub ? mod.emplace_function(name, signature, offset) : mod.emplace_function(signature, offset));
functions.emplace(std::make_pair(name, std::move(signature)), handle);
functions[name].push_back(handle);
handle.dispatch();
return { generator_error::Success };
}
case token::Native: {
@@ -315,10 +383,9 @@ struct mod_context {
furvm::function_h handle = (pub ? mod.emplace_function(name, signature, std::move(nativeName))
: mod.emplace_function(signature, std::move(nativeName)));
functions.emplace(std::make_pair(name, std::move(signature)), handle);
functions[name].push_back(handle);
handle.dispatch();
return { generator_error::Success };
}
case token::Import: {
@@ -340,41 +407,10 @@ struct mod_context {
result = next_token(lexer);
if (!result) return result.error;
switch (result->type) {
case token::Import: {
auto typeNameRes = eat_token(lexer, token::Identifier);
if (!typeNameRes) return typeNameRes.error;
return { generator_error::Success };
}
case token::Array: {
result = eat_token(lexer, token::Dolar);
if (!result) return result.error;
auto typeNameRes = eat_token(lexer, token::Identifier);
if (!typeNameRes) return typeNameRes.error;
auto size = eat_token(lexer, token::Unsigned);
if (!size) return size.error;
furvm::mod_type_id innerId = 0;
if (auto it = types.find(std::string(typeNameRes->value.string)); it != types.end()) {
innerId = it->second.id();
} else {
return { generator_error::UnknownType,
"Unknown type "s + std::string(typeNameRes->value.string) };
}
auto type = mod.emplace_type(innerId, size->value.uint);
types.emplace(std::string(nameRes->value.string), type);
type.dispatch();
return { generator_error::Success };
}
default:
return { generator_error::UnexpectedToken,
"Unexpected token "s + token_type(result->type) +
", expected either type, `import`, or `array`" };
}
auto type = eat_type(lexer, result.value);
types.emplace(std::string(nameRes->value.string), std::move(type));
return { generator_error::Success };
}
return { generator_error::UnexpectedToken,
@@ -450,6 +486,8 @@ struct mod_context {
case token::Lenof:
case token::Load:
case token::Store:
case token::LoadGlobal:
case token::StoreGlobal:
case token::Call:
case token::Jmp:
case token::Jnz:
@@ -493,22 +531,16 @@ struct mod_context {
case furvm::instruction_argument::Function: {
furvm::function_sig signature;
while ((result = next_token(lexer)).error.type == generator_error::Success &&
result->type == token::Dolar) {
result = eat_token(lexer, token::Identifier);
if (!result) return result.error;
auto type = types.find(std::string(result->value.string));
if (type == types.end())
return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) };
signature.params.push_back(type->second);
result->type != token::Identifier) {
signature.params.push_back(eat_type(lexer, result.value));
}
if (!result || result->type != token::Identifier) return result.error;
std::string name(result->value.string);
auto func = functions.find(std::make_pair(name, signature));
if (func == functions.end())
return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) };
auto id = func->second.id();
instr.arg.u16 = id;
auto func = find_function(name, signature);
if (func.empty())
return { generator_error::UnknownType, "Unknown function "s + std::string(result->value.string) };
instr.arg.u16 = func.id();
} break;
case furvm::instruction_argument::Offset: {
result = eat_token(lexer, token::Sha256);
+2
View File
@@ -173,6 +173,8 @@ private:
thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const;
thing<> make_reference(const thing<>& thing) const;
private:
static bool compare_thing_types(const thing_type& lhs, const thing_type& rhs);
private:
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
context* m_context;
+25 -2
View File
@@ -33,12 +33,14 @@ thing_type executor::thing_type_impl(mod_h mod, mod_type type) const {
case thing_type::U32:
case thing_type::U64: return { static_cast<enum thing_type::type>(type.type) };
case thing_type::Ptr: return { thing_type::Ptr, mod_to_thing_type(mod, *mod->type_at(type.value.typeRef)) };
case thing_type::Ref: return { thing_type::Ref, mod_to_thing_type(mod, *mod->type_at(type.value.typeRef)) };
case thing_type::Array: {
return { static_cast<enum thing_type::type>(type.type),
{ mod_to_thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } };
}
default: throw std::runtime_error("invalid thing type");
case thing_type::Count: break;
}
throw std::runtime_error("invalid thing type");
}
thing_type* executor::mod_to_thing_type(const mod_h& mod, const mod_type& type) const {
@@ -53,6 +55,27 @@ thing<> executor::make_reference(const thing<>& thing) const {
return std::move(ref);
}
bool executor::compare_thing_types(const thing_type& lhs, const thing_type& rhs) {
if (lhs.type != rhs.type) return false;
switch (lhs.type) {
case thing_type::S8:
case thing_type::S16:
case thing_type::S32:
case thing_type::S64:
case thing_type::U8:
case thing_type::U16:
case thing_type::U32:
case thing_type::U64: return true;
case thing_type::Ptr:
case thing_type::Ref: return compare_thing_types(*lhs.value.typeRef, *rhs.value.typeRef);
case thing_type::Array:
return lhs.value.array.size == rhs.value.array.size &&
compare_thing_types(*lhs.value.array.type, *rhs.value.array.type);
case thing_type::Count: break;
}
throw std::runtime_error("unreachable");
}
void executor::push_frame(const mod_h& mod, function function) {
mod_h modInst = mod;
while (function.type() == function_t::Import) {
@@ -65,7 +88,7 @@ void executor::push_frame(const mod_h& mod, function function) {
args.reserve(signature.params.size());
for (const auto& param : signature.params) {
auto arg = pop_thing();
if (arg.true_type() != *mod_to_thing_type(mod, *param))
if (compare_thing_types(arg.type(), *mod_to_thing_type(mod, *param)))
throw std::runtime_error("function argument type mismatch");
args.push_back(std::move(arg));
}