Skip to content

Commit

Permalink
Basic functionality reproduced in Astro
Browse files Browse the repository at this point in the history
  • Loading branch information
crummy committed Dec 9, 2024
1 parent 1f3324f commit fa2d85b
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 7 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"astro": "astro"
},
"dependencies": {
"astro": "^5.0.3"
"astro": "^5.0.3",
"ppegjs": "0.1.0"
}
}
40 changes: 40 additions & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {defineCollection, z} from 'astro:content';


// Examples should be like this:
// examples/foo/grammar.txt
// examples/foo/input.txt
// TODO: convert to markdown, if astro is happy with multiple files in a single markdown file - easier to do titles too
export const examples = defineCollection({
loader: async () => {
// Would prefer to get a list of folders in the examples directory but Vite only seems to want to
// grab files. So we get both and match them up, a little awkwardly.
const grammars = import.meta.glob('./examples/**/grammar.txt', { query: "?raw", import: "default"})
const inputs = import.meta.glob('./examples/**/input.txt', { query: "?raw", import: "default"})
if (Object.keys(grammars).length !== Object.keys(inputs).length) {
throw new Error('Mismatch between grammars and inputs')
}
const examples: { id: string, title: string, grammar: string, input: string }[] = []
for (const [path, grammarFile] of Object.entries(grammars)) {
const folder = path.split('/').slice(-2, -1)[0]
const grammar = await grammarFile() as string
// yuck...
const input = await inputs[`./examples/${folder}/input.txt`]() as string
examples.push({
id: folder,
title: folder,
grammar,
input,
})
}
return examples;
},
// This schema ensures that the data read in the collection above is valid, by parsing it with Zod
schema: z.object({
title: z.string(),
grammar: z.string(),
input: z.string(),
})
});

export const collections = {examples};
7 changes: 7 additions & 0 deletions src/examples/csv/grammar.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CSV = Hdr Row+
Hdr = Row
Row = field (',' field)* '\r'? '\n'
field = _string / _text / ''

_text = ~[,\n\r]+
_string = '"' (~["] / '""')* '"'
4 changes: 4 additions & 0 deletions src/examples/csv/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
A,B,C
a1,b1,c1
a2,"b,2",c2
a3,b3,c3
12 changes: 12 additions & 0 deletions src/examples/date/grammar.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
date = year '-' month '-' day
year = [1-2][0-9]*3
month = '0'[1-9] / '1'[0-2]
day = [0-3][0-9]

# A simple example to play around with.
# More examples in menu at top.

# This Dingus is only a toy web-page.
# To try your own pPEG grammars use
# the peg-play.mjs command line tool,
# that lets you work on your own files.
1 change: 1 addition & 0 deletions src/examples/date/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2021-02-03
14 changes: 14 additions & 0 deletions src/examples/json/grammar.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
json = _ value _
value = Str / Arr / Obj / num / lit
Obj = '{'_ (memb (_','_ memb)*)? _'}'
memb = Str _':'_ value
Arr = '['_ (value (_','_ value)*)? _']'
Str = '"' chars* '"'
chars = ~[\u0000-\u001F"\]+ / '\' esc
esc = ["\/bfnrt] / 'u' [0-9a-fA-F]*4
num = _int _frac? _exp?
_int = '-'? ([1-9] [0-9]* / '0')
_frac = '.' [0-9]+
_exp = [eE] [+-]? [0-9]+
lit = 'true' / 'false' / 'null'
_ = [ \t\n\r]*
5 changes: 5 additions & 0 deletions src/examples/json/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"answer": 42,
"mixed": [1, 2.3, "a\tstring", true, [4, 5]],
"empty": {}
}
9 changes: 9 additions & 0 deletions src/examples/url/grammar.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Equivalent to the regular expression for
# well-formed URI's in RFC 3986.
URI = (scheme ':')? ('//' auth)?
path ('?' query)? ('#' frag)?
scheme = ~[:/?#]+
auth = ~[/?#]*
path = ~[?#]*
query = ~'#'*
frag = ~[ \t\n\r]*
1 change: 1 addition & 0 deletions src/examples/url/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
http://www.ics.uci.edu/pub/ietf/uri/#Related
2 changes: 1 addition & 1 deletion src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>Astro Basics</title>
<title>pPEGjs Demo</title>
</head>
<body>
<slot />
Expand Down
124 changes: 119 additions & 5 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,125 @@
---
import Welcome from '../components/Welcome.astro';
import Layout from '../layouts/Layout.astro';
// Welcome to Astro! Wondering what to do next? Check out the Astro documentation at https://docs.astro.build
// Don't want to use any of this? Delete everything in this file, the `assets`, `components`, and `layouts` directories, and start fresh.
import {getCollection} from "astro:content"
const examples = (await getCollection("examples")).map(c => c.data)
---

<script>
import {ppeg} from "ppegjs/index.js"

window.dingus = {
eg: () => {
const eg = document.getElementById('examples'),
grammar = document.getElementById('grammar'),
input = document.getElementById('input');
grammar.textContent = document.getElementById(eg.value + '-grammar').textContent,
input.textContent = document.getElementById(eg.value + '-input').textContent;
dingus.run();
},
}

const firstExample = examples[0]

window.load = () => {
const selected = document.getElementById<HTMLSelectElement>('examples').value
const option = document.getElementById(`option-${selected}`)
const grammar = option.dataset.grammar
const input = option.dataset.input
document.getElementById('grammar').textContent = grammar;
document.getElementById('input').textContent = input;
window.run()
}

window.run = () => {
const grammar = document.getElementById('grammar')
const parser = ppeg.compile(grammar.textContent)
const input = document.getElementById('input')
const parse = parser.parse(input.innerText) //textContent),
const output = document.getElementById('output');
if (parse.ok) output.textContent = parse.show_ptree(); // TODO json?
else output.textContent = parse.show_err();
}

window.load()
</script>

<Layout>
<Welcome />
</Layout>
<style>
.box {
display: flex;
flex-wrap: wrap;
}

.grammar, .input, .output {
flex: auto;
width: 400px;
margin: 2px;
border: thin solid gray;
}

.header {
position: relative;
top: 0;
height: 20px;
padding: 5px;
border-bottom: thin solid gray;
background: whitesmoke;
}

.header > button {
float: right;
}

.header > .examples {
float: right;
}

#grammar, #input, #output {
position: relative;
height: 250px;
font-family: "Courier Line Draw", "Courier Prime", "Courier New", monospace;
white-space: pre-wrap;
margin: 2px;
padding: 5px;
resize: both;
overflow: auto;
}
</style>
<h1>pPEG Dingus</h1>

<div class='box'>
<div class='grammar'>
<div class='bag'>
<div class='header'>
<label for="grammar">Grammar</label>
<span class='examples'>
<label for="examples">Examples: </label>
<select name="examples" id="examples" onchange="load()">
{examples.map(({title, grammar, input}) =>
<option id={`option-${title}`} value={title} data-grammar={grammar} data-input={input}>{title}</option>)}
</select>
</span>
</div>
<div id='grammar' contenteditable='true'></div>
</div>
</div>
<div class='input'>
<div class='bag'>
<div class='header'>
<label for="input">Input</label>
<button onclick="run()">Parse..</button>
</div>
<div id='input' contenteditable='true'></div>
</div>
</div>
<div class='output'>
<div class='bag'>
<div class='header'>Parse Tree</div>
<div id='output'></div>
</div>
</div>
</div>
<div>Copyright 2024</div>
</Layout>

0 comments on commit fa2d85b

Please sign in to comment.