Finish thp code DSL basic implementation
This commit is contained in:
parent
838bd233ac
commit
957921b793
@ -1,5 +1,7 @@
|
||||
---
|
||||
import { lex } from "../lexer/lexer";
|
||||
import type { Instruction } from "../thp_machine/machine_parser";
|
||||
import { parse_str } from "../thp_machine/machine_parser";
|
||||
const {code, steps} = Astro.props;
|
||||
|
||||
/**
|
||||
@ -97,6 +99,15 @@ function highlightCode(lines: Array<string>): string {
|
||||
}
|
||||
|
||||
const codeHtml = highlightCode(trimAndDedent(code));
|
||||
let instructionSet: Array<Array<Instruction>>;
|
||||
try {
|
||||
instructionSet = parse_str(steps);
|
||||
} catch (e) {
|
||||
console.error(Astro.url);
|
||||
throw e;
|
||||
}
|
||||
|
||||
const serialized_inst = JSON.stringify(instructionSet);
|
||||
---
|
||||
|
||||
<div class="bg-black text-white rounded px-1"
|
||||
@ -104,7 +115,7 @@ const codeHtml = highlightCode(trimAndDedent(code));
|
||||
line: 0,
|
||||
stdout: "",
|
||||
ip: 0,
|
||||
inst: ${steps},
|
||||
inst: ${serialized_inst},
|
||||
done: false,
|
||||
state: {},
|
||||
}`}
|
||||
@ -138,12 +149,13 @@ const codeHtml = highlightCode(trimAndDedent(code));
|
||||
</div>
|
||||
|
||||
<script>
|
||||
type Instruction = "line" | "out" | "set" | "unset";
|
||||
import { InstructionType, type Instruction } from "../thp_machine/machine_parser";
|
||||
|
||||
type AlpineState = {
|
||||
line: number,
|
||||
stdout: string,
|
||||
ip: number,
|
||||
inst: Array<Array<[Instruction, string, string | undefined]>>
|
||||
inst: Array<Array<Instruction>>
|
||||
done: boolean,
|
||||
state: {[key: string]: string},
|
||||
}
|
||||
@ -156,22 +168,25 @@ const codeHtml = highlightCode(trimAndDedent(code));
|
||||
|
||||
const instructions = data.inst[ip]!;
|
||||
for (const instructionSet of instructions) {
|
||||
const instructionArr = instructionSet;
|
||||
switch (instructionArr[0]) {
|
||||
case "line": {
|
||||
data.line = Number(instructionArr[1]);
|
||||
const i = instructionSet;
|
||||
|
||||
switch (i.t) {
|
||||
case InstructionType.Line: {
|
||||
data.line = Number(i.v0);
|
||||
break;
|
||||
}
|
||||
case "out": {
|
||||
data.stdout += String(instructionArr[1])
|
||||
case InstructionType.Out: {
|
||||
data.stdout += i.v0
|
||||
break;
|
||||
}
|
||||
case "set": {
|
||||
data.state[String(instructionArr[1])] = String(instructionArr[2]);
|
||||
case InstructionType.Set: {
|
||||
const i_key = i.v0.slice(1, -1);
|
||||
const i_value = i.v1!.slice(1, -1);
|
||||
data.state[i_key] = i_value;
|
||||
break;
|
||||
}
|
||||
case "unset": {
|
||||
delete data.state[String(instructionArr[1])];
|
||||
case InstructionType.Unset: {
|
||||
delete data.state[i.v0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -83,101 +83,36 @@ Use a naked `try` when you want to rethrow an error, if there is any.
|
||||
val res1 = run() // First, without error
|
||||
val res2 = run() // Then, an example with error
|
||||
`}
|
||||
steps={`[
|
||||
[["line", 14]],
|
||||
[["line", 7]],
|
||||
[
|
||||
["line", 8],
|
||||
["set", "= = =", "run() = = = ="]
|
||||
],
|
||||
[
|
||||
["line", 10],
|
||||
["set", " dangerous()", "..."],
|
||||
],
|
||||
[["line", 1]],
|
||||
[
|
||||
["line", 2],
|
||||
["set", " = = =", "dangerous() = = = ="]
|
||||
],
|
||||
[["line", 3]],
|
||||
[
|
||||
["set", " Math.random()", "0.2"]
|
||||
],
|
||||
[
|
||||
["unset", " Math.random()"],
|
||||
["set", " return", "Int 50"]
|
||||
],
|
||||
[["line", 5]],
|
||||
[
|
||||
["line", 10],
|
||||
["unset", " return"],
|
||||
["unset", " = = ="],
|
||||
["set", " dangerous()", "Int 50"]
|
||||
],
|
||||
[
|
||||
["unset", " dangerous()"],
|
||||
["set", " Int result", "Int 50"]
|
||||
],
|
||||
[["line", 11]],
|
||||
[
|
||||
["line", 12],
|
||||
["out", "The result is 50\\n"],
|
||||
],
|
||||
[
|
||||
["line", 14],
|
||||
["unset", " Int result"],
|
||||
["unset", "= = ="],
|
||||
],
|
||||
[
|
||||
["line", 15],
|
||||
["set", "!Exception res1", "<empty>"],
|
||||
],
|
||||
|
||||
[["line", 7]],
|
||||
[
|
||||
["line", 8],
|
||||
["set", "= = =", "run() = = = ="]
|
||||
],
|
||||
[
|
||||
["line", 10],
|
||||
["set", " dangerous()", "..."],
|
||||
],
|
||||
[["line", 1]],
|
||||
[
|
||||
["line", 2],
|
||||
["set", " = = =", "dangerous() = = = ="],
|
||||
],
|
||||
[["line", 3]],
|
||||
[
|
||||
["set", " Math.random()", "0.9"],
|
||||
],
|
||||
[
|
||||
["line", "4"],
|
||||
["unset", " Math.random()"],
|
||||
["set", " return", "Exception(\\"Unlucky\\")"],
|
||||
],
|
||||
[["line", 5]],
|
||||
[
|
||||
["line", 10],
|
||||
["unset", " return"],
|
||||
["unset", " = = ="],
|
||||
["set", " dangerous()", "Exception \\"Unlucky\\""],
|
||||
],
|
||||
[
|
||||
["line", 12],
|
||||
["unset", " dangerous()"],
|
||||
["set", " return", "Exception(\\"Unlucky\\")"],
|
||||
],
|
||||
[
|
||||
["line", 15],
|
||||
["unset", " return"],
|
||||
["unset", "= = ="],
|
||||
],
|
||||
[
|
||||
["line", 16],
|
||||
["set", "!Exception res2", "Exception(\\"Unlucky\\")"],
|
||||
],
|
||||
]`}
|
||||
steps={`
|
||||
step { line 14 }
|
||||
step { line 7 }
|
||||
step {
|
||||
line 8
|
||||
set "= = =" "run() = = = ="
|
||||
}
|
||||
step {
|
||||
line 10
|
||||
set " dangerous()" "..."
|
||||
}
|
||||
step {line 1}
|
||||
step {
|
||||
line 2
|
||||
set " = = =" "dangerous() = = = ="
|
||||
}
|
||||
step {line 3}
|
||||
step {set " Math.random()" "0.2"}
|
||||
step {
|
||||
unset " Math.random()"
|
||||
set " return" "Int 50"
|
||||
}
|
||||
step {line 5}
|
||||
step {
|
||||
line 10
|
||||
unset " return"
|
||||
unset " = = ="
|
||||
set " dangerous()" "Int 50"
|
||||
}
|
||||
`}
|
||||
></InteractiveCode>
|
||||
|
||||
|
||||
|
@ -78,25 +78,25 @@ The documentation contains snippets of interactive THP code, like this:
|
||||
|
||||
f(x, y)
|
||||
`}
|
||||
steps={`[
|
||||
[["line", 1]],
|
||||
[
|
||||
["line", 2],
|
||||
["set", "String x", "\\"android\\""]
|
||||
],
|
||||
[
|
||||
["line", 8],
|
||||
["set", "Int y", "17"]
|
||||
],
|
||||
[["line", 4]],
|
||||
[["line", 5]],
|
||||
[
|
||||
["out", "hello, android 17"],
|
||||
["line", 6]
|
||||
],
|
||||
[["line", 8]],
|
||||
[["line", 0]]
|
||||
]`}
|
||||
steps={`
|
||||
step {line 1}
|
||||
step {
|
||||
line 2
|
||||
set "String x" "\\"android\\""
|
||||
}
|
||||
step {
|
||||
line 8
|
||||
set "Int y" "17"
|
||||
}
|
||||
step {line 4}
|
||||
step {line 5}
|
||||
step {
|
||||
out "hello, android 17"
|
||||
line 6
|
||||
}
|
||||
step {line 8}
|
||||
step {line 0}
|
||||
`}
|
||||
></InteractiveCode>
|
||||
|
||||
Use the `Step` and `Reset` buttons to emulate the execution of a
|
||||
|
@ -14,6 +14,7 @@ enum TokenType {
|
||||
Step,
|
||||
Line,
|
||||
Set,
|
||||
Out,
|
||||
Number,
|
||||
String,
|
||||
Unset,
|
||||
@ -96,6 +97,7 @@ function lex_word(input: Array<string>, pos: number): [Token, number] {
|
||||
else if (value === "line") { token_type = TokenType.Line; }
|
||||
else if (value === "set") { token_type = TokenType.Set; }
|
||||
else if (value === "unset"){ token_type = TokenType.Unset; }
|
||||
else if (value === "out") { token_type = TokenType.Out; }
|
||||
else
|
||||
{
|
||||
throw new Error(`Invalid word: ${value}`);
|
||||
@ -104,27 +106,40 @@ function lex_word(input: Array<string>, pos: number): [Token, number] {
|
||||
return [[token_type, value], next_p]
|
||||
}
|
||||
|
||||
enum InstructionType {
|
||||
export enum InstructionType {
|
||||
Line,
|
||||
Set,
|
||||
Unset,
|
||||
Out,
|
||||
}
|
||||
|
||||
type Instruction = {
|
||||
export type Instruction = {
|
||||
t: InstructionType,
|
||||
v0: string,
|
||||
v1?: string,
|
||||
}
|
||||
|
||||
export function parse_str(input: string): Array<Array<Instruction>> {
|
||||
return parse(lex(input));
|
||||
}
|
||||
|
||||
// Parses the tokens into a instruction set
|
||||
function parse(tokens: Array<Token>): Array<Array<Instruction>> {
|
||||
let pos = 0;
|
||||
let max = tokens.length;
|
||||
|
||||
return [];
|
||||
const ret = [];
|
||||
|
||||
while (pos < max) {
|
||||
const [steps, next_pos] = parse_step(tokens, pos);
|
||||
pos = next_pos;
|
||||
ret.push(steps);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function parse_step(tokens: Array<Token>, _pos: number): Array<Instruction> {
|
||||
function parse_step(tokens: Array<Token>, _pos: number): [Array<Instruction>, number] {
|
||||
let pos = _pos;
|
||||
|
||||
expect(tokens, pos, TokenType.Step, "expected step");
|
||||
@ -146,7 +161,7 @@ function parse_step(tokens: Array<Token>, _pos: number): Array<Instruction> {
|
||||
expect(tokens, pos, TokenType.BraceClose, "expected closing brace");
|
||||
pos += 1
|
||||
|
||||
return instructions;
|
||||
return [instructions, pos];
|
||||
}
|
||||
|
||||
function parse_instruction(tokens: Array<Token>, _pos: number): [Instruction|null, number] {
|
||||
@ -173,6 +188,22 @@ function parse_instruction(tokens: Array<Token>, _pos: number): [Instruction|nul
|
||||
v1: tokens[pos]![1]!,
|
||||
}, pos + 1]
|
||||
}
|
||||
else if (instruction_type === TokenType.Unset) {
|
||||
expect(tokens, pos + 1, TokenType.String, "expected a a string after the `unset` instruction");
|
||||
|
||||
return [{
|
||||
t: InstructionType.Unset,
|
||||
v0: tokens[pos + 1]![1]!,
|
||||
}, pos + 2]
|
||||
}
|
||||
else if (instruction_type === TokenType.Out) {
|
||||
expect(tokens, pos + 1, TokenType.String, "expected a a string after the `unset` instruction");
|
||||
|
||||
return [{
|
||||
t: InstructionType.Out,
|
||||
v0: tokens[pos + 1]![1]!,
|
||||
}, pos + 2]
|
||||
}
|
||||
|
||||
return [null, pos];
|
||||
}
|
||||
@ -180,9 +211,8 @@ function parse_instruction(tokens: Array<Token>, _pos: number): [Instruction|nul
|
||||
function expect(t: Array<Token>, pos: number, type: TokenType, err: string) {
|
||||
const [t_type] = t[pos]!;
|
||||
if (t_type !== type) {
|
||||
console.error(t[pos]);
|
||||
throw new Error(err);
|
||||
console.error("`" + String(t[pos]) + "`");
|
||||
throw new Error(err + " , got " + t[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(parse_step(lex(" step { line 20 set \"a\" \"b\" }"), 0))
|
||||
|
Loading…
Reference in New Issue
Block a user