Font editer coming a long. first font is looking good. some parser changes to accomodate any string as record fields. other stuff

master
Dustin Swan 4 days ago
parent e3b8930111
commit d79166a5bc
Signed by: dustinswan
GPG Key ID: 30D46587E2100467

@ -220,7 +220,7 @@ export function prettyPrint(ast: AST, indent = 0): string {
const parts = ast.entries.map(entry =>
entry.kind === 'spread'
? `...${prettyPrint(entry.expr, indent + 1)}`
: `${entry.key} = ${prettyPrint(entry.value, indent + 1)}`
: `${needsQuotes(entry.key) ? `"${entry.key}"` : entry.key} = ${prettyPrint(entry.value, indent + 1)}`
);
if (parts.length <= 1) return `{ ${parts.join(', ')} }`;
const inner = parts.map(p => `${' '.repeat(indent + 1)}${p}`).join(',\n');
@ -238,11 +238,12 @@ export function prettyPrint(ast: AST, indent = 0): string {
}
case 'record-access':
return `${prettyPrint(ast.record, indent)}.${ast.field}`;
const field = needsQuotes(ast.field) ? `"${ast.field}"` : ast.field;
return `${prettyPrint(ast.record, indent)}.${field}`;
case 'record-update': {
const updates = Object.entries(ast.updates)
.map(([k, v]) => `${k} = ${prettyPrint(v, indent)}`)
.map(([k, v]) => `${needsQuotes(k) ? `"${k}"` : k} = ${prettyPrint(v, indent)}`)
.join(', ');
return `${prettyPrint(ast.record, indent)}.{ ${updates} }`
}
@ -298,7 +299,7 @@ function prettyPrintPattern(pattern: Pattern): string {
case 'record':
const fields = Object.entries(pattern.fields)
.map(([k, p]) => `${k} = ${prettyPrintPattern(p)}`)
.map(([k, p]) => `${needsQuotes(k) ? `"${k}"` : k} = ${prettyPrintPattern(p)}`)
.join(', ');
return `{${fields}}`;
@ -306,3 +307,7 @@ function prettyPrintPattern(pattern: Pattern): string {
return `Unknown AST kind: ${(pattern as any).kind}`
}
}
function needsQuotes(key: string): boolean {
return !/^[a-z_][a-zA-Z0-9_]*$/.test(key);
}

File diff suppressed because it is too large Load Diff

@ -51,12 +51,15 @@ fontEditor = config \
| _ \ { state = state, emit = [] },
view = state emit \
tileSize = 50;
tileSize = 52;
tileView = g \
glyph = g.value;
key = g.key;
scale = max 1 (floor (min (tileSize / glyph.w) (tileSize / glyph.h)) - 2);
# scale = max 1 (floor (min (tileSize / glyph.w) (tileSize / glyph.h)) - 2);
scale = 4;
x = floor ((tileSize - glyph.w * scale) / 2);
ui.clickable {
onClick = \ editGlyph (c.path & ".glyphs." & key),
child = ui.stack {
@ -64,30 +67,41 @@ fontEditor = config \
ui.rect { w = tileSize, h = tileSize, strokeWidth = 1, strokeColor = "#fff" },
# center tileSize tileSize (glyphView { glyph = glyph, scale = scale })
ui.positioned {
x = scale, y = scale,
x = 3 * scale, y = scale,
child = glyphView { glyph = glyph, scale = scale }
}
]
}
};
headerHeight = 30;
header = ui.row {
gap = 10,
children = [
inputButton {
h = headerHeight,
key = "new-glyph-button",
label = "New Glyph",
onSubmit = key \ rebindAt (c.path & ".glyphs." & key) { w = 5, h = 7, map = [] }
onSubmit = key \ rebindAt (c.path & ".glyphs." & key) { w = 7, h = 12, map = [] }
}
]
};
ui.column {
gap = 2,
children = [
header,
...map tileView (entries state.glyphs)
]
}
perRow = floor (ctx.w / tileSize) - 1;
grid = ui.stack {
children = mapWithIndex (g idx \
x = (idx % perRow) * tileSize + 2 * (idx % perRow);
y = (floor (idx / perRow)) * tileSize + 2 * (floor (idx / perRow));
ui.positioned {
x = x,
y = y,
child = tileView g
}) (entries state.glyphs)
};
ui.column { gap = 2, children = [ header, grid ] }
}
};

@ -36,6 +36,7 @@ pixelEditor = config \
{ state = newState, emit = saveGlyph newState });
existing = eval! (c.path);
_ = debug! "existing" existing;
# return App
{
@ -50,16 +51,16 @@ pixelEditor = config \
init = existing
| Value v \ {
map = v.map,
pixelWidth = 5,
pixelHeight = 7,
pixelWidth = v.w,
pixelHeight = v.h,
cellSize = 30,
selectedRow = 0,
selectedCol = 0
}
| _ \ {
map = [],
pixelWidth = 5,
pixelHeight = 7,
pixelWidth = 7,
pixelHeight = 12,
cellSize = 30,
selectedRow = 0,
selectedCol = 0

@ -56,7 +56,7 @@ export function compile(ast: AST, ctx: CompileCtx = defaultCtx): string {
const parts = ast.entries.map(entry =>
entry.kind === 'spread'
? `...${compile(entry.expr, ctx)}`
: `${sanitizeName(entry.key)}: ${compile(entry.value, ctx)}`
: `${JSON.stringify(entry.key)}: ${compile(entry.value, ctx)}`
)
return `({${parts.join(', ')}})`;
}
@ -69,11 +69,11 @@ export function compile(ast: AST, ctx: CompileCtx = defaultCtx): string {
}
case 'record-access':
return `${compile(ast.record, ctx)}.${sanitizeName(ast.field)}`;
return `${compile(ast.record, ctx)}[${JSON.stringify(ast.field)}]`;
case 'record-update':
const updates = Object.entries(ast.updates)
.map(([k, v]) => `${sanitizeName(k)}: ${compile(v, ctx)}`);
.map(([k, v]) => `${JSON.stringify(k)}: ${compile(v, ctx)}`);
return `({...${compile(ast.record, ctx)}, ${updates.join(', ')}})`;
case 'let': {
@ -207,7 +207,7 @@ function compilePattern(pattern: Pattern, expr: string): { condition: string, bi
let condition = 'true';
const bindings: string[] = [];
for (const [field, fieldPattern] of Object.entries(pattern.fields)) {
const sub = compilePattern(fieldPattern, `${expr}.${sanitizeName(field)}`);
const sub = compilePattern(fieldPattern, `${expr}[${JSON.stringify(field)}]`);
if (sub.condition !== 'true') condition += ` && ${sub.condition}`;
bindings.push(...sub.bindings);
}

@ -44,11 +44,11 @@ export class Parser {
private expectIdent(): Token {
const token = this.current();
if (token.kind === 'ident' || token.kind === 'type-ident') {
if (token.kind === 'ident' || token.kind === 'type-ident' || token.kind === 'string') {
this.advance();
return token;
}
throw this.error(`Expected identifier, got ${token.kind}`);
throw ParseError(`Expected identifier, got ${token.kind}`);
}
private getPos(token: Token) {

Loading…
Cancel
Save