buildins and other stuff

This commit is contained in:
Mikkel Kongsted 2024-12-12 16:07:59 +01:00
parent a7bf4ac701
commit d9d08dc2ed
14 changed files with 298 additions and 97 deletions

View File

@ -40,9 +40,17 @@ export type Builtins = typeof Builtins;
export const Builtins = {
StringConcat: 0x10,
StringEqual: 0x11,
ArraySet: 0x20,
StringCharAt: 0x12,
StringLength: 0x13,
StringPushChar: 0x14,
ArrayNew: 0x20,
ArraySet: 0x21,
ArrayPush: 0x22,
ArrayAt: 0x23,
ArrayLength: 0x24,
StructSet: 0x30,
Print: 0x40,
} as const;
export function opToString(op: number): string {
@ -112,16 +120,14 @@ export function opToString(op: number): string {
export function builtinToString(builtin: number): string {
switch (builtin) {
case Builtins.StringConcat:
return "StringConcat";
case Builtins.StringEqual:
return "StringEqual";
case Builtins.ArraySet:
return "ArraySet";
case Builtins.StructSet:
return "StructSet";
case Builtins.Print:
return "Print";
case Builtins.StringConcat: return "StringConcat";
case Builtins.StringEqual: return "StringEqual";
case Builtins.StringCharAt: return "StringCharAt";
case Builtins.StringLength: return "StringLength";
case Builtins.StringPushChar: return "StringPushChar";
case Builtins.ArraySet: return "ArraySet";
case Builtins.StructSet: return "StructSet";
case Builtins.Print: return "Print";
default:
return `<unknown Builtin ${builtin}>`;
}

View File

@ -114,7 +114,7 @@ export class Assembler {
}).join(", ");
console.log(`${ip.toString().padStart(8, " ")}: ${op} ${args}`);
ip += line.ins.map((lit) =>
typeof lit === "string" ? lit.length : 1
typeof lit === "string" ? lit.length + 1 : 1
).reduce((acc, curr) => acc + curr, 0);
}
}

View File

@ -119,16 +119,17 @@ export class Checker {
if (stmt.kind.vtype!.type !== "fn") {
throw new Error();
}
const { returnType } = stmt.kind.vtype!;
this.fnReturnStack.push(returnType);
const isBuiltin = stmt.kind.anno && stmt.kind.anno.ident === "builtin";
if (isBuiltin) {
stmt.kind.body.kind = { type: "block", stmts: [] };
return;
}
const body = this.checkExpr(stmt.kind.body);
const { returnType } = stmt.kind.vtype!;
this.fnReturnStack.push(returnType);
const body = this.checkExpr(stmt.kind.body);
this.fnReturnStack.pop();
if (!vtypesEqual(returnType, body)) {
this.report(
`incompatible return type` +

View File

@ -1,6 +1,7 @@
import { Reporter } from "./info.ts";
import { Pos, Token } from "./token.ts";
export class Lexer {
private index = 0;
private line = 1;

View File

@ -128,10 +128,42 @@ export class Lowerer {
}
const value = anno.kind.value;
switch (value) {
case "print": {
case "Print": {
this.program.add(Ops.Builtin, Builtins.Print);
break;
}
case "StringLength": {
this.program.add(Ops.Builtin, Builtins.StringLength);
break;
}
case "StringCharAt": {
this.program.add(Ops.Builtin, Builtins.StringCharAt);
break;
}
case "StringPushChar": {
this.program.add(Ops.Builtin, Builtins.StringPushChar);
break;
}
case "ArrayNew": {
this.program.add(Ops.Builtin, Builtins.ArrayNew);
break;
}
case "ArraySet": {
this.program.add(Ops.Builtin, Builtins.ArraySet);
break;
}
case "ArrayPush": {
this.program.add(Ops.Builtin, Builtins.ArrayPush);
break;
}
case "ArrayLength": {
this.program.add(Ops.Builtin, Builtins.ArrayLength);
break;
}
case "ArrayAt": {
this.program.add(Ops.Builtin, Builtins.ArrayAt);
break;
}
default: {
throw new Error(
`unrecognized builtin '${value}'`,
@ -279,6 +311,9 @@ export class Lowerer {
case "+":
this.program.add(Ops.Add);
return;
case "-":
this.program.add(Ops.Subtract);
return;
case "*":
this.program.add(Ops.Multiply);
return;

View File

@ -429,7 +429,7 @@ export class Parser {
left = this.parBinTail(left, pos, this.parseMulDiv, "+");
continue;
}
if (this.test(".")) {
if (this.test("-")) {
left = this.parBinTail(left, pos, this.parseMulDiv, "-");
continue;
}

53
examples/std.slg Normal file
View File

@ -0,0 +1,53 @@
fn array_new_string() -> [string] #[builtin(ArrayNew)] {}
fn print(msg: string) #[builtin(Print)] {}
fn array_push_string(array: [string], str: string) #[builtin(ArrayPush)] {}
fn string_push_char(str: string, value: int) #[builtin(StringPushChar)] {}
fn string_char_at(str: string, index: int) -> int #[builtin(StringCharAt)] {}
fn string_length(str: string) -> int #[builtin(StringLength)] {}
fn array_string_length(array: [string]) -> int #[builtin(StringLength)] {}
fn array_string_at(array: [string], index: int) -> string #[builtin(ArrayAt)] {}
fn char(ch: string) -> int {
string_char_at(ch, 0)
}
fn split(str: string, seperator: int) -> [string] {
let result: [string] = array_new_string();
let i = 0;
let current_str = "";
loop {
let char = string_char_at(str, i);
if char == seperator {
array_push_string(result, current_str);
current_str = "";
} else {
string_push_char(current_str, char);
}
if string_length(str) - 1 == i {
break;
}
i = i + 1;
}
result
}
fn main() {
let array = split("aoisfjasoifjsaiofjsa", char("a"));
let i = 0;
loop {
print(array_string_at(array, i) + "\n");
i = i + 1;
if array_string_length(array) - 1 == i {
break;
}
}
}

View File

@ -33,6 +33,10 @@ template <> struct AllocTypeType<AllocType::Struct> { using Type = Struct; };
// clang-format on
struct AllocItem {
AllocItem(Value&& val) : type(AllocType::Value), value(val) {}
AllocItem(Array&& val) : type(AllocType::Array), value(val) {}
AllocItem(Struct&& val) : type(AllocType::Struct), value(val) {}
template <AllocType AT> inline auto as() & -> AllocTypeType<AT>::Type&
{
return std::get<typename AllocTypeType<AT>::Type>(this->value);
@ -54,6 +58,26 @@ struct AllocItem {
std::get<typename AllocTypeType<AT>::Type>(this->value));
}
inline auto as_value() & -> Value& {
return std::get<Value>(this->value);
}
inline auto as_value() const & -> const Value& {
return std::get<Value>(this->value);
}
inline auto as_array() & -> Array& {
return std::get<Array>(this->value);
}
inline auto as_array() const & -> const Array& {
return std::get<Array>(this->value);
}
inline auto as_struct() & -> Struct& {
return std::get<Struct>(this->value);
}
inline auto as_struct() const & -> const Struct& {
return std::get<Struct>(this->value);
}
AllocType type;
std::variant<Value, Array, Struct> value;
};
@ -65,16 +89,23 @@ enum class ErrType {
template <typename T> struct Res {
Res(T val)
: val(std::forward<T>(val))
: m_val(std::forward<T>(val))
{
}
Res(ErrType err)
: err(err)
: m_err(err)
{
}
std::optional<T> val;
std::optional<ErrType> err;
auto ok() const -> bool { return m_val.has_value(); }
auto val() & -> T& { return m_val.value(); }
auto val() const& -> const T& { return m_val.value(); }
auto val() && -> T&& { return std::move(m_val.value()); }
auto val() const&& -> const T&& { return std::move(m_val.value()); }
auto err() -> ErrType { return m_err.value(); }
std::optional<T> m_val;
std::optional<ErrType> m_err;
};
class Heap {
@ -124,9 +155,9 @@ private:
inline void move_item_to_other(uint32_t ptr)
{
auto res = at(ptr);
if (!res.val.has_value())
if (!res.ok())
return;
auto val = res.val.value();
auto val = res.val();
switch (val->type) {
case AllocType::Value: {
auto& v = val->as<AllocType::Value>();

View File

@ -41,7 +41,14 @@ enum class Op : uint32_t {
enum class Builtin : uint32_t {
StringConcat = 0x10,
StringEqual = 0x11,
ArraySet = 0x20,
StringCharAt = 0x12,
StringLength = 0x13,
StringPushChar = 0x14,
ArrayNew = 0x20,
ArraySet = 0x21,
ArrayPush = 0x22,
ArrayAt = 0x23,
ArrayLength = 0x24,
StructSet = 0x30,
Print = 0x40,
};

View File

@ -170,36 +170,7 @@ enum class TokTyp {
Colon,
};
inline auto tok_typ_to_string(TokTyp typ) -> std::string
{
switch (typ) {
case TokTyp::Eof:
return "Eof";
case TokTyp::String:
return "String";
case TokTyp::Float:
return "Float";
case TokTyp::False:
return "False";
case TokTyp::True:
return "True";
case TokTyp::Null:
return "Null";
case TokTyp::LBrace:
return "LBrace";
case TokTyp::RBrace:
return "RBrace";
case TokTyp::LBracket:
return "LBracket";
case TokTyp::RBracket:
return "RBracket";
case TokTyp::Comma:
return "Comma";
case TokTyp::Colon:
return "Colon";
}
std::unreachable();
}
auto tok_typ_to_string(TokTyp typ) -> std::string;
struct Tok {
Tok(TokTyp typ, Pos pos)

View File

@ -9,7 +9,7 @@
#include <string>
#include <vector>
bool print_stack_debug = false;
bool print_stack_debug = true;
int execute_file_and_exit(std::string filename)
{

76
runtime/to_string.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "vm.hpp"
#include "json.hpp"
using namespace sliger;
auto sliger::maybe_op_to_string(uint32_t value) -> std::string
{
switch (static_cast<Op>(value)) {
/* clang-format off */
case Op::Nop: return "Nop";
case Op::PushNull: return "PushNull";
case Op::PushInt: return "PushInt";
case Op::PushBool: return "PushBool";
case Op::PushString: return "PushString";
case Op::PushPtr: return "PushPtr";
case Op::Pop: return "Pop";
case Op::ReserveStatic: return "ReserveStatic";
case Op::LoadStatic: return "LoadStatic";
case Op::StoreStatic: return "StoreStatic";
case Op::LoadLocal: return "LoadLocal";
case Op::StoreLocal: return "StoreLocal";
case Op::Call: return "Call";
case Op::Return: return "Return";
case Op::Jump: return "Jump";
case Op::JumpIfTrue: return "JumpIfTrue";
case Op::Builtin: return "Builtin";
case Op::Add: return "Add";
case Op::Subtract: return "Subtract";
case Op::Multiply: return "Multiply";
case Op::Divide: return "Divide";
case Op::Remainder: return "Remainder";
case Op::Equal: return "Equal";
case Op::LessThan: return "LessThan";
case Op::And: return "And";
case Op::Or: return "Or";
case Op::Xor: return "Xor";
case Op::Not: return "Not";
case Op::SourceMap: return "SourceMap";
/* clang-format on */
default:
return std::to_string(value);
}
}
auto json::tok_typ_to_string(json::TokTyp typ) -> std::string
{
using namespace json;
switch (typ) {
case TokTyp::Eof:
return "Eof";
case TokTyp::String:
return "String";
case TokTyp::Float:
return "Float";
case TokTyp::False:
return "False";
case TokTyp::True:
return "True";
case TokTyp::Null:
return "Null";
case TokTyp::LBrace:
return "LBrace";
case TokTyp::RBrace:
return "RBrace";
case TokTyp::LBracket:
return "LBracket";
case TokTyp::RBracket:
return "RBracket";
case TokTyp::Comma:
return "Comma";
case TokTyp::Colon:
return "Colon";
}
std::unreachable();
}

View File

@ -10,45 +10,6 @@
using namespace sliger;
inline auto maybe_op_to_string(uint32_t value) -> std::string
{
switch (static_cast<Op>(value)) {
/* clang-format off */
case Op::Nop: return "Nop";
case Op::PushNull: return "PushNull";
case Op::PushInt: return "PushInt";
case Op::PushBool: return "PushBool";
case Op::PushString: return "PushString";
case Op::PushPtr: return "PushPtr";
case Op::Pop: return "Pop";
case Op::ReserveStatic: return "ReserveStatic";
case Op::LoadStatic: return "LoadStatic";
case Op::StoreStatic: return "StoreStatic";
case Op::LoadLocal: return "LoadLocal";
case Op::StoreLocal: return "StoreLocal";
case Op::Call: return "Call";
case Op::Return: return "Return";
case Op::Jump: return "Jump";
case Op::JumpIfTrue: return "JumpIfTrue";
case Op::Builtin: return "Builtin";
case Op::Add: return "Add";
case Op::Subtract: return "Subtract";
case Op::Multiply: return "Multiply";
case Op::Divide: return "Divide";
case Op::Remainder: return "Remainder";
case Op::Equal: return "Equal";
case Op::LessThan: return "LessThan";
case Op::And: return "And";
case Op::Or: return "Or";
case Op::Xor: return "Xor";
case Op::Not: return "Not";
case Op::SourceMap: return "SourceMap";
/* clang-format on */
default:
return std::to_string(value);
}
}
void VM::run_until_done()
{
while (!done()) {
@ -164,8 +125,11 @@ void VM::run_instruction()
stack_push(Ptr { .value = this->bp });
this->pc = fn_ptr.as_ptr().value;
this->bp = static_cast<uint32_t>(this->stack.size());
for (size_t i = arguments.size(); i > 0; --i) {
stack_push(std::move(arguments.at(i - 1)));
// for (size_t i = arguments.size(); i > 0; --i) {
// stack_push(std::move(arguments.at(i - 1)));
// }
for (size_t i = 0; i < arguments.size(); ++i) {
stack_push(std::move(arguments.at(i)));
}
if (this->opts.flame_graph) {
this->flame_graph.report_call(
@ -348,5 +312,59 @@ void VM::run_builtin(Builtin builtin_id)
stack_push(Null());
break;
}
case Builtin::StringCharAt: {
assert_stack_has(2);
auto str = stack_pop();
auto index_value = stack_pop();
auto index = static_cast<size_t>(index_value.as_int().value);
auto ch = static_cast<int32_t>(str.as_string().value.at(index));
stack_push(Int(ch));
break;
}
case Builtin::StringLength: {
assert_stack_has(1);
auto str = stack_pop().as_string().value;
auto length = static_cast<int32_t>(str.length());
stack_push(Int(length));
break;
}
case Builtin::StringPushChar: {
assert_stack_has(2);
auto str = stack_pop();
auto ch = stack_pop();
auto new_str = std::string(str.as_string().value);
new_str.push_back(static_cast<char>(ch.as_int().value));
stack_push(String(new_str));
break;
}
case Builtin::ArrayNew: {
auto alloc_res = this->heap.alloc<heap::AllocType::Array>();
stack_push(Ptr(alloc_res.val()));
break;
}
case Builtin::ArrayPush: {
assert_stack_has(2);
auto array_ptr = stack_pop().as_ptr().value;
auto value = stack_pop();
auto array = this->heap.at(array_ptr).val()->as_array();
array.values.push_back(value);
stack_push(Null());
break;
}
case Builtin::ArrayAt: {
assert_stack_has(2);
auto array_ptr = stack_pop().as_ptr().value;
auto index = stack_pop().as_int().value;
auto array = this->heap.at(array_ptr).val()->as_array();
stack_push(array.values.at(static_cast<size_t>(index)));
break;
}
case Builtin::ArrayLength: {
assert_stack_has(1);
auto array_ptr = stack_pop().as_ptr().value;
auto array = this->heap.at(array_ptr).val()->as_array();
stack_push(Int(static_cast<int32_t>(array.values.size())));
break;
}
}
}

View File

@ -286,4 +286,6 @@ private:
CodeCoverageBuilder code_coverage;
};
auto maybe_op_to_string(uint32_t value) -> std::string;
}