initial ideas
This commit is contained in:
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));
|
Reference in New Issue
Block a user