initial ideas
This commit is contained in:
parent
3e7bf2dd80
commit
3390e9d50a
158
colors.html
Normal file
158
colors.html
Normal file
@ -0,0 +1,158 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<style>
|
||||
.swatch {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: hsl(var(--hue), var(--saturation), var(--lightness));
|
||||
}
|
||||
|
||||
.h1p {
|
||||
--hue: 310;
|
||||
}
|
||||
.h1 {
|
||||
--hue: 340;
|
||||
}
|
||||
.h1s {
|
||||
--hue: 335;
|
||||
}
|
||||
.h2d {
|
||||
--hue: 50;
|
||||
}
|
||||
.h2 {
|
||||
--hue: 37;
|
||||
}
|
||||
.h2s {
|
||||
--hue: 30;
|
||||
}
|
||||
.h2h {
|
||||
--hue: 57;
|
||||
}
|
||||
.h3 {
|
||||
--hue: 130;
|
||||
}
|
||||
.h3s {
|
||||
--hue: 145;
|
||||
}
|
||||
.h3h {
|
||||
--hue: 203;
|
||||
}
|
||||
.h4 {
|
||||
--hue: 224;
|
||||
}
|
||||
/* .h4hs {
|
||||
--hue: 228;
|
||||
}
|
||||
.h4s {
|
||||
--hue: 235;
|
||||
} */
|
||||
.h4hs {
|
||||
--hue: 235;
|
||||
}
|
||||
.h4s {
|
||||
--hue: 240;
|
||||
}
|
||||
.h5 {
|
||||
--hue: 250;
|
||||
}
|
||||
.h6 {
|
||||
--hue: 230;
|
||||
}
|
||||
.h7 {
|
||||
--hue: 30;
|
||||
}
|
||||
|
||||
.sp {
|
||||
--saturation: 90%;
|
||||
}
|
||||
.s1 {
|
||||
--saturation: 85%;
|
||||
}
|
||||
.s1x {
|
||||
--saturation: 75%;
|
||||
}
|
||||
.sx {
|
||||
--saturation: 65%;
|
||||
}
|
||||
.smx {
|
||||
--saturation: 60%;
|
||||
}
|
||||
.sm {
|
||||
--saturation: 55%;
|
||||
}
|
||||
.smm {
|
||||
--saturation: 50%;
|
||||
}
|
||||
.s2 {
|
||||
--saturation: 45%;
|
||||
}
|
||||
.ss {
|
||||
--saturation: 40%;
|
||||
}
|
||||
.sl {
|
||||
--saturation: 25%;
|
||||
}
|
||||
.s3 {
|
||||
--saturation: 13%;
|
||||
}
|
||||
|
||||
.l0 {
|
||||
--lightness: 95%;
|
||||
}
|
||||
.l1 {
|
||||
--lightness: 82%;
|
||||
}
|
||||
.l1h {
|
||||
--lightness: 75%;
|
||||
}
|
||||
.l1hh {
|
||||
--lightness: 70%;
|
||||
}
|
||||
.l2 {
|
||||
--lightness: 67%;
|
||||
}
|
||||
.l2m {
|
||||
--lightness: 62%;
|
||||
}
|
||||
.lm {
|
||||
--lightness: 58%;
|
||||
}
|
||||
.l3 {
|
||||
--lightness: 50%;
|
||||
}
|
||||
.l3h {
|
||||
--lightness: 40%;
|
||||
}
|
||||
.l4 {
|
||||
--lightness: 30%;
|
||||
}
|
||||
.l4h {
|
||||
--lightness: 25%;
|
||||
}
|
||||
.l5 {
|
||||
--lightness: 20%;
|
||||
}
|
||||
.l6 {
|
||||
--lightness: 5%;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#palette {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="palette"></div>
|
||||
<script src="colors.js"></script>
|
||||
<script>
|
||||
const div = document.getElementById("palette");
|
||||
div.innerHTML = palette.map(c => `<div class="swatch" style="background-color: hsl(${c[0]}, ${c[1]}%, ${c[2]}%);"></div>`).join("");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
54
colors.js
Normal file
54
colors.js
Normal file
@ -0,0 +1,54 @@
|
||||
const hue_gray = 230;
|
||||
const hue_brown = 30;
|
||||
const hue_orange = 37;
|
||||
const hue_purple = 250;
|
||||
const hue_pink = 310;
|
||||
const hue_red = 340;
|
||||
const hue_red_shade = 335;
|
||||
const hue_yellow = 57;
|
||||
const hue_green = 130;
|
||||
const hue_green_shade = 145;
|
||||
const hue_sky = 203;
|
||||
const hue_blue = 224;
|
||||
const hue_blue_shade = 235;
|
||||
const hue_blue_shade_2 = 240;
|
||||
|
||||
const saturation_max = 90;
|
||||
const saturation_normal = 60;
|
||||
const saturation_low = 40;
|
||||
const saturation_min = 13;
|
||||
|
||||
const lightness_max = 95;
|
||||
const lightness_light = 67;
|
||||
const lightness_mediumlight = 62;
|
||||
const lightness_medium = 50;
|
||||
const lightness_mediumdark = 40;
|
||||
const lightness_dark = 30;
|
||||
const lightness_almostverydark = 25;
|
||||
const lightness_verydark = 20;
|
||||
const lightness_min = 5;
|
||||
|
||||
const hsl = (h, s, l) => [h, s, l];
|
||||
|
||||
const palette = [
|
||||
hsl(hue_gray, saturation_min, lightness_max),
|
||||
hsl(hue_gray, saturation_min, lightness_light),
|
||||
hsl(hue_gray, saturation_min, lightness_dark),
|
||||
hsl(hue_gray, saturation_min, lightness_min),
|
||||
hsl(hue_orange, saturation_normal, lightness_medium),
|
||||
hsl(hue_brown, saturation_low, lightness_light),
|
||||
hsl(hue_brown, saturation_low, lightness_mediumdark),
|
||||
hsl(hue_brown, saturation_low, lightness_almostverydark),
|
||||
hsl(hue_purple, saturation_normal, lightness_light),
|
||||
hsl(hue_pink, saturation_normal, lightness_light),
|
||||
hsl(hue_red, saturation_normal, lightness_medium),
|
||||
hsl(hue_red_shade, saturation_normal, lightness_dark),
|
||||
hsl(hue_yellow, saturation_max, lightness_mediumlight),
|
||||
hsl(hue_green, saturation_normal, lightness_medium),
|
||||
hsl(hue_green_shade, saturation_normal, lightness_dark),
|
||||
hsl(hue_green_shade, saturation_normal, lightness_verydark),
|
||||
hsl(hue_sky, saturation_max, lightness_light),
|
||||
hsl(hue_blue, saturation_normal, lightness_medium),
|
||||
hsl(hue_blue_shade, saturation_normal, lightness_mediumdark),
|
||||
hsl(hue_blue_shade_2, saturation_normal, lightness_dark),
|
||||
]
|
54
colors2.js
Normal file
54
colors2.js
Normal file
@ -0,0 +1,54 @@
|
||||
const hue_gray = 230;
|
||||
const hue_brown = 25;
|
||||
const hue_brown_shade = 10;
|
||||
const hue_orange = 37;
|
||||
const hue_purple = 250;
|
||||
const hue_pink = 310;
|
||||
const hue_red = 340;
|
||||
const hue_red_shade = 335;
|
||||
const hue_redbrown_dark = 0;
|
||||
const hue_yellow = 57;
|
||||
const hue_green = 140;
|
||||
const hue_green_shade = 145;
|
||||
const hue_sky = 203;
|
||||
const hue_blue = 240;
|
||||
const hue_blue_shade = 235;
|
||||
const hue_blue_shade_2 = 240;
|
||||
const hue_bluegreen_dark = 215;
|
||||
|
||||
const saturation_max = 90;
|
||||
const saturation_normal = 60;
|
||||
const saturation_low = 40;
|
||||
const saturation_min = 13;
|
||||
|
||||
const lightness_max = 95;
|
||||
const lightness_light = 67;
|
||||
const lightness_mediumlight = 62;
|
||||
const lightness_medium = 50;
|
||||
const lightness_mediumdark = 40;
|
||||
const lightness_dark = 30;
|
||||
const lightness_almostverydark = 25;
|
||||
const lightness_verydark = 20;
|
||||
const lightness_min = 5;
|
||||
|
||||
const hsl = (h, s, l) => [h, s, l];
|
||||
|
||||
const palette = [
|
||||
hsl(hue_gray, saturation_min, lightness_max),
|
||||
hsl(hue_gray, saturation_min, lightness_light),
|
||||
hsl(hue_gray, saturation_min, lightness_dark),
|
||||
hsl(hue_gray, saturation_min, lightness_min),
|
||||
hsl(hue_orange, saturation_normal, lightness_medium),
|
||||
hsl(hue_brown, saturation_low, lightness_light),
|
||||
hsl(hue_brown_shade, saturation_low, lightness_mediumdark),
|
||||
hsl(hue_pink, saturation_normal, lightness_light),
|
||||
hsl(hue_red, saturation_normal, lightness_medium),
|
||||
hsl(hue_red_shade, saturation_normal, lightness_dark),
|
||||
hsl(hue_yellow, saturation_max, lightness_mediumlight),
|
||||
hsl(hue_green, saturation_normal, lightness_medium),
|
||||
hsl(hue_green_shade, saturation_normal, lightness_dark),
|
||||
hsl(hue_sky, saturation_max, lightness_light),
|
||||
hsl(hue_blue, saturation_normal, lightness_mediumlight),
|
||||
hsl(hue_blue_shade, saturation_normal, lightness_mediumdark),
|
||||
hsl(hue_bluegreen_dark, saturation_normal, lightness_verydark),
|
||||
]
|
133
femto-lang/faux/faux.ts
Normal file
133
femto-lang/faux/faux.ts
Normal file
@ -0,0 +1,133 @@
|
||||
// const STR = (s: string): StringValue => ({type: "string", value: s});
|
||||
// const FN = (f: FunctionValue["value"]): FunctionValue => ({type: "function", value: f});
|
||||
// const SYM = (s: string): SymbolValue => ({type: "symbol", value: s});
|
||||
// const UNDEF = (): UndefinedValue => ({type: "undefined", value: null});
|
||||
// const CODE = (p: CodeBlockValue["value"]): CodeBlockValue => ({type: "code", value: p});
|
||||
// const THUNK = (t: ThunkValue["value"]): ThunkValue => ({type: "thunk", value: t});
|
||||
// const BOOL = (b: boolean): BooleanValue => ({type: "boolean", value: b});
|
||||
|
||||
// console.log("HELLO");
|
||||
|
||||
// type SymbolValue = {
|
||||
// type: "symbol",
|
||||
// value: string,
|
||||
// }
|
||||
|
||||
// type FunctionValue = {
|
||||
// type: "function",
|
||||
// value: (arg: Value, env: Environment, passalong: Passalong) => Result,
|
||||
// }
|
||||
|
||||
// type StringValue = {
|
||||
// type: "string",
|
||||
// value: string,
|
||||
// }
|
||||
|
||||
// type BooleanValue = {
|
||||
// type: "boolean",
|
||||
// value: boolean,
|
||||
// }
|
||||
|
||||
// type UndefinedValue = {
|
||||
// type: "undefined",
|
||||
// value: null,
|
||||
// }
|
||||
|
||||
// type CodeBlockValue = {
|
||||
// type: "code",
|
||||
// value: Array<Value>,
|
||||
// }
|
||||
|
||||
// type ThunkValue = {
|
||||
// type: "thunk",
|
||||
// value: Array<Value>,
|
||||
// }
|
||||
|
||||
// type Value =
|
||||
// | SymbolValue
|
||||
// | FunctionValue
|
||||
// | StringValue
|
||||
// | UndefinedValue
|
||||
// | CodeBlockValue
|
||||
// | ThunkValue
|
||||
// | BooleanValue
|
||||
|
||||
// type Passalong = Value;
|
||||
|
||||
// type Result<V extends Value = Value> = {
|
||||
// result: V,
|
||||
// passalong: any,
|
||||
// }
|
||||
|
||||
// type Environment = {[key: string]: Value}
|
||||
|
||||
// const evaluate_codeblock = (codeBlock: CodeBlockValue, env: Environment): Result => {
|
||||
// let result: Result = {
|
||||
// result: UNDEF(),
|
||||
// passalong: UNDEF(),
|
||||
// };
|
||||
// const terms = [...codeBlock.value];
|
||||
// while (terms.length) {
|
||||
// console.log('evaluating phrase', terms);
|
||||
// result = evaluate_phrase(terms, env, result.passalong);
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// const evaluate_phrase = (terms: Array<Value>, env: Environment, passalong: Passalong): Result => {
|
||||
// let head: Result = evaluate_term(terms.shift() as Value, env, passalong);
|
||||
// let pa = passalong;
|
||||
// while (head.result.type === "function") {
|
||||
// if (!terms.length) {
|
||||
// throw 'Runtime Error: head function has no argument to be called with';
|
||||
// }
|
||||
// const tail: Result = evaluate_term(terms.shift() as Value, env, UNDEF());
|
||||
// head = head.result.value(tail.result, env, pa);
|
||||
// pa = head.passalong;
|
||||
// }
|
||||
// return head;
|
||||
// }
|
||||
|
||||
// const evaluate_term = (term: Value, env: Environment, passalong: Passalong): Result => {
|
||||
// if (term.type === "symbol") {
|
||||
// return {
|
||||
// result: env[term.value],
|
||||
// passalong: UNDEF(), // TODO: this should include term.value as a "name"
|
||||
// }
|
||||
// } else if (term.type === "string") {
|
||||
// return {
|
||||
// result: term,
|
||||
// passalong: UNDEF(),
|
||||
// }
|
||||
// } else if (term.type === "function") {
|
||||
// return {
|
||||
// result: term,
|
||||
// passalong: UNDEF(),
|
||||
// }
|
||||
// } else if (term.type === "boolean") {
|
||||
// return {
|
||||
// result: term,
|
||||
// passalong: UNDEF(),
|
||||
// }
|
||||
// }
|
||||
// return {
|
||||
// result: UNDEF(),
|
||||
// passalong: UNDEF(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// const my_env: Environment = {
|
||||
// print: FN((arg, env, passalong) => {
|
||||
// console.log(arg);
|
||||
// return {
|
||||
// result: UNDEF(),
|
||||
// passalong: UNDEF(),
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// const my_prog: CodeBlockValue = CODE([
|
||||
// SYM("print"), STR("hi"),
|
||||
// ]);
|
||||
|
||||
// console.log(evaluate_codeblock(my_prog, my_env));
|
141
femto-lang/faux/trying.js
Normal file
141
femto-lang/faux/trying.js
Normal file
@ -0,0 +1,141 @@
|
||||
const STR = (s) => ({type: "string", value: s});
|
||||
const FN = (f) => ({type: "function", value: f});
|
||||
const SYM = (s) => ({type: "symbol", value: s});
|
||||
const UNDEF = () => ({type: "undefined", value: null});
|
||||
const CODE = (p) => ({type: "code", value: p});
|
||||
const THUNK = (t) => ({type: "thunk", value: t});
|
||||
const BOOL = (b) => ({type: "boolean", value: b});
|
||||
|
||||
const evaluate_codeblock = (codeBlock, env) => {
|
||||
let result = {
|
||||
result: UNDEF(),
|
||||
passalong: {},
|
||||
};
|
||||
const terms = [...codeBlock.value];
|
||||
while (terms.length) {
|
||||
// console.log('evaluating phrase', terms);
|
||||
result = evaluate_phrase(terms, env, result.passalong);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const evaluate_phrase = (terms, env, passalong) => {
|
||||
let head = evaluate_term(terms.shift(), env, passalong);
|
||||
let pa = passalong;
|
||||
while (head.result.type === "function") {
|
||||
if (!terms.length) {
|
||||
throw 'Runtime Error: head function has no argument to be called with';
|
||||
}
|
||||
const tail = evaluate_term(terms.shift(), env, {});
|
||||
head = head.result.value(tail.result, env, pa);
|
||||
pa = head.passalong;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
const evaluate_term = (term, env, passalong) => {
|
||||
if (term.type === "symbol") {
|
||||
return {
|
||||
result: env[term.value],
|
||||
passalong: {name: STR(term.value)}, // TODO: this should include term.value as a "name"
|
||||
}
|
||||
} else if (term.type === "string") {
|
||||
return {
|
||||
result: term,
|
||||
passalong: {},
|
||||
}
|
||||
} else if (term.type === "function") {
|
||||
return {
|
||||
result: term,
|
||||
passalong: {},
|
||||
}
|
||||
} else if (term.type === "boolean") {
|
||||
return {
|
||||
result: term,
|
||||
passalong: {},
|
||||
}
|
||||
} else if (term.type === "thunk") {
|
||||
return {
|
||||
result: term,
|
||||
passalong: {},
|
||||
}
|
||||
}
|
||||
return {
|
||||
result: UNDEF(),
|
||||
passalong: {},
|
||||
}
|
||||
}
|
||||
|
||||
const my_env = {
|
||||
print: FN((arg, env, passalong) => {
|
||||
console.log('PRINT', arg);
|
||||
return {
|
||||
result: UNDEF(),
|
||||
passalong: {},
|
||||
}
|
||||
}),
|
||||
if: FN((arg, env, passalong) => {
|
||||
return {
|
||||
result: FN((thunk, e2, pa) => {
|
||||
if (arg.type === "boolean" && arg.value) {
|
||||
return {
|
||||
result: evaluate_codeblock(thunk, e2),
|
||||
passalong: {handled: true},
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
result: UNDEF(),
|
||||
passalong: {handled: false},
|
||||
}
|
||||
}
|
||||
}),
|
||||
passalong: {},
|
||||
}
|
||||
}),
|
||||
else: FN((thunk, env, passalong) => {
|
||||
if (!passalong.handled) {
|
||||
return {
|
||||
result: evaluate_codeblock(thunk, env),
|
||||
passalong: {handled: true},
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
result: UNDEF(),
|
||||
passalong: {handled: true},
|
||||
}
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
`
|
||||
print "hi"
|
||||
if false {
|
||||
print "hi2"
|
||||
} else {
|
||||
print "hi3"
|
||||
}
|
||||
set x = 10
|
||||
set y = 20
|
||||
set f = fn h => {
|
||||
print h
|
||||
print h
|
||||
}
|
||||
f x
|
||||
|
||||
for value in obj {
|
||||
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
const my_prog = CODE([
|
||||
SYM("print"), STR("hi"),
|
||||
SYM("if"), BOOL(false), THUNK([
|
||||
SYM("print"), STR("hi2"),
|
||||
]),
|
||||
SYM("else"), THUNK([
|
||||
SYM("print"), STR("hi3"),
|
||||
]),
|
||||
]);
|
||||
|
||||
console.log(evaluate_codeblock(my_prog, my_env));
|
150
femto-lang/lexer.ts
Normal file
150
femto-lang/lexer.ts
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
|
||||
// type Token = {
|
||||
// type: "paren",
|
||||
// value: 1 | -1,
|
||||
// } | {
|
||||
// type: "bracket",
|
||||
// value: 1 | -1,
|
||||
// } | {
|
||||
// type: "brace",
|
||||
// value: 1 | -1,
|
||||
// } | {
|
||||
// type: "number",
|
||||
// value: number,
|
||||
// } | {
|
||||
// type: "keyword",
|
||||
// value: (typeof KEYWORDS)[number],
|
||||
// } | {
|
||||
// type: "identifier",
|
||||
// value: string,
|
||||
// } | {
|
||||
// type: "string",
|
||||
// value: string,
|
||||
// } | {
|
||||
// type: "assignment-op",
|
||||
// value: "=",
|
||||
// }
|
||||
|
||||
|
||||
// const KEYWORDS = [
|
||||
// "let",
|
||||
// "if",
|
||||
// ] as const;
|
||||
|
||||
// const isKeyword = (str: string): str is (typeof KEYWORDS)[number] => {
|
||||
// return KEYWORDS.includes(str as any);
|
||||
// }
|
||||
|
||||
// const isMatchNestChar = (char: string): char is "(" | ")" | "[" | "]" | "{" | "}" => {
|
||||
// return char === "(" || char === ")" || char === "[" || char === "]" || char === "{" || char === "}";
|
||||
// }
|
||||
|
||||
// const matchNestType = {
|
||||
// "(": "paren",
|
||||
// ")": "paren",
|
||||
// "[": "bracket",
|
||||
// "]": "bracket",
|
||||
// "{": "brace",
|
||||
// "}": "brace",
|
||||
// } as const
|
||||
|
||||
// const matchNestValue = {
|
||||
// "(": 1,
|
||||
// ")": -1,
|
||||
// "[": 1,
|
||||
// "]": -1,
|
||||
// "{": 1,
|
||||
// "}": -1,
|
||||
// } as const
|
||||
|
||||
// const isSkippableChar = (char: string) => {
|
||||
// return [" ", "\n", "\t", ";"].includes(char);
|
||||
// }
|
||||
|
||||
// const isAlpha = (char: string) => {
|
||||
// return /^[a-z]$/.test(char);
|
||||
// }
|
||||
|
||||
// const isNumeric = (char: string) => {
|
||||
// return /^\d$/.test(char);
|
||||
// }
|
||||
|
||||
// const isAlphaNumeric = (char: string) => {
|
||||
// return isAlpha(char) || isNumeric(char);
|
||||
// }
|
||||
|
||||
// const tokenize = (source: string) => {
|
||||
// const tokens: Array<Token> = [];
|
||||
// let src = [...source];
|
||||
// while (src.length) {
|
||||
// const char = src[0];
|
||||
// if (isMatchNestChar(char)) {
|
||||
// const token = {type: matchNestType[char], value: matchNestValue[char]};
|
||||
// tokens.push(token);
|
||||
// src.shift();
|
||||
// } else if (char === "=") {
|
||||
// const token = {type: "assignment-op", value: "="} as const;
|
||||
// tokens.push(token);
|
||||
// src.shift();
|
||||
// } else {
|
||||
// if (isSkippableChar(char)) {
|
||||
// src.shift();
|
||||
// } else if (isNumeric(char)) {
|
||||
// let num = "";
|
||||
// while (src.length && isNumeric(src[0])) {
|
||||
// num += src.shift();
|
||||
// }
|
||||
// const token = {type: "number" as const, value: Number(num)};
|
||||
// tokens.push(token);
|
||||
// } else if (isAlpha(char)) {
|
||||
// let ident = "";
|
||||
// while (src.length && isAlphaNumeric(src[0])) {
|
||||
// ident += src.shift();
|
||||
// }
|
||||
// if (isKeyword(ident)) {
|
||||
// const token = {type: "keyword" as const, value: ident};
|
||||
// tokens.push(token);
|
||||
// } else {
|
||||
// const token = {type: "identifier" as const, value: ident};
|
||||
// tokens.push(token);
|
||||
// }
|
||||
// } else if (char === '"' || char === "'") {
|
||||
// console.log('lexing a string');
|
||||
// const q = char;
|
||||
// src.shift();
|
||||
// let s = "";
|
||||
// while (src.length && src[0] !== q) {
|
||||
// const c = src.shift();
|
||||
// console.log(`c: "${c}"`);
|
||||
// if (c === "\\") {
|
||||
// s += src.shift();
|
||||
// } else {
|
||||
// s += c;
|
||||
// }
|
||||
// }
|
||||
// if (src.length) {
|
||||
// src.shift();
|
||||
// }
|
||||
// const token = {type: "string" as const, value: s};
|
||||
// tokens.push(token);
|
||||
// } else {
|
||||
// throw `Unrecognized character: '${char}'`
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return tokens;
|
||||
// }
|
||||
|
||||
|
||||
// const code = `
|
||||
// let x = 45;
|
||||
// let y = ( 10 );
|
||||
// if (y) {
|
||||
// let z = (x = y);
|
||||
// }
|
||||
// let say = "Hello, \\"world\\"!";
|
||||
|
||||
// `
|
||||
|
||||
// console.log(tokenize(code));
|
107
femto-lang/oddlang.js
Normal file
107
femto-lang/oddlang.js
Normal file
@ -0,0 +1,107 @@
|
||||
// const STR = (s) => ({type: "string", value: s});
|
||||
// const FN = (f) => ({type: "function", value: f});
|
||||
// const NUL = () => ({type: "null", value: null});
|
||||
// const SYM = (s) => ({type: "symbol", value: s});
|
||||
// const UNDEF = () => ({type: "undefined", value: null});
|
||||
// const PROG = (p) => ({type: "program", value: p});
|
||||
// const THUNK = (t) => ({type: "thunk", value: t});
|
||||
// const BOOL = (b) => ({type: "boolean", value: b});
|
||||
|
||||
// const my_prog = [
|
||||
// SYM("print"), STR("hi"),
|
||||
// SYM("if"), BOOL(false), THUNK([
|
||||
// SYM("print"), STR("hi2"),
|
||||
// ]),
|
||||
// SYM("else"), THUNK([
|
||||
// SYM("print"), STR("hi3"),
|
||||
// ]),
|
||||
// ];
|
||||
|
||||
// const my_env = {
|
||||
// print: FN((arg) => {
|
||||
// console.log(arg.value);
|
||||
// return {result: UNDEF()};
|
||||
// }),
|
||||
// if: FN((arg) => {
|
||||
// if (arg.type === "boolean" && arg.value) {
|
||||
// return {
|
||||
// result: FN((thunk) => {
|
||||
// return {
|
||||
// result: eval_program(thunk.value, my_env).result,
|
||||
// handled: BOOL(true),
|
||||
// };
|
||||
// })
|
||||
// };
|
||||
// }
|
||||
// return {
|
||||
// result: UNDEF(),
|
||||
// handled: BOOL(false),
|
||||
// };
|
||||
// }),
|
||||
// else: FN((arg, passalong) => {
|
||||
// console.log('ELSE', arg, passalong);
|
||||
// if (passalong.handled === false) {
|
||||
// return {
|
||||
// result: eval_program(arg.value, my_env).result,
|
||||
// };
|
||||
// }
|
||||
// return {
|
||||
// result: UNDEF(),
|
||||
// };
|
||||
// }),
|
||||
// }
|
||||
|
||||
// const debugLog = (...args) => {
|
||||
// // console.log(args);
|
||||
// }
|
||||
|
||||
// const eval_program = (program, env) => {
|
||||
// debugLog('evaluating program');
|
||||
// let val = {result: UNDEF()};
|
||||
// while (program.length) {
|
||||
// val = eval_phrase(program, env, val);
|
||||
// }
|
||||
// debugLog('program evaluated to', val);
|
||||
// return val;
|
||||
// }
|
||||
|
||||
// const eval_phrase = (program, env, passalong) => {
|
||||
// debugLog('evaluating phrase');
|
||||
// const phraseStart = program.shift();
|
||||
// let head = eval_expression(phraseStart, env, passalong);
|
||||
// while (program.length && head.result.type === "function") {
|
||||
// debugLog('head', head);
|
||||
// const tail = eval_expression(program.shift(), env, head);
|
||||
// debugLog('tail', tail);
|
||||
// head = head.result.value(tail.result, passalong, tail);
|
||||
// }
|
||||
// debugLog('end of phrase, result:', head, 'start:', phraseStart);
|
||||
// return head;
|
||||
// }
|
||||
|
||||
// const eval_expression = (expr, env) => {
|
||||
// debugLog('evaluating expression', expr);
|
||||
// let result = {result: UNDEF()};
|
||||
// if (expr.type === "symbol") {
|
||||
// result = {
|
||||
// result: env[expr.value],
|
||||
// name: STR(expr.value),
|
||||
// }
|
||||
// } else if (expr.type === "string") {
|
||||
// result = {
|
||||
// result: expr,
|
||||
// }
|
||||
// } else if (expr.type === "boolean") {
|
||||
// result = {
|
||||
// result: expr,
|
||||
// }
|
||||
// } else if (expr.type === "thunk") {
|
||||
// result = {
|
||||
// result: expr,
|
||||
// }
|
||||
// }
|
||||
// debugLog('expression evaluated to', result);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// console.log(eval_program(my_prog, my_env));
|
233
ideas.md
Normal file
233
ideas.md
Normal file
@ -0,0 +1,233 @@
|
||||
A game is comprised of up to 16 "bags", each bag being exactly 8196 characters (8 kibibytes)
|
||||
The first bag is the "core" of the game, and is what executes on startup.
|
||||
It may include code from other bags.
|
||||
bags can contain arbitrary data, but the built-in system allows convenient usage of data in specific forms.
|
||||
The main uses of data are:
|
||||
1. code
|
||||
2. planar grid (sprites, maps, etc.)
|
||||
3. sounds
|
||||
|
||||
(5.5 colors * 1.5 saturations + 1 gray) * 3.5 brightnesses
|
||||
|
||||
red 2 3
|
||||
yellow/orange 2 4
|
||||
green 2 3
|
||||
blue 2 3
|
||||
purple 1 3
|
||||
gray 1 4
|
||||
|
||||
6 + 8 + 6 + 6 + 3 + 4 = 33
|
||||
|
||||
"data" can refer to a sprite or a sound
|
||||
|
||||
## In PICO
|
||||
|
||||
A sprite is:
|
||||
- an 8x8 grid of values each of which is: 4 bits,
|
||||
- and 8 1-bit flags
|
||||
that is: 64x4 = 32x8 = 32 bytes
|
||||
|
||||
A sound is:
|
||||
- an array of 32 notes each of which is: pitch(0-63), volume(0-7), instrument(0-15?), effect(0-7),
|
||||
- 5 flags: 0-1, 0-1, 0-2, 0-2, 0-2
|
||||
that is: 32x(6+3+4+3) = 32x16 = 64x8 = 64 bytes
|
||||
|
||||
## In FEMTO
|
||||
|
||||
A sprite is:
|
||||
- an 8x8 grid of values each of which is: color(0-31), 3 unused bits
|
||||
that is: 64x8 = 64 bytes
|
||||
|
||||
A sound is:
|
||||
- an array of 16 notes each of which is: pitch(0-63), volume(0-7), instrument(0-15?), effect(0-7),
|
||||
that is: 16(6+3+4+3) = 16x16 = 32x8 = 32 bytes
|
||||
|
||||
A "block" is 64 bytes = 0x40
|
||||
|
||||
A "sheet" is 64 blocks = 4096 bytes = 4KiB = 0x1000
|
||||
|
||||
A sound-sheet, a sprite-sheet, a code-sheet, a map-sheet
|
||||
|
||||
A full map is:
|
||||
- 128x128 with values from 0-255
|
||||
|
||||
A quarter-map is:
|
||||
- 64x64 grid of values each of which is 8 bits
|
||||
This is equivalent to a "sheet": the "blocks" are 8x8 regions
|
||||
|
||||
|
||||
What if we allow a "meta-sheet" which contains metadata for other blocks.
|
||||
Each block in a different sheet is associated with a single byte here.
|
||||
That means this has 64 sheets' worth of metadata.
|
||||
|
||||
A meta-sheet is:
|
||||
- each block is 64 bytes: one byte for each block of a different sheet. -- the hooking up happens separately
|
||||
|
||||
Your package can be comprised of up to 64 sheets (= 256KiB = 0.25MiB)
|
||||
|
||||
Each sheet can be accessed by an id 0-63. Each block in a sheet can be accessed by an id 0-63.
|
||||
|
||||
Sheet 0 is the entrypoint and is the code that starts running.
|
||||
|
||||
draw_sprite(sheet_id, block_id)
|
||||
play_sound(sheet_id, block_id)
|
||||
map_get(sheet_id, block_id, x, y)
|
||||
|
||||
|
||||
## The Language
|
||||
|
||||
Considering a functional language idea.
|
||||
|
||||
We have an IO "monad"?
|
||||
|
||||
type systems seem complicated... so we'll skip that for now.
|
||||
|
||||
functions are variables.
|
||||
|
||||
```
|
||||
// JSON5 + arrow functions
|
||||
|
||||
set {succ: (n) => {
|
||||
for (key: value in obj) {
|
||||
|
||||
}
|
||||
|
||||
if (condition) {
|
||||
// do stuff
|
||||
}
|
||||
elseif (cond2) {
|
||||
// different stuff
|
||||
}
|
||||
else {
|
||||
// more stuff
|
||||
}
|
||||
return +(n, 1)
|
||||
}}
|
||||
|
||||
```
|
||||
|
||||
If a function is called with the
|
||||
|
||||
```
|
||||
funcname (arg1, arg2) {
|
||||
// block here
|
||||
}
|
||||
```
|
||||
|
||||
syntax, then contents of the block can be called by calling `thunk()`.
|
||||
|
||||
Each function can also prepare for a chain, by calling `passalong(value)`, and the very next function call can read it with `passalong()`.
|
||||
|
||||
```
|
||||
:x 40
|
||||
:x 50
|
||||
|
||||
obj = {
|
||||
abc: "def",
|
||||
ghi: "jkl"
|
||||
}
|
||||
|
||||
arr = [
|
||||
"foo",
|
||||
"bar"
|
||||
]
|
||||
|
||||
succ = (n) => +(n, 1)
|
||||
|
||||
succ(n)
|
||||
|
||||
myif = (cond) => if(cond, thunk)
|
||||
|
||||
|
||||
map(obj, (key, value) =>
|
||||
if(eq(key, "abc"),
|
||||
"overridden",
|
||||
value
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
Maybe just use lua, js, or lisp after all.
|
||||
|
||||
Main downsides of lua: I don't love the function syntax and lack of curly braces.
|
||||
|
||||
Downsides of lisp: syntax is hard to get used to.
|
||||
|
||||
Maybe: js-like.
|
||||
|
||||
So:
|
||||
- arrow functions
|
||||
- JSON5 object syntax
|
||||
- if/else with js syntax
|
||||
- for with `for (key: value in obj)` OR `for (value in obj)` OR `for (key: in obj)`
|
||||
- break and continue
|
||||
- while with js syntax
|
||||
|
||||
No `this`.
|
||||
|
||||
```
|
||||
x = 5;
|
||||
while(condition, () => {
|
||||
// do stuff
|
||||
});
|
||||
if(equal(x, 5), () => {
|
||||
x = +(x, 1);
|
||||
});
|
||||
foreach(obj, (value, key) => {
|
||||
// do stuff
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
if cond {
|
||||
|
||||
}
|
||||
elseif cond2 {
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Eval strategy: eval current thing. If current thing is function, then eval next thing, and apply the func to that next thing. If current thing is function, eval next thing, and apply the func to that next thing. repeat. Do that if `return-and-call` was used, otherwise, if just `return` was used, move on to evaluate the next thing.
|
||||
|
||||
You can pass along certain things, e.g. "if" can say "i ran" or "i didn't run", and the "else" can pick that up and run with it.
|
||||
|
||||
You can also set a flag that says "I'm the end of this statement"
|
||||
|
||||
The pass-along can also be used to implement setting a variable, like `x = 5`, since the `x` can pass along its name, then the `=` can set it, and end after the `5`.
|
||||
|
||||
In general, anything infix can work that way, but precedence won't be right. E.g. `x = x + 5` will set `x = x`, and then add 5 to the result of that assignment, and return, but without updating `x`.
|
||||
|
||||
```
|
||||
for val in obj {
|
||||
|
||||
}
|
||||
|
||||
for key : val in obj {
|
||||
|
||||
}
|
||||
|
||||
for key : in obj {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Functions are created with `fn var thunk`, or `var => thunk`
|
||||
|
||||
Properties can be accessed and set with `obj . prop`
|
||||
|
||||
Command is:
|
||||
```
|
||||
set x = 5
|
||||
if condition {
|
||||
// ...
|
||||
}
|
||||
|
||||
```
|
250
index.html
Normal file
250
index.html
Normal file
@ -0,0 +1,250 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<style>
|
||||
.swatch {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: hsl(var(--hue), var(--saturation), var(--lightness));
|
||||
}
|
||||
|
||||
.h1p {
|
||||
--hue: 310;
|
||||
}
|
||||
.h1 {
|
||||
--hue: 340;
|
||||
}
|
||||
.h1s {
|
||||
--hue: 335;
|
||||
}
|
||||
.h2d {
|
||||
--hue: 50;
|
||||
}
|
||||
.h2 {
|
||||
--hue: 37;
|
||||
}
|
||||
.h2s {
|
||||
--hue: 30;
|
||||
}
|
||||
.h2h {
|
||||
--hue: 57;
|
||||
}
|
||||
.h3 {
|
||||
--hue: 130;
|
||||
}
|
||||
.h3s {
|
||||
--hue: 145;
|
||||
}
|
||||
.h3h {
|
||||
--hue: 203;
|
||||
}
|
||||
.h4 {
|
||||
--hue: 224;
|
||||
}
|
||||
/* .h4hs {
|
||||
--hue: 228;
|
||||
}
|
||||
.h4s {
|
||||
--hue: 235;
|
||||
} */
|
||||
.h4hs {
|
||||
--hue: 235;
|
||||
}
|
||||
.h4s {
|
||||
--hue: 240;
|
||||
}
|
||||
.h5 {
|
||||
--hue: 250;
|
||||
}
|
||||
.h6 {
|
||||
--hue: 230;
|
||||
}
|
||||
.h7 {
|
||||
--hue: 30;
|
||||
}
|
||||
|
||||
.sp {
|
||||
--saturation: 90%;
|
||||
}
|
||||
.s1 {
|
||||
--saturation: 85%;
|
||||
}
|
||||
.s1x {
|
||||
--saturation: 75%;
|
||||
}
|
||||
.sx {
|
||||
--saturation: 65%;
|
||||
}
|
||||
.smx {
|
||||
--saturation: 60%;
|
||||
}
|
||||
.sm {
|
||||
--saturation: 55%;
|
||||
}
|
||||
.smm {
|
||||
--saturation: 50%;
|
||||
}
|
||||
.s2 {
|
||||
--saturation: 45%;
|
||||
}
|
||||
.ss {
|
||||
--saturation: 40%;
|
||||
}
|
||||
.sl {
|
||||
--saturation: 25%;
|
||||
}
|
||||
.s3 {
|
||||
--saturation: 13%;
|
||||
}
|
||||
|
||||
.l0 {
|
||||
--lightness: 95%;
|
||||
}
|
||||
.l1 {
|
||||
--lightness: 82%;
|
||||
}
|
||||
.l1h {
|
||||
--lightness: 75%;
|
||||
}
|
||||
.l1hh {
|
||||
--lightness: 70%;
|
||||
}
|
||||
.l2 {
|
||||
--lightness: 67%;
|
||||
}
|
||||
.l2m {
|
||||
--lightness: 62%;
|
||||
}
|
||||
.lm {
|
||||
--lightness: 58%;
|
||||
}
|
||||
.l3 {
|
||||
--lightness: 50%;
|
||||
}
|
||||
.l3h {
|
||||
--lightness: 40%;
|
||||
}
|
||||
.l4 {
|
||||
--lightness: 30%;
|
||||
}
|
||||
.l4h {
|
||||
--lightness: 25%;
|
||||
}
|
||||
.l5 {
|
||||
--lightness: 20%;
|
||||
}
|
||||
.l6 {
|
||||
--lightness: 5%;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="row">
|
||||
<div class="swatch h6 s3 l0"></div>
|
||||
<div class="swatch h6 s3 l2"></div>
|
||||
<div class="swatch h6 s3 l4"></div>
|
||||
<div class="swatch h6 s3 l6"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h2 smx l3"></div>
|
||||
<div class="swatch h7 ss l2"></div>
|
||||
<div class="swatch h7 ss l3h"></div>
|
||||
<div class="swatch h7 ss l4h"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h5 smx l2"></div>
|
||||
<div class="swatch h1p smx l2"></div>
|
||||
<div class="swatch h1 smx l3"></div>
|
||||
<div class="swatch h1s smx l4"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h2h sp l2m"></div>
|
||||
<div class="swatch h3 smx l3"></div>
|
||||
<div class="swatch h3s smx l4"></div>
|
||||
<div class="swatch h3s smx l5"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h3h sp l2"></div>
|
||||
<div class="swatch h4 smx l3"></div>
|
||||
<div class="swatch h4hs smx l3h"></div>
|
||||
<div class="swatch h4s smx l4"></div>
|
||||
</div>
|
||||
<!-- -->
|
||||
<!-- <div class="row">
|
||||
<div class="swatch h1 smx l3"></div>
|
||||
<div class="swatch h1s smx l4"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h2h sx lm"></div>
|
||||
<div class="swatch h3 smx l3"></div>
|
||||
<div class="swatch h3s smx l4"></div>
|
||||
<div class="swatch h3s smx l5"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h4 smx l3"></div>
|
||||
<div class="swatch h4hs smx l3h"></div>
|
||||
<div class="swatch h4s smx l4"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h7 ss l4h"></div>
|
||||
<div class="swatch h2s ss l3h"></div>
|
||||
<div class="swatch h2s ss l2"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h6 s3 l0"></div>
|
||||
<div class="swatch h6 s3 l2"></div>
|
||||
<div class="swatch h6 s3 l4"></div>
|
||||
<div class="swatch h6 s3 l6"></div>
|
||||
</div> -->
|
||||
<!-- -->
|
||||
<!-- <div class="row">
|
||||
<div class="swatch h1 smx l2"></div>
|
||||
<div class="swatch h1 smx l3"></div>
|
||||
<div class="swatch h1s smx l4"></div>
|
||||
<div class="swatch h1s smx l5"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h2 smx l2"></div>
|
||||
<div class="swatch h2 smx l3"></div>
|
||||
<div class="swatch h2s smx l4"></div>
|
||||
<div class="swatch h2s smx l5"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h3 smx l2"></div>
|
||||
<div class="swatch h3 smx l3"></div>
|
||||
<div class="swatch h3s smx l4"></div>
|
||||
<div class="swatch h3s smx l5"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h4 smx l2"></div>
|
||||
<div class="swatch h4 smx l3"></div>
|
||||
<div class="swatch h4s smx l4"></div>
|
||||
<div class="swatch h4s smx l5"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h5 sl lm"></div>
|
||||
<div class="swatch h5 sl l3h"></div>
|
||||
<div class="swatch h5 sl l4h"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h6 s3 l0"></div>
|
||||
<div class="swatch h6 s3 l1"></div>
|
||||
<div class="swatch h6 s3 l2"></div>
|
||||
<div class="swatch h6 s3 l3"></div>
|
||||
<div class="swatch h6 s3 l4"></div>
|
||||
<div class="swatch h6 s3 l5"></div>
|
||||
<div class="swatch h6 s3 l6"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="swatch h7 ss l1"></div>
|
||||
<div class="swatch h7 ss l2"></div>
|
||||
<div class="swatch h7 ss l3"></div>
|
||||
<div class="swatch h7 ss l4"></div>
|
||||
<div class="swatch h7 ss l5"></div>
|
||||
</div> -->
|
||||
</body>
|
||||
</html>
|
54
lang2/lexer.ts
Normal file
54
lang2/lexer.ts
Normal file
@ -0,0 +1,54 @@
|
||||
type Token<T extends string> = {
|
||||
type: T,
|
||||
string: string,
|
||||
}
|
||||
|
||||
type LexerProps<T extends string> = {
|
||||
rules: {
|
||||
[key in T]: RegExp;
|
||||
},
|
||||
// postprocess?: (token: Token<T>) =>
|
||||
}
|
||||
|
||||
const entries = <K extends string, V>(obj: {[key in K]: V}) => {
|
||||
return Object.entries(obj) as Array<[K, V]>;
|
||||
}
|
||||
|
||||
const lexer = <T extends string>(props: LexerProps<T>) => {
|
||||
const {rules} = props;
|
||||
return (string: string): Array<Token<T>> => {
|
||||
const tokens: Array<Token<T>> = [];
|
||||
let str = string;
|
||||
while (str.length) {
|
||||
let matched = false;
|
||||
for (const [type, matcher] of entries(rules)) {
|
||||
const match = str.match(matcher);
|
||||
if (match && match.index === 0) {
|
||||
if (type !== "_skip") {
|
||||
tokens.push({type, string: match[0]});
|
||||
}
|
||||
str = str.slice(match[0].length);
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
console.log(tokens);
|
||||
console.log(str);
|
||||
throw 'Infinite Loop';
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
|
||||
const my_lexer = lexer({
|
||||
rules: {
|
||||
symbol: /\w+/,
|
||||
punctuation: /[\.,:;()[\]{}]/,
|
||||
string_literal: /"([^"\\]|\\.)*"/,
|
||||
_skip: /\s+/,
|
||||
}
|
||||
});
|
||||
|
||||
console.log(my_lexer(`abc def { ghi } "string literal!" "with \\"escaped\\" quote marks"`));
|
28
lang2/peg.js
Normal file
28
lang2/peg.js
Normal file
@ -0,0 +1,28 @@
|
||||
const Expression = rule(
|
||||
[{head: Term}, {tail: star([_, slash("+", "-"), _, Term])}],
|
||||
({head, tail}) => {
|
||||
return tail.reduce(function(result, element) {
|
||||
if (element[1] === "+") { return result + element[3]; }
|
||||
if (element[1] === "-") { return result - element[3]; }
|
||||
}, head);
|
||||
}
|
||||
);
|
||||
|
||||
const Term = rule(
|
||||
[{head: Factor}, {tail: star([_, slash("*", "/"), _, Factor])}],
|
||||
({head, tail}) => {
|
||||
return tail.reduce(function(result, element) {
|
||||
if (element[1] === "*") { return result * element[3]; }
|
||||
if (element[1] === "/") { return result / element[3]; }
|
||||
}, head);
|
||||
}
|
||||
);
|
||||
|
||||
const Factor = slash(
|
||||
rule(["(", _, {expr: Expression}, _, ")"], ({expr}) => expr),
|
||||
Integer
|
||||
);
|
||||
|
||||
const Integer = rule([_, /[0-9]+/], () => { return parseInt(text(), 10); });
|
||||
|
||||
const _ = /[ \t\n\r]*/;
|
Loading…
x
Reference in New Issue
Block a user