refactor interpreter to new file
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import React, { useEffect, useState } from "react"
|
import React, { useEffect, useRef, useState } from "react"
|
||||||
import { Card, CardContent, Grid, IconButton, TextField, Typography } from "@mui/material"
|
import { Card, CardContent, Grid, IconButton, TextField, Typography } from "@mui/material"
|
||||||
import instructions, { Instruction } from "../instructions"
|
import { Instruction } from "../instructions"
|
||||||
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight"
|
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight"
|
||||||
|
import PlayArrowIcon from "@mui/icons-material/PlayArrow"
|
||||||
|
import StopIcon from "@mui/icons-material/Stop"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BOARD_HEIGHT,
|
BOARD_HEIGHT,
|
||||||
BOARD_WIDTH,
|
BOARD_WIDTH,
|
||||||
@@ -10,40 +13,28 @@ import {
|
|||||||
SIDEBAR_WIDTH,
|
SIDEBAR_WIDTH,
|
||||||
TILE_SIZE
|
TILE_SIZE
|
||||||
} from "../const"
|
} from "../const"
|
||||||
|
import { iterate, newProgram, ProgramState, resetProgram } from "../interpreter"
|
||||||
// considering renaming this to vector
|
|
||||||
interface Point {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const Direction = {
|
|
||||||
Up: { x: 0, y: -1 },
|
|
||||||
Right: { x: 1, y: 0 },
|
|
||||||
Left: { x: -1, y: 0 },
|
|
||||||
Down: { x: 0, y: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
function Board() {
|
function Board() {
|
||||||
let key = 0
|
let key = 0
|
||||||
const [output, setOutput] = useState("")
|
|
||||||
const [done, setDone] = useState(true)
|
const [program, setProgram] = useState<ProgramState>(newProgram())
|
||||||
const [direction, setDirection] = useState<Point>(Direction.Right)
|
const [playing, setPlaying] = useState<boolean>(false)
|
||||||
const [programCounter, setProgramCounter] = useState<Point>({ x: -1, y: 0 })
|
|
||||||
const [board, setBoard] = useState<Instruction[][]>(
|
|
||||||
new Array(BOARD_HEIGHT)
|
|
||||||
.fill(0)
|
|
||||||
.map(() => new Array(BOARD_WIDTH).fill(0).map(() => structuredClone(instructions[0])))
|
|
||||||
)
|
|
||||||
let stringmode = false
|
|
||||||
const [stack, setStack] = useState<number[]>([])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (done) {
|
if (program.done) {
|
||||||
setProgramCounter({ x: -1, y: 0 })
|
const x = structuredClone(program)
|
||||||
setDirection(Direction.Right)
|
resetProgram(x)
|
||||||
|
x.done = false
|
||||||
|
setProgram(x)
|
||||||
}
|
}
|
||||||
}, [done])
|
}, [program])
|
||||||
|
|
||||||
|
const step = () => {
|
||||||
|
const x = structuredClone(program)
|
||||||
|
iterate(x)
|
||||||
|
setProgram(x)
|
||||||
|
}
|
||||||
|
|
||||||
const handleDrop = (
|
const handleDrop = (
|
||||||
col: number,
|
col: number,
|
||||||
@@ -51,16 +42,15 @@ function Board() {
|
|||||||
event: React.DragEvent<HTMLDivElement> | undefined
|
event: React.DragEvent<HTMLDivElement> | undefined
|
||||||
): void => {
|
): void => {
|
||||||
if (event === undefined) {
|
if (event === undefined) {
|
||||||
console.log("invalid drop target")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const data = JSON.parse(event.dataTransfer.getData("instruction")) as Instruction
|
const data = JSON.parse(event.dataTransfer.getData("instruction")) as Instruction
|
||||||
const x = [...board]
|
const x = structuredClone(program)
|
||||||
x[row][col] = data
|
x.board[row][col] = data
|
||||||
setBoard(x)
|
setProgram(x)
|
||||||
|
|
||||||
const target = event.target as HTMLInputElement
|
const target = event.target as HTMLInputElement
|
||||||
target.value = data.symbol
|
target.value = data.emoji
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnDragOver = (event: React.DragEvent<HTMLDivElement> | undefined) => {
|
const handleOnDragOver = (event: React.DragEvent<HTMLDivElement> | undefined) => {
|
||||||
@@ -68,175 +58,41 @@ function Board() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const safepop = (): number => {
|
const handleTextFieldChange = (
|
||||||
if (stack.length === 0) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const x = [...stack]
|
|
||||||
let result = x.pop()
|
|
||||||
setStack(x)
|
|
||||||
|
|
||||||
if (result === undefined) {
|
|
||||||
result = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
const iterate = () => {
|
|
||||||
setDone(false)
|
|
||||||
stepProgramCounter()
|
|
||||||
// This is asynchronous, the next line is run before program counter
|
|
||||||
// is updated. That is bad
|
|
||||||
console.log(board[programCounter.y][programCounter.x])
|
|
||||||
|
|
||||||
const cmd = board[programCounter.y][programCounter.x].ascii
|
|
||||||
let a: number
|
|
||||||
let b: number
|
|
||||||
|
|
||||||
if (stringmode && cmd !== '"') {
|
|
||||||
setStack([...stack, cmd.charCodeAt(0)])
|
|
||||||
} else if ("0123456789".includes(cmd)) {
|
|
||||||
setStack([...stack, +cmd])
|
|
||||||
} else {
|
|
||||||
switch (cmd) {
|
|
||||||
case "+":
|
|
||||||
stack.push(safepop() + safepop())
|
|
||||||
break
|
|
||||||
case "-":
|
|
||||||
stack.push(-safepop() + safepop())
|
|
||||||
break
|
|
||||||
case "*":
|
|
||||||
stack.push(safepop() * safepop())
|
|
||||||
break
|
|
||||||
case "/":
|
|
||||||
stack.push((1 / safepop()) * safepop())
|
|
||||||
break
|
|
||||||
case "%":
|
|
||||||
a = safepop()
|
|
||||||
b = safepop()
|
|
||||||
stack.push(b % a)
|
|
||||||
break
|
|
||||||
case "!":
|
|
||||||
stack.push(safepop() === 0 ? 1 : 0)
|
|
||||||
break
|
|
||||||
case "`":
|
|
||||||
stack.push(safepop() < safepop() ? 1 : 0)
|
|
||||||
break
|
|
||||||
case ">":
|
|
||||||
setDirection(Direction.Right)
|
|
||||||
break
|
|
||||||
case "<":
|
|
||||||
setDirection(Direction.Left)
|
|
||||||
break
|
|
||||||
case "^":
|
|
||||||
setDirection(Direction.Up)
|
|
||||||
break
|
|
||||||
case "v":
|
|
||||||
setDirection(Direction.Down)
|
|
||||||
break
|
|
||||||
case "?":
|
|
||||||
setDirection(
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
[Direction.Up, Direction.Down, Direction.Left, Direction.Right].at(
|
|
||||||
Math.floor(Math.random() * 4)
|
|
||||||
)!
|
|
||||||
)
|
|
||||||
break
|
|
||||||
case "_":
|
|
||||||
setDirection(safepop() === 0 ? Direction.Right : Direction.Left)
|
|
||||||
break
|
|
||||||
case "|":
|
|
||||||
setDirection(safepop() === 0 ? Direction.Down : Direction.Up)
|
|
||||||
break
|
|
||||||
case '"':
|
|
||||||
stringmode = !stringmode
|
|
||||||
break
|
|
||||||
case ":":
|
|
||||||
setStack([...stack, stack[stack.length - 1]])
|
|
||||||
break
|
|
||||||
case "\\":
|
|
||||||
swapTopStackValues()
|
|
||||||
break
|
|
||||||
case "$":
|
|
||||||
safepop()
|
|
||||||
break
|
|
||||||
case ".":
|
|
||||||
setOutput(output + safepop())
|
|
||||||
break
|
|
||||||
case ",":
|
|
||||||
setOutput(output + String.fromCharCode(safepop()))
|
|
||||||
break
|
|
||||||
case "#":
|
|
||||||
stepProgramCounter()
|
|
||||||
break
|
|
||||||
case "g":
|
|
||||||
a = safepop()
|
|
||||||
b = safepop()
|
|
||||||
setStack([...stack, board[b][a].ascii.charCodeAt(0)])
|
|
||||||
break
|
|
||||||
case "p":
|
|
||||||
// TODO
|
|
||||||
break
|
|
||||||
case "&":
|
|
||||||
// TODO
|
|
||||||
break
|
|
||||||
case "~":
|
|
||||||
// TODO
|
|
||||||
break
|
|
||||||
case "@":
|
|
||||||
setDone(true)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
console.log("unknown command:", cmd)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const stepProgramCounter = () => {
|
|
||||||
const tmp: Point = {
|
|
||||||
x: programCounter.x + direction.x,
|
|
||||||
y: programCounter.y + direction.y
|
|
||||||
}
|
|
||||||
if (tmp.x >= BOARD_WIDTH || tmp.x < 0 || tmp.y >= BOARD_HEIGHT || tmp.y < 0) {
|
|
||||||
setDone(true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setProgramCounter(tmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
const swapTopStackValues = () => {
|
|
||||||
const a = safepop()
|
|
||||||
const b = safepop()
|
|
||||||
setStack([...stack, a, b])
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleChange = (
|
|
||||||
col: number,
|
col: number,
|
||||||
row: number,
|
row: number,
|
||||||
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||||
) => {
|
) => {
|
||||||
const x = [...board]
|
const x = structuredClone(program)
|
||||||
x[row][col].symbol = event.target.value
|
x.board[row][col].emoji = event.target.value
|
||||||
setBoard(x)
|
x.board[row][col].bytecode = event.target.value
|
||||||
|
setProgram(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ marginLeft: `${SIDEBAR_WIDTH + 1}rem` }}>
|
<div style={{ marginLeft: `${SIDEBAR_WIDTH + 1}rem` }}>
|
||||||
{/* BUTTON PANEL */}
|
{/* BUTTON PANEL */}
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<IconButton onClick={() => iterate()}>
|
<Grid container>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<IconButton onClick={() => setPlaying(!playing)}>
|
||||||
|
{playing ? <StopIcon /> : <PlayArrowIcon />}
|
||||||
|
</IconButton>
|
||||||
|
<IconButton onClick={() => step()}>
|
||||||
<KeyboardDoubleArrowRightIcon />
|
<KeyboardDoubleArrowRightIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography>stack: {JSON.stringify(stack)}</Typography>
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<Typography>output: {program.output}</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<Typography>stack: {JSON.stringify(program.stack)}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* BOARD */}
|
{/* BOARD */}
|
||||||
{board.map((row, rowNo): JSX.Element => {
|
{program.board.map((row, rowNo): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Grid key={key++} container columns={BOARD_WIDTH} sx={{ width: `${5 * 12}rem` }}>
|
<Grid key={key++} container columns={BOARD_WIDTH} sx={{ width: `${5 * 12}rem` }}>
|
||||||
{row.map((tile, colNo): JSX.Element => {
|
{row.map((tile, colNo): JSX.Element => {
|
||||||
@@ -253,7 +109,8 @@ function Board() {
|
|||||||
width: `${TILE_SIZE}rem`,
|
width: `${TILE_SIZE}rem`,
|
||||||
margin: 1,
|
margin: 1,
|
||||||
bgcolor:
|
bgcolor:
|
||||||
rowNo === programCounter.y && colNo === programCounter.x
|
rowNo === program.instructionPointer.y &&
|
||||||
|
colNo === program.instructionPointer.x
|
||||||
? SELECTED_TILE_COLOR
|
? SELECTED_TILE_COLOR
|
||||||
: DEFAULT_TILE_COLOR
|
: DEFAULT_TILE_COLOR
|
||||||
}}>
|
}}>
|
||||||
@@ -261,8 +118,8 @@ function Board() {
|
|||||||
<TextField
|
<TextField
|
||||||
sx={{ mt: "10%" }}
|
sx={{ mt: "10%" }}
|
||||||
variant="standard"
|
variant="standard"
|
||||||
inputProps={{ maxLength: 1 }}
|
inputProps={{ maxLength: 1, style: { textAlign: "center" } }}
|
||||||
onChange={(event) => handleChange(colNo, rowNo, event)}
|
onChange={(event) => handleTextFieldChange(colNo, rowNo, event)}
|
||||||
onDragOver={handleOnDragOver}
|
onDragOver={handleOnDragOver}
|
||||||
onDrop={(event) => {
|
onDrop={(event) => {
|
||||||
handleDrop(colNo, rowNo, event)
|
handleDrop(colNo, rowNo, event)
|
||||||
|
|||||||
247
src/interpreter.tsx
Normal file
247
src/interpreter.tsx
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
import { BOARD_HEIGHT, BOARD_WIDTH } from "./const"
|
||||||
|
import instructions, { Instruction } from "./instructions"
|
||||||
|
|
||||||
|
export interface ProgramState {
|
||||||
|
instructionPointer: Point
|
||||||
|
direction: Point
|
||||||
|
stack: number[]
|
||||||
|
board: Instruction[][]
|
||||||
|
output: string
|
||||||
|
stringmode: boolean
|
||||||
|
done: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Point {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Direction = {
|
||||||
|
Up: { x: 0, y: -1 },
|
||||||
|
Right: { x: 1, y: 0 },
|
||||||
|
Left: { x: -1, y: 0 },
|
||||||
|
Down: { x: 0, y: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new program
|
||||||
|
* @returns new program object with initialized attributes
|
||||||
|
*/
|
||||||
|
export const newProgram = () => {
|
||||||
|
const program: ProgramState = {
|
||||||
|
instructionPointer: { x: 0, y: 0 },
|
||||||
|
direction: Direction.Right,
|
||||||
|
stack: [],
|
||||||
|
board: newBoard(),
|
||||||
|
output: "",
|
||||||
|
stringmode: false,
|
||||||
|
done: true
|
||||||
|
}
|
||||||
|
|
||||||
|
return program
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all program values to their default state
|
||||||
|
* @param program - program to be reset
|
||||||
|
*/
|
||||||
|
export const resetProgram = (program: ProgramState) => {
|
||||||
|
/*program.board.forEach((row) => {
|
||||||
|
row.forEach((tile) => {
|
||||||
|
tile.bytecode = instructions[0].bytecode
|
||||||
|
tile.description = instructions[0].description
|
||||||
|
tile.emoji = instructions[0].emoji
|
||||||
|
tile.name = instructions[0].name
|
||||||
|
tile.searchtags = instructions[0].searchtags
|
||||||
|
})
|
||||||
|
})*/
|
||||||
|
|
||||||
|
program.direction = Direction.Right
|
||||||
|
program.done = false
|
||||||
|
program.instructionPointer.x = 0
|
||||||
|
program.instructionPointer.y = 0
|
||||||
|
program.output = ""
|
||||||
|
program.stack.length = 0
|
||||||
|
program.stringmode = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a 2D array of instructions with all elements set to the NOOP instruction
|
||||||
|
* @returns Instruction[BOARD_HEIGHT][BOARD_WIDTH]
|
||||||
|
*/
|
||||||
|
export const newBoard = () => {
|
||||||
|
return new Array(BOARD_HEIGHT)
|
||||||
|
.fill(0)
|
||||||
|
.map(() => new Array(BOARD_WIDTH).fill(0).map(() => structuredClone(instructions[0])))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the last element from an array and returns it. If the array is empty it returns 0
|
||||||
|
* @param arr array to pop from
|
||||||
|
* @returns last element of array if array is non-empty, zero otherwise
|
||||||
|
*/
|
||||||
|
const safepop = (arr: number[]): number => {
|
||||||
|
const result = arr.pop()
|
||||||
|
|
||||||
|
if (result !== undefined) {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the instructionPointer of a program according to the programs direction attribute
|
||||||
|
* @param program program to increment its instruction pointer
|
||||||
|
*/
|
||||||
|
const step = (program: ProgramState) => {
|
||||||
|
program.instructionPointer.x += program.direction.x
|
||||||
|
program.instructionPointer.y += program.direction.y
|
||||||
|
|
||||||
|
if (
|
||||||
|
program.instructionPointer.x >= BOARD_WIDTH ||
|
||||||
|
program.instructionPointer.x < 0 ||
|
||||||
|
program.instructionPointer.y >= BOARD_HEIGHT ||
|
||||||
|
program.instructionPointer.y < 0
|
||||||
|
) {
|
||||||
|
console.log("pointer out of bounds, resetting program")
|
||||||
|
resetProgram(program)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the current instruction pointed at and executes it, then moves the instruction pointer
|
||||||
|
* according to the direction
|
||||||
|
* @param program program to iterate
|
||||||
|
* @see step()
|
||||||
|
* @see safepop()
|
||||||
|
*/
|
||||||
|
export const iterate = (program: ProgramState) => {
|
||||||
|
const cmd = program.board[program.instructionPointer.y][program.instructionPointer.x].bytecode
|
||||||
|
let a: number
|
||||||
|
let b: number
|
||||||
|
let maybeA: number | undefined
|
||||||
|
|
||||||
|
program.done = false
|
||||||
|
|
||||||
|
if (program.stringmode && cmd !== '"') {
|
||||||
|
program.stack.push(cmd.charCodeAt(0))
|
||||||
|
} else if ("0123456789".includes(cmd)) {
|
||||||
|
program.stack.push(+cmd)
|
||||||
|
} else {
|
||||||
|
switch (cmd) {
|
||||||
|
case " ":
|
||||||
|
break
|
||||||
|
case "+":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(a + b)
|
||||||
|
break
|
||||||
|
case "-":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(b - a)
|
||||||
|
break
|
||||||
|
case "*":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(a * b)
|
||||||
|
break
|
||||||
|
case "/":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(b / a)
|
||||||
|
break
|
||||||
|
case "%":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(b % a)
|
||||||
|
break
|
||||||
|
case "!":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
program.stack.push(a === 0 ? 1 : 0)
|
||||||
|
break
|
||||||
|
case "`":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(a < b ? 1 : 0)
|
||||||
|
break
|
||||||
|
case ">":
|
||||||
|
program.direction = Direction.Right
|
||||||
|
break
|
||||||
|
case "<":
|
||||||
|
program.direction = Direction.Left
|
||||||
|
break
|
||||||
|
case "^":
|
||||||
|
program.direction = Direction.Up
|
||||||
|
break
|
||||||
|
case "v":
|
||||||
|
program.direction = Direction.Down
|
||||||
|
break
|
||||||
|
case "?":
|
||||||
|
program.direction =
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
[Direction.Up, Direction.Down, Direction.Left, Direction.Right].at(
|
||||||
|
Math.floor(Math.random() * 4)
|
||||||
|
)!
|
||||||
|
break
|
||||||
|
case "_":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
program.direction = a === 0 ? Direction.Right : Direction.Left
|
||||||
|
break
|
||||||
|
case "|":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
program.direction = a === 0 ? Direction.Down : Direction.Up
|
||||||
|
break
|
||||||
|
case '"':
|
||||||
|
program.stringmode = !program.stringmode
|
||||||
|
break
|
||||||
|
case ":":
|
||||||
|
maybeA = program.stack.at(-1)
|
||||||
|
if (maybeA !== undefined) {
|
||||||
|
program.stack.push(maybeA)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "\\":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(b, a)
|
||||||
|
break
|
||||||
|
case "$":
|
||||||
|
safepop(program.stack)
|
||||||
|
break
|
||||||
|
case ".":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
program.output += a
|
||||||
|
break
|
||||||
|
case ",":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
program.output += String.fromCharCode(a)
|
||||||
|
break
|
||||||
|
case "#":
|
||||||
|
step(program)
|
||||||
|
break
|
||||||
|
case "g":
|
||||||
|
a = safepop(program.stack)
|
||||||
|
b = safepop(program.stack)
|
||||||
|
program.stack.push(program.board[b][a].bytecode.charCodeAt(0))
|
||||||
|
break
|
||||||
|
case "p":
|
||||||
|
// TODO
|
||||||
|
break
|
||||||
|
case "&":
|
||||||
|
// TODO
|
||||||
|
break
|
||||||
|
case "~":
|
||||||
|
// TODO
|
||||||
|
break
|
||||||
|
case "@":
|
||||||
|
program.done = true
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
step(program)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user