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
	 dylan
					dylan