JSFiddle - React, Tailwind, and code Playground
by Ben Gillbanks
HTML
<script src="https://unpkg.com/[email protected]/dist/ohm.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Logo-style Language Interpreter</title>
<script id="grammar" type="ohm/grammar">
Logo {
sourceCharacter = any
lineTerminator = "\n" | "\r" | "\u2028" | "\u2029"
whitespace = "\t"
| "\x0B" -- verticalTab
| "\x0C" -- formFeed
| " "
| "\u00A0" -- noBreakSpace
| "\uFEFF" -- byteOrderMark
| unicodeSpaceSeparator
unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000"
start = commandList
commandList = command (space command)*
command = move | turn | draw
num = "-"? digit+
move = "MOVE" num
turn = "TURN" num
draw = "DRAW"
space := whitespace | lineTerminator | comment
comment = "//" (~lineTerminator sourceCharacter)*
}
</script>
</head>
<body>
<textarea id="userInput" rows="10" cols="50">MOVE 50
TURN 90
DRAW
</textarea>
<br>
<button onclick="interpretInput()">Interpret</button>
</body>
</html>
JavaScript
const logoGrammar = document.querySelector('#grammar').textContent;
const logoParser = ohm.grammar(logoGrammar);
function interpretInput() {
const userInput = document.getElementById('userInput').value.trim();
if ( !userInput ) { return; }
const match = logoParser.match(userInput);
console.log(match.message);
// console.log(userInput, match);
// const semantics = logoParser.createSemantics();
if (match.succeeded()) {
// Input is valid
const semantics = logoParser.createSemantics();
// Define actions for different commands
semantics.addOperation('interpret', {
move(_, num) {
return `Move forward ${Number(num)}`;
},
turn(_, num) {
return `Turn ${Number(num)} degrees`;
},
draw(_, num) {
return `Draw a line of length ${Number(num)}`;
},
});
const output = semantics(match).interpret();
console.log(output); // You can display this output on the screen or perform other actions.
} else {
// Input is not valid
console.log('Invalid input');
}
}