basic muddle parser
This commit is contained in:
parent
0a4762f758
commit
8aa2726b4b
103
mudparse.js
Normal file
103
mudparse.js
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// parse beta.mud
|
||||||
|
export const removeComments = (text) => {
|
||||||
|
let newText = []
|
||||||
|
let i = 0
|
||||||
|
while (i < text.length) {
|
||||||
|
let iLim = text.indexOf("/*", i)
|
||||||
|
let iNext
|
||||||
|
if (iLim < 0) {
|
||||||
|
iLim = text.length
|
||||||
|
iNext = iLim
|
||||||
|
} else {
|
||||||
|
const iCommentEnd = text.indexOf("*/", iLim + 2)
|
||||||
|
if (iCommentEnd > 0) {
|
||||||
|
iNext = iCommentEnd + 2
|
||||||
|
} else {
|
||||||
|
throw new Error(`Comment started at ${iLim} has no end`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newText.push(text.slice(i, iLim))
|
||||||
|
i = iNext
|
||||||
|
}
|
||||||
|
return newText.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitLine = (line) => {
|
||||||
|
const tokens = line.trim().split(/\s+/)
|
||||||
|
return (tokens.length == 1 && tokens[0] == '') ? [] : tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
const reString = /^"(.*)"$/
|
||||||
|
const parseResourceLine = (line, dict) => {
|
||||||
|
const tokens = splitLine(line)
|
||||||
|
if (tokens.length == 1 && tokens[0] == "}") {
|
||||||
|
return false
|
||||||
|
} else if (tokens.length == 0) {
|
||||||
|
return true
|
||||||
|
} else if (tokens.length == 1 || !tokens[0].endsWith(":") || !tokens[1].match(reString)) {
|
||||||
|
throw new Error(`Expected 'key: "value"' but got '${line}'`)
|
||||||
|
} else {
|
||||||
|
const key = tokens[0].slice(0, -1)
|
||||||
|
const value = { filename: tokens[1].match(reString)[1] }
|
||||||
|
if (tokens.length > 2) {
|
||||||
|
value.arguments = tokens.slice(2).map((v) => parseInt(v)) // would be nice to know what these mean
|
||||||
|
}
|
||||||
|
dict[key] = value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseClassLine = (line, cls) => {
|
||||||
|
const tokens = splitLine(line)
|
||||||
|
if (tokens.length == 1 && tokens[0] == "}") {
|
||||||
|
return false
|
||||||
|
} else if (tokens.length == 0) {
|
||||||
|
return true
|
||||||
|
} else if (tokens.length == 1) {
|
||||||
|
throw new Error(`Expected "resourcetype reference" but got ${line}`)
|
||||||
|
} else {
|
||||||
|
const resourceType = tokens[0]
|
||||||
|
if (!cls[resourceType]) {
|
||||||
|
cls[resourceType] = []
|
||||||
|
}
|
||||||
|
const array = cls[resourceType]
|
||||||
|
if (resourceType == "byte" && tokens.length == 2) {
|
||||||
|
array.push(parseInt(tokens[1]))
|
||||||
|
} else if (tokens.length == 2) {
|
||||||
|
array.push({ id: tokens[1] })
|
||||||
|
} else {
|
||||||
|
array.push({ id: tokens[1], arguments: tokens.slice(2).map((v) => parseInt(v)) })
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseStructure = (lines, iline, struct, parser) => {
|
||||||
|
while (parser(lines[iline], struct)) {
|
||||||
|
iline ++
|
||||||
|
}
|
||||||
|
return iline
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseMud = (lines) => {
|
||||||
|
const mud = {"class": {}}
|
||||||
|
for (let iline = 0; iline < lines.length; iline ++) {
|
||||||
|
const tokens = splitLine(lines[iline])
|
||||||
|
if (tokens.length == 2 && tokens[1] == "{") {
|
||||||
|
const mapping = {}
|
||||||
|
iline = parseStructure(lines, iline + 1, mapping, parseResourceLine)
|
||||||
|
mud[tokens[0]] = mapping
|
||||||
|
} else if (tokens.length == 4 && tokens[0] == "class" && tokens[3] == "{") {
|
||||||
|
const cls = { id: parseInt(tokens[2]) }
|
||||||
|
iline = parseStructure(lines, iline + 1, cls, parseClassLine)
|
||||||
|
mud.class[tokens[1]] = cls
|
||||||
|
} else if (tokens.length != 0) {
|
||||||
|
throw new Error(`Expected "resourcetype {" but got ${lines[iline]}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mud
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parse = (text) => {
|
||||||
|
return parseMud(removeComments(text).split("\n"))
|
||||||
|
}
|
44
objects.html
Normal file
44
objects.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<title>Inhabitor - The Habitat Inspector</title>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
margin:40px auto;
|
||||||
|
line-height:1.6;
|
||||||
|
font-size:18px;
|
||||||
|
color:#444;
|
||||||
|
padding:0 10px
|
||||||
|
}
|
||||||
|
h1,h2,h3 {
|
||||||
|
line-height:1.2
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Inhabitor - The Habitat Inspector</h1>
|
||||||
|
<div id="muddle">
|
||||||
|
<h3>Muddle database</h3>
|
||||||
|
</div>
|
||||||
|
<a href="javascript:showErrors();">Show errors</a>
|
||||||
|
<div id="errors" style="display: none"></div>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import { parse, removeComments } from "./mudparse.js"
|
||||||
|
import { textNode } from "./show.js"
|
||||||
|
|
||||||
|
window.showErrors = () => {
|
||||||
|
document.getElementById('errors').style.display = 'block'
|
||||||
|
}
|
||||||
|
const onload = async () => {
|
||||||
|
const response = await fetch("beta.mud", { cache: "no-cache" })
|
||||||
|
const text = await response.text()
|
||||||
|
const container = document.getElementById("muddle")
|
||||||
|
const mud = parse(text)
|
||||||
|
container.appendChild(textNode(JSON.stringify(mud, null, 2), "pre"))
|
||||||
|
}
|
||||||
|
onload()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue