Compare commits
2 Commits
c841427eff
...
6737ed86b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
6737ed86b0
|
|||
|
4ede6f3476
|
+15
-3
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+101
-69
@@ -127,11 +127,7 @@ struct mod_context {
|
||||
};
|
||||
|
||||
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, 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;
|
||||
|
||||
@@ -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,42 +407,11 @@ 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;
|
||||
|
||||
auto type = eat_type(lexer, result.value);
|
||||
types.emplace(std::string(nameRes->value.string), std::move(type));
|
||||
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`" };
|
||||
}
|
||||
}
|
||||
|
||||
return { generator_error::UnexpectedToken,
|
||||
"Unexpected token "s + token_type(result->type) + ", expected either `func` or `type`" };
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user