fix call stuff
This commit is contained in:
parent
d9d08dc2ed
commit
18eddd82a4
@ -50,85 +50,16 @@ export const Builtins = {
|
||||
ArrayLength: 0x24,
|
||||
StructSet: 0x30,
|
||||
Print: 0x40,
|
||||
|
||||
} as const;
|
||||
|
||||
export function opToString(op: number): string {
|
||||
switch (op) {
|
||||
case Ops.Nop:
|
||||
return "Nop";
|
||||
case Ops.PushNull:
|
||||
return "PushNull";
|
||||
case Ops.PushInt:
|
||||
return "PushInt";
|
||||
case Ops.PushBool:
|
||||
return "PushBool";
|
||||
case Ops.PushString:
|
||||
return "PushString";
|
||||
case Ops.PushPtr:
|
||||
return "PushPtr";
|
||||
case Ops.Pop:
|
||||
return "Pop";
|
||||
case Ops.ReserveStatic:
|
||||
return "ReserveStatic";
|
||||
case Ops.LoadStatic:
|
||||
return "LoadStatic";
|
||||
case Ops.StoreStatic:
|
||||
return "StoreStatic";
|
||||
case Ops.LoadLocal:
|
||||
return "LoadLocal";
|
||||
case Ops.StoreLocal:
|
||||
return "StoreLocal";
|
||||
case Ops.Call:
|
||||
return "Call";
|
||||
case Ops.Return:
|
||||
return "Return";
|
||||
case Ops.Jump:
|
||||
return "Jump";
|
||||
case Ops.JumpIfTrue:
|
||||
return "JumpIfTrue";
|
||||
case Ops.Builtin:
|
||||
return "Builtin";
|
||||
case Ops.Add:
|
||||
return "Add";
|
||||
case Ops.Subtract:
|
||||
return "Subtract";
|
||||
case Ops.Multiply:
|
||||
return "Multiply";
|
||||
case Ops.Divide:
|
||||
return "Divide";
|
||||
case Ops.Remainder:
|
||||
return "Remainder";
|
||||
case Ops.Equal:
|
||||
return "Equal";
|
||||
case Ops.LessThan:
|
||||
return "LessThan";
|
||||
case Ops.And:
|
||||
return "And";
|
||||
case Ops.Or:
|
||||
return "Or";
|
||||
case Ops.Xor:
|
||||
return "Xor";
|
||||
case Ops.Not:
|
||||
return "Not";
|
||||
case Ops.SourceMap:
|
||||
return "SourceMap";
|
||||
default:
|
||||
return `<unknown Op ${op}>`;
|
||||
}
|
||||
return Object.entries(Ops)
|
||||
.find(([_key, value]) => value === op)
|
||||
?.[0] ?? `<unknown Op ${op}>`;
|
||||
}
|
||||
|
||||
export function builtinToString(builtin: number): string {
|
||||
switch (builtin) {
|
||||
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}>`;
|
||||
}
|
||||
return Object.entries(Builtins)
|
||||
.find(([_key, value]) => value === builtin)
|
||||
?.[0] ?? `<unknown Builtin ${builtin}>`;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export class Reporter {
|
||||
|
||||
private printReport({ reporter, type, pos, msg }: Report) {
|
||||
console.error(
|
||||
`${reporter}: ${type}: ${msg}${
|
||||
`${reporter} ${type}: ${msg}${
|
||||
pos ? ` at ${pos.line}:${pos.col}` : ""
|
||||
}`,
|
||||
);
|
||||
|
@ -113,7 +113,8 @@ export class Lowerer {
|
||||
if (stmt.kind.expr) {
|
||||
this.lowerExpr(stmt.kind.expr);
|
||||
}
|
||||
this.program.add(Ops.Jump, this.breakStack.at(-1)!);
|
||||
this.program.add(Ops.PushPtr, this.breakStack.at(-1)!);
|
||||
this.program.add(Ops.Jump);
|
||||
}
|
||||
|
||||
private lowerBuiltinAnno(annoArgs: Expr[]) {
|
||||
@ -127,49 +128,15 @@ export class Lowerer {
|
||||
);
|
||||
}
|
||||
const value = anno.kind.value;
|
||||
switch (value) {
|
||||
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}'`,
|
||||
);
|
||||
}
|
||||
const builtin = Object.entries(Builtins).find((entry) =>
|
||||
entry[0] === value
|
||||
)?.[1];
|
||||
if (builtin === undefined) {
|
||||
throw new Error(
|
||||
`unrecognized builtin '${value}'`,
|
||||
);
|
||||
}
|
||||
this.program.add(Ops.Builtin, builtin);
|
||||
}
|
||||
|
||||
private lowerFnStmt(stmt: Stmt) {
|
||||
@ -238,7 +205,7 @@ export class Lowerer {
|
||||
case "ident":
|
||||
break;
|
||||
case "group":
|
||||
break;
|
||||
return void this.lowerExpr(expr.kind.expr);
|
||||
case "field":
|
||||
break;
|
||||
case "index":
|
||||
@ -246,7 +213,7 @@ export class Lowerer {
|
||||
case "call":
|
||||
return this.lowerCallExpr(expr);
|
||||
case "unary":
|
||||
break;
|
||||
return this.lowerUnaryExpr(expr);
|
||||
case "binary":
|
||||
return this.lowerBinaryExpr(expr);
|
||||
case "if":
|
||||
@ -299,6 +266,28 @@ export class Lowerer {
|
||||
this.program.add(Ops.PushString, expr.kind.value);
|
||||
}
|
||||
|
||||
private lowerUnaryExpr(expr: Expr) {
|
||||
if (expr.kind.type !== "unary") {
|
||||
throw new Error();
|
||||
}
|
||||
this.lowerExpr(expr.kind.subject);
|
||||
const vtype = expr.kind.subject.vtype!;
|
||||
if (vtype.type === "bool") {
|
||||
switch (expr.kind.unaryType) {
|
||||
case "not":
|
||||
this.program.add(Ops.Not);
|
||||
return;
|
||||
default:
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`unhandled unary` +
|
||||
` '${vtypeToString(expr.vtype!)}' aka. ` +
|
||||
` ${expr.kind.unaryType}` +
|
||||
` '${vtypeToString(expr.kind.subject.vtype!)}'`,
|
||||
);
|
||||
}
|
||||
|
||||
private lowerBinaryExpr(expr: Expr) {
|
||||
if (expr.kind.type !== "binary") {
|
||||
throw new Error();
|
||||
@ -320,6 +309,9 @@ export class Lowerer {
|
||||
case "==":
|
||||
this.program.add(Ops.Equal);
|
||||
return;
|
||||
case "<":
|
||||
this.program.add(Ops.LessThan);
|
||||
return;
|
||||
case ">=":
|
||||
this.program.add(Ops.LessThan);
|
||||
this.program.add(Ops.Not);
|
||||
@ -403,7 +395,8 @@ export class Lowerer {
|
||||
|
||||
this.program.setLabel(contineLabel);
|
||||
this.lowerExpr(expr.kind.body);
|
||||
this.program.add(Ops.PushPtr, breakLabel);
|
||||
this.program.add(Ops.Pop);
|
||||
this.program.add(Ops.PushPtr, contineLabel);
|
||||
this.program.add(Ops.Jump);
|
||||
this.program.setLabel(breakLabel);
|
||||
if (expr.vtype!.type === "null") {
|
||||
|
@ -1,19 +1,16 @@
|
||||
|
||||
fn array_new_string() -> [string] #[builtin(ArrayNew)] {}
|
||||
|
||||
fn print(msg: string) #[builtin(Print)] {}
|
||||
fn println(msg: string) { print(msg + "\n") }
|
||||
|
||||
fn array_push_string(array: [string], str: string) #[builtin(ArrayPush)] {}
|
||||
|
||||
fn string_push_char(str: string, value: int) #[builtin(StringPushChar)] {}
|
||||
|
||||
fn string_push_char(str: string, value: int) -> string #[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 array_new_string() -> [string] #[builtin(ArrayNew)] {}
|
||||
fn array_push_string(array: [string], value: string) #[builtin(ArrayPush)] {}
|
||||
fn array_length_string(array: [string]) -> int #[builtin(ArrayLength)] {}
|
||||
fn array_at_string(array: [string], index: int) -> string #[builtin(ArrayAt)] {}
|
||||
|
||||
fn char(ch: string) -> int {
|
||||
string_char_at(ch, 0)
|
||||
@ -25,6 +22,9 @@ fn split(str: string, seperator: int) -> [string] {
|
||||
let i = 0;
|
||||
let current_str = "";
|
||||
loop {
|
||||
if i >= string_length(str) {
|
||||
break;
|
||||
}
|
||||
let char = string_char_at(str, i);
|
||||
if char == seperator {
|
||||
array_push_string(result, current_str);
|
||||
@ -32,9 +32,6 @@ fn split(str: string, seperator: int) -> [string] {
|
||||
} else {
|
||||
string_push_char(current_str, char);
|
||||
}
|
||||
if string_length(str) - 1 == i {
|
||||
break;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
result
|
||||
@ -43,11 +40,13 @@ fn split(str: string, seperator: int) -> [string] {
|
||||
fn main() {
|
||||
let array = split("aoisfjasoifjsaiofjsa", char("a"));
|
||||
let i = 0;
|
||||
let array_length = array_length_string(array);
|
||||
loop {
|
||||
print(array_string_at(array, i) + "\n");
|
||||
i = i + 1;
|
||||
if array_string_length(array) - 1 == i {
|
||||
if i >= array_length {
|
||||
break;
|
||||
}
|
||||
let v = array_at_string(array, 0);
|
||||
println(v);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
25
examples/string_int_args.slg
Normal file
25
examples/string_int_args.slg
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
fn print(msg: string) #[builtin(Print)] {}
|
||||
|
||||
fn repeat(value: string, amount: int) -> string {
|
||||
let result = "";
|
||||
|
||||
let i = 0;
|
||||
loop {
|
||||
if not (i < amount) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = result + value;
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let value = repeat("hello world\n", 3);
|
||||
print(value);
|
||||
}
|
||||
|
140
runtime/vm.cpp
140
runtime/vm.cpp
@ -30,8 +30,13 @@ void VM::run_n_instructions(size_t amount)
|
||||
void VM::run_instruction()
|
||||
{
|
||||
if (this->opts.print_stack_debug) {
|
||||
// std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc,
|
||||
// maybe_op_to_string(this->program[this->pc]),
|
||||
// stack_repr_string(8));
|
||||
auto stack_frame_size = this->stack.size() - this->bp;
|
||||
std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc,
|
||||
maybe_op_to_string(this->program[this->pc]), stack_repr_string(8));
|
||||
maybe_op_to_string(this->program[this->pc]),
|
||||
stack_repr_string(stack_frame_size));
|
||||
}
|
||||
auto op = eat_op();
|
||||
switch (op) {
|
||||
@ -125,11 +130,9 @@ 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 = 0; i < arguments.size(); ++i) {
|
||||
stack_push(std::move(arguments.at(i)));
|
||||
for (auto&& arg = arguments.rbegin(); arg != arguments.rend();
|
||||
++arg) {
|
||||
stack_push(*arg);
|
||||
}
|
||||
if (this->opts.flame_graph) {
|
||||
this->flame_graph.report_call(
|
||||
@ -277,20 +280,57 @@ void VM::run_instruction()
|
||||
|
||||
void VM::run_builtin(Builtin builtin_id)
|
||||
{
|
||||
if (this->opts.print_stack_debug) {
|
||||
std::cout << std::format(
|
||||
"Running builtin {}\n", static_cast<uint32_t>(builtin_id));
|
||||
}
|
||||
switch (builtin_id) {
|
||||
case Builtin::StringConcat: {
|
||||
assert_stack_has(2);
|
||||
auto left = stack_pop();
|
||||
auto right = stack_pop();
|
||||
auto left = stack_pop();
|
||||
stack_push(
|
||||
String(right.as_string().value + left.as_string().value));
|
||||
String(left.as_string().value + right.as_string().value));
|
||||
break;
|
||||
}
|
||||
case Builtin::StringEqual: {
|
||||
assert_stack_has(2);
|
||||
auto left = stack_pop();
|
||||
auto right = stack_pop();
|
||||
stack_push(Bool(right.as_string().value == left.as_string().value));
|
||||
auto left = stack_pop();
|
||||
stack_push(Bool(left.as_string().value == right.as_string().value));
|
||||
break;
|
||||
}
|
||||
case Builtin::StringCharAt: {
|
||||
assert_stack_has(2);
|
||||
auto index_value = stack_pop();
|
||||
auto str = 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 ch = stack_pop();
|
||||
auto str = 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::ArraySet: {
|
||||
@ -299,6 +339,32 @@ void VM::run_builtin(Builtin builtin_id)
|
||||
std::exit(1);
|
||||
break;
|
||||
}
|
||||
case Builtin::ArrayPush: {
|
||||
assert_stack_has(2);
|
||||
auto value = stack_pop();
|
||||
auto array_ptr = stack_pop().as_ptr().value;
|
||||
|
||||
this->heap.at(array_ptr).val()->as_array().values.push_back(value);
|
||||
stack_push(Null());
|
||||
break;
|
||||
}
|
||||
case Builtin::ArrayAt: {
|
||||
assert_stack_has(2);
|
||||
auto index = stack_pop().as_int().value;
|
||||
auto array_ptr = stack_pop().as_ptr().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;
|
||||
}
|
||||
case Builtin::StructSet: {
|
||||
assert_stack_has(2);
|
||||
std::cerr << std::format("not implemented\n");
|
||||
@ -312,59 +378,5 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,8 +185,8 @@ public:
|
||||
result += std::format(
|
||||
"{:<11}", stack[stack.size() - i - 1].to_repr_string());
|
||||
}
|
||||
if (stack.size() >= max_items) {
|
||||
result += std::format(" ... + {}", stack.size() - max_items + 1);
|
||||
if (stack.size() > max_items) {
|
||||
result += std::format(" ... + {}", stack.size() - max_items);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user