add stuff to chapter 4

This commit is contained in:
Simon From Jakobsen 2024-10-03 14:10:53 +00:00
parent 1ad298acf5
commit cdf70dcf48

View File

@ -57,13 +57,47 @@ Lastly we'll define a type for built in functions.
```ts ```ts
type Value = type Value =
// ... // ...
| { type: "builtin_fn", action: BuiltInAction } | { type: "builtin_fn", name: string }
// ... // ...
type BuiltinAction = (...args: Value[]) => Value;
``` ```
A builtin function will have an action function, which takes a varying number of parameters and returns a value. A builtin function will have a name, which the evaluator will understand and treat accordingly.
### 4.2.1 Stringification
We'll need a way to represent values as text in strings.
```ts
function valueToString(value: Value): string {
if (value.type === "error") {
return "<error>";
} else if (value.type === "null") {
return "null";
} else if (value.type === "int") {
return value.value.toString();
} else if (value.type === "string") {
return `"${value.value}"`;
} else if (value.type === "bool") {
return value.value ? "true" : "false";
} else if (value.type === "array") {
const valueStrings = result.values
.map(value => value.toString());
return `[${valueStrings.join(", ")}]`;
} else if (value.type === "struct") {
const fieldStrings = Object.entries(result.fields)
.map(([key, value]) => `${key}: ${valueToString(value)}`);
return `struct { ${fieldStrings.join(", ")} }`;
} else if (value.type === "fn") {
return `<fn: ${value.fnDefId}>`;
} else if (value.type === "builtin_fn") {
return `<builtin_fn: ${value.name}>`;
} else {
throw new Error("unexhaustive");
}
}
```
The `valueToString` function takes a value (variable of type `Value`) and checks its type. For each type of value, it returns a string representing that value. For error and null we return a static string of `"<error>"` and `"null"` respectably. For the others, we return a string also representing the *value's value*, eg. for int, we return the int value as a string. For array and struct, we call `valueToString` recursively on the contained values.
## 4.2 Symbols ## 4.2 Symbols
@ -162,16 +196,7 @@ class Evaluator {
private root = new Syms(); private root = new Syms();
public withBuiltins(): Evaluator { public withBuiltins(): Evaluator {
this.root.define("println", (fmt, ...args) => { this.root.define("println", { type: "builtin_fn", name: "println" });
if (!fmt)
throw new Error("incorrect arguments");
let msg = fmt;
for (const arg of args) {
if (!msg.includes("{}"))
throw new Error("incorrect arguments");
msg.replace("{}", )
}
});
} }
public evalStmts(stmts: Stmt[]): Flow { public evalStmts(stmts: Stmt[]): Flow {
@ -183,8 +208,31 @@ class Evaluator {
} }
public evalExpr(expr: Expr): Flow { public evalExpr(expr: Expr): Flow {
// ...
} }
private executeBuiltin(name: string, args: Value[]): Flow {
if (name === "println") {
if (args.length < 1)
throw new Error("incorrect arguments");
let msg = args[0];
for (const arg of args.slice(1)) {
if (!msg.includes("{}"))
throw new Error("incorrect arguments");
msg.replace("{}", valueToString(arg));
}
console.log(msg);
return this.value(this.nullValue);
} else {
throw new Error("unknown builtin");
}
}
private value(value: Value): Flow { return { type: "value", value }; }
private readonly errorValue: Value = { type: "null" };
private readonly nullValue: Value = { type: "error" };
} }
``` ```