Switching to ML style type annotations. not separate statement from the expression
This commit is contained in:
parent
6acec5641c
commit
f3c3a76671
6 changed files with 35 additions and 36 deletions
|
|
@ -325,9 +325,9 @@ export function prettyPrint(ast: AST, indent = 0): string {
|
||||||
|
|
||||||
case 'definition':
|
case 'definition':
|
||||||
const ann = ast.annotation
|
const ann = ast.annotation
|
||||||
? `${ast.name} : ${prettyPrintType(ast.annotation.type)};\n`
|
? ` : ${prettyPrintType(ast.annotation.type)}`
|
||||||
: '';
|
: '';
|
||||||
return `${ann}${ast.name} = ${prettyPrint(ast.body, indent)};`;
|
return `${ast.name}${ann} = ${prettyPrint(ast.body, indent)};`;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return `Unknown AST kind: ${i}${(ast as any).kind}`
|
return `Unknown AST kind: ${i}${(ast as any).kind}`
|
||||||
|
|
@ -373,7 +373,7 @@ function prettyPrintPattern(pattern: Pattern): string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prettyPrintType(type: TypeAST): string {
|
export function prettyPrintType(type: TypeAST): string {
|
||||||
switch (type.kind) {
|
switch (type.kind) {
|
||||||
case 'type-name':
|
case 'type-name':
|
||||||
case 'type-var':
|
case 'type-var':
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@ Maybe a = None | Some a;
|
||||||
# | [0, [x, ...xs]] \ (Some x)
|
# | [0, [x, ...xs]] \ (Some x)
|
||||||
# | [n, [x, ...xs]] \ nth (n - 1) xs;
|
# | [n, [x, ...xs]] \ nth (n - 1) xs;
|
||||||
|
|
||||||
map : (a \ b) \ List a \ List b;
|
map : (a \ b) \ List a \ List b = f list \ list
|
||||||
map = f list \ list
|
|
||||||
| [] \ []
|
| [] \ []
|
||||||
| [x, ...xs] \ [f x, ...map f xs];
|
| [x, ...xs] \ [f x, ...map f xs];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
myFontBackup = { glyphs = {
|
myFont = { glyphs = {
|
||||||
"0" = {
|
"0" = {
|
||||||
w = 7,
|
w = 7,
|
||||||
h = 12,
|
h = 12,
|
||||||
|
|
@ -5836,7 +5836,7 @@ myFontBackup = { glyphs = {
|
||||||
}
|
}
|
||||||
} };
|
} };
|
||||||
|
|
||||||
myFont2Backup = { glyphs = {
|
myFont2 = { glyphs = {
|
||||||
"0" = {
|
"0" = {
|
||||||
w = 5,
|
w = 5,
|
||||||
h = 12,
|
h = 12,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ type CompileCtx = {
|
||||||
};
|
};
|
||||||
const defaultCtx: CompileCtx = { useStore: true, bound: new Set(), topLevel: new Set() };
|
const defaultCtx: CompileCtx = { useStore: true, bound: new Set(), topLevel: new Set() };
|
||||||
|
|
||||||
export const definitions: Map<string, AST> = new Map();
|
export const definitions: Map<string, Definition> = new Map();
|
||||||
export const dependencies: Map<string, Set<string>> = new Map();
|
export const dependencies: Map<string, Set<string>> = new Map();
|
||||||
export const dependents: Map<string, Set<string>> = new Map();
|
export const dependents: Map<string, Set<string>> = new Map();
|
||||||
export const astRegistry = new Map<number, AST>();
|
export const astRegistry = new Map<number, AST>();
|
||||||
|
|
@ -226,7 +226,7 @@ export function compileAndRun(defs: Definition[]) {
|
||||||
const topLevel = new Set(defs.map(d => d.name));
|
const topLevel = new Set(defs.map(d => d.name));
|
||||||
|
|
||||||
for (const def of defs) {
|
for (const def of defs) {
|
||||||
definitions.set(def.name, def.body);
|
definitions.set(def.name, def);
|
||||||
const free = freeVars(def.body);
|
const free = freeVars(def.body);
|
||||||
const deps = new Set([...free].filter(v => topLevel.has(v)));
|
const deps = new Set([...free].filter(v => topLevel.has(v)));
|
||||||
dependencies.set(def.name, deps);
|
dependencies.set(def.name, deps);
|
||||||
|
|
@ -364,7 +364,9 @@ function patternVars(pattern: Pattern): string[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recompile(name: string, newAst: AST) {
|
export function recompile(name: string, newAst: AST) {
|
||||||
definitions.set(name, newAst);
|
const existing = definitions.get(name);
|
||||||
|
definitions.set(name, { kind: 'definition', name, body: newAst, annotation: existing?.annotation });;
|
||||||
|
// definitions.set(name, newAst);
|
||||||
|
|
||||||
const topLevel = new Set(definitions.keys());
|
const topLevel = new Set(definitions.keys());
|
||||||
const free = freeVars(newAst);
|
const free = freeVars(newAst);
|
||||||
|
|
@ -394,7 +396,7 @@ export function recompile(name: string, newAst: AST) {
|
||||||
collectDependents(name);
|
collectDependents(name);
|
||||||
|
|
||||||
for (const defName of toRecompile) {
|
for (const defName of toRecompile) {
|
||||||
const ast = definitions.get(defName)!;
|
const ast = definitions.get(defName)!.body;
|
||||||
const compiled = compile(ast);
|
const compiled = compile(ast);
|
||||||
|
|
||||||
const fn = new Function('store', `return ${compiled}`);
|
const fn = new Function('store', `return ${compiled}`);
|
||||||
|
|
|
||||||
|
|
@ -160,21 +160,6 @@ export class Parser {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// type annotation
|
|
||||||
if (this.current().kind === 'ident' && this.peek().kind === 'colon') {
|
|
||||||
this.advance(); // eat ident
|
|
||||||
|
|
||||||
this.advance();
|
|
||||||
const type = this.parseType();
|
|
||||||
this.expect('semicolon');
|
|
||||||
|
|
||||||
// parse definition
|
|
||||||
const def = this.parseDefinition();
|
|
||||||
def.annotation = { constraints: [], type };
|
|
||||||
|
|
||||||
definitions.push(def);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
definitions.push(this.parseDefinition());
|
definitions.push(this.parseDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,6 +170,12 @@ export class Parser {
|
||||||
const nameToken = this.expect('ident');
|
const nameToken = this.expect('ident');
|
||||||
const name = (nameToken as { value: string }).value;
|
const name = (nameToken as { value: string }).value;
|
||||||
|
|
||||||
|
let annotation: Annotation | undefined;
|
||||||
|
if (this.current().kind === 'colon') {
|
||||||
|
this.advance();
|
||||||
|
annotation = { constraints: [], type: this.parseType() };
|
||||||
|
}
|
||||||
|
|
||||||
this.expect('equals');
|
this.expect('equals');
|
||||||
|
|
||||||
const body = this.parseExpression();
|
const body = this.parseExpression();
|
||||||
|
|
@ -193,7 +184,7 @@ export class Parser {
|
||||||
this.expect('semicolon');
|
this.expect('semicolon');
|
||||||
}
|
}
|
||||||
|
|
||||||
return { kind: 'definition', name, body, ...this.getPos(nameToken) };
|
return { kind: 'definition', name, body, annotation, ...this.getPos(nameToken) };
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseExpression(): AST {
|
private parseExpression(): AST {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { tokenize } from './lexer'
|
import { tokenize } from './lexer'
|
||||||
import { Parser } from './parser'
|
import { Parser } from './parser'
|
||||||
import { compile, recompile, definitions, freeVars, dependencies, dependents, astRegistry } from './compiler'
|
import { compile, recompile, definitions, freeVars, dependencies, dependents, astRegistry } from './compiler'
|
||||||
import { prettyPrint } from './ast'
|
import { prettyPrint, prettyPrintType } from './ast'
|
||||||
import type { AST } from './ast'
|
import type { AST } from './ast'
|
||||||
import { measure } from './ui';
|
import { measure } from './ui';
|
||||||
|
|
||||||
|
|
@ -118,10 +118,9 @@ export const _rt = {
|
||||||
return obj === undefined ? { _tag: 'None' } : { _tag: 'Some', _0: obj };
|
return obj === undefined ? { _tag: 'None' } : { _tag: 'Some', _0: obj };
|
||||||
},
|
},
|
||||||
getSource: (name: string) => {
|
getSource: (name: string) => {
|
||||||
const ast = definitions.get(name);
|
const def = definitions.get(name);
|
||||||
if (!ast) return "";
|
if (!def) return "";
|
||||||
const printed = prettyPrint(ast);
|
return prettyPrint(def);
|
||||||
return printed;
|
|
||||||
},
|
},
|
||||||
"saveImage!": () => {
|
"saveImage!": () => {
|
||||||
const saved: Record<string, string> = {};
|
const saved: Record<string, string> = {};
|
||||||
|
|
@ -259,8 +258,8 @@ export const _rt = {
|
||||||
|
|
||||||
export function saveDefinitions() {
|
export function saveDefinitions() {
|
||||||
const saved: Record<string, string> = {};
|
const saved: Record<string, string> = {};
|
||||||
for (const [name, ast] of definitions) {
|
for (const [name, def] of definitions) {
|
||||||
const source = prettyPrint({ kind: 'definition', name, body: ast });
|
const source = prettyPrint(def);
|
||||||
saved[name] = source;
|
saved[name] = source;
|
||||||
}
|
}
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(saved));
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(saved));
|
||||||
|
|
@ -356,8 +355,16 @@ function valueToAst(value: any): AST {
|
||||||
export function syncToAst(name: string) {
|
export function syncToAst(name: string) {
|
||||||
// if (definitions.has(name)) {
|
// if (definitions.has(name)) {
|
||||||
if (name in store) {
|
if (name in store) {
|
||||||
definitions.set(name, valueToAst(store[name]));
|
const existing = definitions.get(name);
|
||||||
const source = prettyPrint({ kind: 'definition', name, body: definitions.get(name)! });
|
const newDef: Definition = {
|
||||||
|
kind: 'definition',
|
||||||
|
name,
|
||||||
|
body: valueToAst(store[name]),
|
||||||
|
annotation: existing?.annotation,
|
||||||
|
};
|
||||||
|
definitions.set(name, newDef); // valueToAst(store[name]));
|
||||||
|
// const source = prettyPrint({ kind: 'definition', name, body: definitions.get(name)! });
|
||||||
|
const source = prettyPrint(definitions.get(name)!);
|
||||||
appendChangeLog(name, source);
|
appendChangeLog(name, source);
|
||||||
saveDefinitions();
|
saveDefinitions();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue